From 3577a3e0a32a33ebe4f72e73403836abbc3459c3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 7 Jul 2017 20:02:02 -0400 Subject: [PATCH 0001/2339] fix width and height defaeulting to monitor size when scale==100 --- web/includes/functions.php | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index b50a14917..a2d0c69dd 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -2133,18 +2133,14 @@ function getStreamHTML( $monitor, $options = array() ) { $options['height'] = reScale( $monitor->Height(), $options['scale'] ); } else { if ( ! isset( $options['width'] ) ) { - if ( $options['width'] == 100 ) { - $options['width'] = $monitor->Width(); - } else { - $options['width'] = NULL; - } + $options['width'] = NULL; + } else if ( $options['width'] == 100 ) { + $options['width'] = $monitor->Width(); } if ( ! isset( $options['height'] ) ) { - if ( $options['height'] == 100 ) { - $options['height'] = $monitor->Height(); - } else { - $options['height'] = NULL; - } + $options['height'] = NULL; + } else if ( $options['height'] == 100 ) { + $options['height'] = $monitor->Height(); } } if ( ! isset($options['mode'] ) ) { From da74f8d5338e6df88bec022ed2df59bf373b0a39 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 10 Jul 2017 19:37:55 -0400 Subject: [PATCH 0002/2339] initial turn zma into a thread --- scripts/zmdc.pl.in | 2 +- scripts/zmpkg.pl.in | 2 +- src/CMakeLists.txt | 2 +- src/zm_event.cpp | 2 +- src/zm_monitor.cpp | 31 +++++++++++++++---------------- src/zmc.cpp | 18 ++++++++++++++++++ web/ajax/status.php | 3 ++- 7 files changed, 39 insertions(+), 21 deletions(-) diff --git a/scripts/zmdc.pl.in b/scripts/zmdc.pl.in index aaaee0ff8..2f99f0b06 100644 --- a/scripts/zmdc.pl.in +++ b/scripts/zmdc.pl.in @@ -91,7 +91,7 @@ delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; my @daemons = ( 'zmc', - 'zma', + #'zma', 'zmfilter.pl', 'zmaudit.pl', 'zmtrigger.pl', diff --git a/scripts/zmpkg.pl.in b/scripts/zmpkg.pl.in index 597d7ac1a..da50401b0 100644 --- a/scripts/zmpkg.pl.in +++ b/scripts/zmpkg.pl.in @@ -251,7 +251,7 @@ if ( $command =~ /^(?:start|restart)$/ ) } if ( $monitor->{Function} ne 'Monitor' ) { - runCommand( "zmdc.pl start zma -m $monitor->{Id}" ); + #runCommand( "zmdc.pl start zma -m $monitor->{Id}" ); } if ( $Config{ZM_OPT_CONTROL} ) { diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index aa0dbc370..c0459d55b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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_eventstream.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_monitorstream.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 zm_storage.cpp) +set(ZM_BIN_SRC_FILES zm_analysis_thread.cpp 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_eventstream.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_monitorstream.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 zm_storage.cpp) # A fix for cmake recompiling the source files for every target. add_library(zm STATIC ${ZM_BIN_SRC_FILES}) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index f841c82c6..358ccb495 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -78,7 +78,7 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string static char sql[ZM_SQL_MED_BUFSIZ]; struct tm *stime = localtime( &start_time.tv_sec ); - snprintf( sql, sizeof(sql), "insert into Events ( MonitorId, StorageId, Name, StartTime, Width, Height, Cause, Notes, StateId, Orientation, Videoed ) values ( %d, %d, 'New Event', from_unixtime( %ld ), %d, %d, '%s', '%s', %d, %d, %d )", + snprintf( sql, sizeof(sql), "insert into Events ( MonitorId, StorageId, Name, StartTime, Width, Height, Cause, Notes, StateId, Orientation, Videoed, DefaultVideo ) values ( %d, %d, 'New Event', from_unixtime( %ld ), %d, %d, '%s', '%s', %d, %d, %d, '' )", monitor->Id(), storage->Id(), start_time.tv_sec, diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 1f1c2413e..820c3ff12 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -384,6 +384,7 @@ Monitor::Monitor( snprintf( monitor_dir, sizeof(monitor_dir), "%s/%d", storage->Path(), id ); struct stat statbuf; + // If we are going to actually do capture, then yes, we should stat this dir, otherwise not if ( stat( monitor_dir, &statbuf ) ) { if ( errno == ENOENT || errno == ENOTDIR ) { if ( mkdir( monitor_dir, 0755 ) ) { @@ -427,21 +428,18 @@ Monitor::Monitor( snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "nothing"); video_store_data->size = sizeof(VideoStoreData); //video_store_data->frameNumber = 0; - } else if ( purpose == ANALYSIS ) { - this->connect(); - if ( ! mem_ptr ) exit(-1); - shared_data->state = IDLE; - shared_data->last_read_time = 0; - shared_data->alarm_x = -1; - shared_data->alarm_y = -1; + + //} else if ( purpose == ANALYSIS ) { + + //this->connect(); } - if ( ( ! mem_ptr ) || ! shared_data->valid ) { - if ( purpose != QUERY ) { - Error( "Shared data not initialised by capture daemon for monitor %s", name ); - exit( -1 ); - } - } + //if ( ( ! mem_ptr ) || ! shared_data->valid ) { + //if ( purpose != QUERY ) { + //Error( "Shared data not initialised by capture daemon for monitor %s", name ); + //exit( -1 ); + //} + //} // Will this not happen every time a monitor is instantiated? Seems like all the calls to the Monitor constructor pass a zero for n_zones, then load zones after.. // In my storage areas branch, I took this out.. and didn't notice any problems. @@ -463,8 +461,8 @@ Monitor::Monitor( //Set video recording flag for event start constructor and easy reference in code videoRecording = ((GetOptVideoWriter() == H264PASSTHROUGH) && camera->SupportsNativeVideo()); - if ( purpose == ANALYSIS ) { - + //if ( purpose == ANALYSIS ) { +if ( 0 ) { while( shared_data->last_write_index == (unsigned int)image_buffer_count && shared_data->last_write_time == 0) { Warning( "Waiting for capture daemon" ); @@ -472,13 +470,14 @@ Monitor::Monitor( } ref_image.Assign( width, height, camera->Colours(), camera->SubpixelOrder(), image_buffer[shared_data->last_write_index].image->Buffer(), camera->ImageSize()); +} n_linked_monitors = 0; linked_monitors = 0; adaptive_skip = true; ReloadLinkedMonitors( p_linked_monitors ); - } + //} } bool Monitor::connect() { diff --git a/src/zmc.cpp b/src/zmc.cpp index 5915d4ef5..b6b6ccd99 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -70,6 +70,7 @@ possible, this should run at more or less constant speed. #include "zm_time.h" #include "zm_signal.h" #include "zm_monitor.h" +#include "zm_analysis_thread.h" void Usage() { fprintf( stderr, "zmc -d or -r -H -P -p or -f or -m \n" ); @@ -238,6 +239,7 @@ int main( int argc, char *argv[] ) { exit( -1 ); } + AnalysisThread **analysis_threads = new AnalysisThread *[n_monitors]; long *capture_delays = new long[n_monitors]; long *alarm_capture_delays = new long[n_monitors]; long *next_delays = new long[n_monitors]; @@ -246,6 +248,15 @@ int main( int argc, char *argv[] ) { last_capture_times[i].tv_sec = last_capture_times[i].tv_usec = 0; capture_delays[i] = monitors[i]->GetCaptureDelay(); alarm_capture_delays[i] = monitors[i]->GetAlarmCaptureDelay(); + + Monitor::Function function = monitors[0]->GetFunction(); + if ( function == Monitor::MODECT || function == Monitor::MOCORD ) { + Debug(1, "Starting an analysis thread for monitor (%d)", monitors[i]->Id() ); + analysis_threads[i] = new AnalysisThread( monitors[i] ); + analysis_threads[i]->start(); + } else { + analysis_threads[i] = NULL; + } } int result = 0; @@ -309,8 +320,15 @@ int main( int argc, char *argv[] ) { sigprocmask( SIG_UNBLOCK, &block_set, 0 ); } // end while ! zm_terminate for ( int i = 0; i < n_monitors; i++ ) { + if ( analysis_threads[i] ) { + analysis_threads[i]->stop(); + analysis_threads[i]->join(); + delete analysis_threads[i]; + analysis_threads[i] = 0; + } delete monitors[i]; } + delete [] analysis_threads; delete [] monitors; delete [] alarm_capture_delays; delete [] capture_delays; diff --git a/web/ajax/status.php b/web/ajax/status.php index fbd91cf08..c9e9115f0 100644 --- a/web/ajax/status.php +++ b/web/ajax/status.php @@ -359,7 +359,8 @@ function getNearEvents() { $eventId = $_REQUEST['id']; $event = dbFetchOne( 'select * from Events where Id = ?', NULL, array( $eventId ) ); - parseFilter( $_REQUEST['filter'] ); + if ( isset($_REQUEST['filter']) ) + parseFilter( $_REQUEST['filter'] ); parseSort(); if ( $user['MonitorIds'] ) From 9fef9d19dde73690bcbe2ae986d032562ab673c6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 4 Sep 2017 15:01:00 -0400 Subject: [PATCH 0003/2339] add zm_ffmpeg_input --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6b63159f4..fd01b4864 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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_analysis_thread.cpp 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_eventstream.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_monitorstream.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_swscale.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 zm_storage.cpp) +set(ZM_BIN_SRC_FILES zm_analysis_thread.cpp 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_eventstream.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_monitorstream.cpp zm_ffmpeg.cpp zm_ffmpeg_input.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_swscale.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 zm_storage.cpp) # A fix for cmake recompiling the source files for every target. add_library(zm STATIC ${ZM_BIN_SRC_FILES}) From 0f6d18eaca0a359a7e9a70aba8f00a22af71eee2 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 4 Sep 2017 15:29:40 -0400 Subject: [PATCH 0004/2339] add analysis_thread --- src/zm_analysis_thread.cpp | 44 ++++++++++++++++++++++++++++++++++++++ src/zm_analysis_thread.h | 29 +++++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 src/zm_analysis_thread.cpp create mode 100644 src/zm_analysis_thread.h diff --git a/src/zm_analysis_thread.cpp b/src/zm_analysis_thread.cpp new file mode 100644 index 000000000..48a2a815c --- /dev/null +++ b/src/zm_analysis_thread.cpp @@ -0,0 +1,44 @@ +#include "zm_analysis_thread.h" + + +AnalysisThread::AnalysisThread( Monitor *p_monitor ) { + monitor = p_monitor; + terminate = false; + sigemptyset( &block_set ); +} + +AnalysisThread::~AnalysisThread() { +} + +int AnalysisThread::run() { + + useconds_t analysis_rate = monitor->GetAnalysisRate(); + unsigned int analysis_update_delay = monitor->GetAnalysisUpdateDelay(); + time_t last_analysis_update_time, cur_time; + monitor->UpdateAdaptiveSkip(); + last_analysis_update_time = time( 0 ); + + while( !terminate ) { + // Process the next image + sigprocmask( SIG_BLOCK, &block_set, 0 ); + + // Some periodic updates are required for variable capturing framerate + if ( analysis_update_delay ) { + cur_time = time( 0 ); + if ( (unsigned int)( cur_time - last_analysis_update_time ) > analysis_update_delay ) { + analysis_rate = monitor->GetAnalysisRate(); + monitor->UpdateAdaptiveSkip(); + last_analysis_update_time = cur_time; + } + } + + if ( !monitor->Analyse() ) { + usleep( monitor->Active()?ZM_SAMPLE_RATE:ZM_SUSPENDED_RATE ); + } else if ( analysis_rate ) { + usleep( analysis_rate ); + } + + sigprocmask( SIG_UNBLOCK, &block_set, 0 ); + } + return 0; +} // end in AnalysisThread::run() diff --git a/src/zm_analysis_thread.h b/src/zm_analysis_thread.h new file mode 100644 index 000000000..33a4fb7f4 --- /dev/null +++ b/src/zm_analysis_thread.h @@ -0,0 +1,29 @@ +#ifndef ZM_ANALYSIS_THREAD_H +#define ZM_ANALYSIS_THREAD_H + +#include "zm_thread.h" +#include + +#include "zm_monitor.h" + +class AnalysisThread : public Thread { + private: + bool terminate; + sigset_t block_set; + Monitor *monitor; + + public: + AnalysisThread( Monitor * ); + ~AnalysisThread(); + int run(); + + void stop() { + terminate = true; + } + bool stopped() const { + return( terminate ); + } + +}; + +#endif From b30e8953dd551d47b57c7edeaad634dfd3ceb762 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 4 Sep 2017 16:36:34 -0400 Subject: [PATCH 0005/2339] starting to rough in adding a frame to zmpacket --- src/zm_analysis_thread.cpp | 15 +++++++-------- src/zm_monitor.cpp | 10 ---------- src/zm_packet.cpp | 3 +++ src/zm_packet.h | 3 +++ src/zm_utils.cpp | 10 ++++++++++ src/zmc.cpp | 4 ++-- 6 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/zm_analysis_thread.cpp b/src/zm_analysis_thread.cpp index 48a2a815c..d0c864ff5 100644 --- a/src/zm_analysis_thread.cpp +++ b/src/zm_analysis_thread.cpp @@ -1,10 +1,9 @@ #include "zm_analysis_thread.h" - -AnalysisThread::AnalysisThread( Monitor *p_monitor ) { +AnalysisThread::AnalysisThread(Monitor *p_monitor) { monitor = p_monitor; terminate = false; - sigemptyset( &block_set ); + sigemptyset(&block_set); } AnalysisThread::~AnalysisThread() { @@ -16,11 +15,11 @@ int AnalysisThread::run() { unsigned int analysis_update_delay = monitor->GetAnalysisUpdateDelay(); time_t last_analysis_update_time, cur_time; monitor->UpdateAdaptiveSkip(); - last_analysis_update_time = time( 0 ); + last_analysis_update_time = time(0); while( !terminate ) { // Process the next image - sigprocmask( SIG_BLOCK, &block_set, 0 ); + sigprocmask(SIG_BLOCK, &block_set, 0); // Some periodic updates are required for variable capturing framerate if ( analysis_update_delay ) { @@ -33,12 +32,12 @@ int AnalysisThread::run() { } if ( !monitor->Analyse() ) { - usleep( monitor->Active()?ZM_SAMPLE_RATE:ZM_SUSPENDED_RATE ); + usleep(monitor->Active()?ZM_SAMPLE_RATE:ZM_SUSPENDED_RATE); } else if ( analysis_rate ) { - usleep( analysis_rate ); + usleep(analysis_rate); } - sigprocmask( SIG_UNBLOCK, &block_set, 0 ); + sigprocmask(SIG_UNBLOCK, &block_set, 0); } return 0; } // end in AnalysisThread::run() diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 3727db7a1..da7388d72 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -62,16 +62,6 @@ #define MAP_LOCKED 0 #endif -std::vector split(const std::string &s, char delim) { - std::vector elems; - std::stringstream ss(s); - std::string item; - while(std::getline(ss, item, delim)) { - elems.push_back(trimSpaces(item)); - } - return elems; -} - Monitor::MonitorLink::MonitorLink( int p_id, const char *p_name ) : id( p_id ) { strncpy( name, p_name, sizeof(name) ); diff --git a/src/zm_packet.cpp b/src/zm_packet.cpp index 7c08d4158..beea0e555 100644 --- a/src/zm_packet.cpp +++ b/src/zm_packet.cpp @@ -44,3 +44,6 @@ ZMPacket::~ZMPacket() { zm_av_packet_unref( &packet ); } +int ZMPacket::decode( AVCodecContext *ctx ) { +} + diff --git a/src/zm_packet.h b/src/zm_packet.h index 303b3af35..b481df3eb 100644 --- a/src/zm_packet.h +++ b/src/zm_packet.h @@ -32,9 +32,12 @@ class ZMPacket { public: AVPacket packet; + AVFrame *frame; // Theoretically only filled if needed. struct timeval timestamp; public: AVPacket *av_packet() { return &packet; } + AVFrame *av_frame() { return frame; } + int decode( AVCodecContext *ctx ); ZMPacket( AVPacket *packet, struct timeval *timestamp ); ZMPacket( AVPacket *packet ); ~ZMPacket(); diff --git a/src/zm_utils.cpp b/src/zm_utils.cpp index f6ce68089..ee295c0d4 100644 --- a/src/zm_utils.cpp +++ b/src/zm_utils.cpp @@ -100,6 +100,16 @@ bool startsWith( const std::string &haystack, const std::string &needle ) return( haystack.substr( 0, needle.length() ) == needle ); } +std::vector split(const std::string &s, char delim) { + std::vector elems; + std::stringstream ss(s); + std::string item; + while(std::getline(ss, item, delim)) { + elems.push_back(trimSpaces(item)); + } + return elems; +} + StringVector split( const std::string &string, const std::string chars, int limit ) { StringVector stringVector; diff --git a/src/zmc.cpp b/src/zmc.cpp index 18eb764c2..4df2faf0d 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -250,8 +250,8 @@ int main(int argc, char *argv[]) { Monitor::Function function = monitors[0]->GetFunction(); if ( function == Monitor::MODECT || function == Monitor::MOCORD ) { - Debug(1, "Starting an analysis thread for monitor (%d)", monitors[i]->Id() ); - analysis_threads[i] = new AnalysisThread( monitors[i] ); + Debug(1, "Starting an analysis thread for monitor (%d)", monitors[i]->Id()); + analysis_threads[i] = new AnalysisThread(monitors[i]); analysis_threads[i]->start(); } else { analysis_threads[i] = NULL; From 94ab00aebdcb1c3c65cae6f4313fc75ece8c440d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 7 Oct 2017 11:30:41 -0400 Subject: [PATCH 0006/2339] continue cleanup of Monitor instantiation --- src/zm_analysis_thread.cpp | 2 + src/zm_monitor.cpp | 134 ++++++++++++++++---------------- web/skins/classic/js/classic.js | 2 +- 3 files changed, 71 insertions(+), 67 deletions(-) diff --git a/src/zm_analysis_thread.cpp b/src/zm_analysis_thread.cpp index d0c864ff5..b38e19108 100644 --- a/src/zm_analysis_thread.cpp +++ b/src/zm_analysis_thread.cpp @@ -17,6 +17,8 @@ int AnalysisThread::run() { monitor->UpdateAdaptiveSkip(); last_analysis_update_time = time(0); + monitor->get_ref_image(); + while( !terminate ) { // Process the next image sigprocmask(SIG_BLOCK, &block_set, 0); diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index a11e4433d..73b6a3dae 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -419,13 +419,10 @@ Monitor::Monitor( trigger_data->trigger_showtext[0] = 0; shared_data->valid = true; video_store_data->recording = (struct timeval){0}; + // Uh, why nothing? Why not NULL? snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "nothing"); video_store_data->size = sizeof(VideoStoreData); //video_store_data->frameNumber = 0; - - //} else if ( purpose == ANALYSIS ) { - - //this->connect(); } //if ( ( ! mem_ptr ) || ! shared_data->valid ) { @@ -435,15 +432,6 @@ Monitor::Monitor( //} //} - // Will this not happen every time a monitor is instantiated? Seems like all the calls to the Monitor constructor pass a zero for n_zones, then load zones after.. - // In my storage areas branch, I took this out.. and didn't notice any problems. - if ( false && !n_zones ) { - Debug( 1, "Monitor %s has no zones, adding one.", name ); - n_zones = 1; - zones = new Zone *[1]; - Coord coords[4] = { Coord( 0, 0 ), Coord( width-1, 0 ), Coord( width-1, height-1 ), Coord( 0, height-1 ) }; - zones[0] = new Zone( this, 0, "All", Zone::ACTIVE, Polygon( sizeof(coords)/sizeof(*coords), coords ), RGB_RED, Zone::BLOBS ); - } start_time = last_fps_time = time( 0 ); event = 0; @@ -455,23 +443,12 @@ Monitor::Monitor( //Set video recording flag for event start constructor and easy reference in code videoRecording = ((GetOptVideoWriter() == H264PASSTHROUGH) && camera->SupportsNativeVideo()); - //if ( purpose == ANALYSIS ) { -if ( 0 ) { - while( shared_data->last_write_index == (unsigned int)image_buffer_count - && shared_data->last_write_time == 0) { - Warning( "Waiting for capture daemon" ); - sleep( 1 ); - } - ref_image.Assign( width, height, camera->Colours(), camera->SubpixelOrder(), image_buffer[shared_data->last_write_index].image->Buffer(), camera->ImageSize()); + n_linked_monitors = 0; + linked_monitors = 0; -} - n_linked_monitors = 0; - linked_monitors = 0; + adaptive_skip = true; - adaptive_skip = true; - - ReloadLinkedMonitors( p_linked_monitors ); - //} + ReloadLinkedMonitors( p_linked_monitors ); } bool Monitor::connect() { @@ -551,33 +528,36 @@ bool Monitor::connect() { Debug(3,"Aligning shared memory images to the next 64 byte boundary"); shared_images = (uint8_t*)((unsigned long)shared_images + (64 - ((unsigned long)shared_images % 64))); } - Debug(3, "Allocating %d image buffers", image_buffer_count ); - image_buffer = new Snapshot[image_buffer_count]; - for ( int i = 0; i < image_buffer_count; i++ ) { - image_buffer[i].timestamp = &(shared_timestamps[i]); - image_buffer[i].image = new Image( width, height, camera->Colours(), camera->SubpixelOrder(), &(shared_images[i*camera->ImageSize()]) ); - image_buffer[i].image->HoldBuffer(true); /* Don't release the internal buffer or replace it with another */ - } - if ( (deinterlacing & 0xff) == 4) { - /* Four field motion adaptive deinterlacing in use */ - /* Allocate a buffer for the next image */ - next_buffer.image = new Image( width, height, camera->Colours(), camera->SubpixelOrder()); - next_buffer.timestamp = new struct timeval; - } - if ( ( purpose == ANALYSIS ) && analysis_fps ) { - // Size of pre event buffer must be greater than pre_event_count - // if alarm_frame_count > 1, because in this case the buffer contains - // alarmed images that must be discarded when event is created - pre_event_buffer_count = pre_event_count + alarm_frame_count - 1; - pre_event_buffer = new Snapshot[pre_event_buffer_count]; - for ( int i = 0; i < pre_event_buffer_count; i++ ) { - pre_event_buffer[i].timestamp = new struct timeval; - pre_event_buffer[i].image = new Image( width, height, camera->Colours(), camera->SubpixelOrder()); - } + + Debug(3, "Allocating %d image buffers", image_buffer_count ); + image_buffer = new Snapshot[image_buffer_count]; + for ( int i = 0; i < image_buffer_count; i++ ) { + image_buffer[i].timestamp = &(shared_timestamps[i]); + image_buffer[i].image = new Image( width, height, camera->Colours(), camera->SubpixelOrder(), &(shared_images[i*camera->ImageSize()]) ); + image_buffer[i].image->HoldBuffer(true); /* Don't release the internal buffer or replace it with another */ } -Debug(3, "Success connecting"); + if ( (deinterlacing & 0xff) == 4) { + /* Four field motion adaptive deinterlacing in use */ + /* Allocate a buffer for the next image */ + next_buffer.image = new Image( width, height, camera->Colours(), camera->SubpixelOrder()); + next_buffer.timestamp = new struct timeval; + } + pre_event_buffer_count = pre_event_count + alarm_frame_count - 1; + //if ( ( purpose == ANALYSIS ) && analysis_fps ) { + // Size of pre event buffer must be greater than pre_event_count + // if alarm_frame_count > 1, because in this case the buffer contains + // alarmed images that must be discarded when event is created + + // Couldn't we just make sure there is always enough frames in the ring buffer? + pre_event_buffer = new Snapshot[pre_event_buffer_count]; + for ( int i = 0; i < pre_event_buffer_count; i++ ) { + pre_event_buffer[i].timestamp = new struct timeval; + pre_event_buffer[i].image = new Image( width, height, camera->Colours(), camera->SubpixelOrder()); + } + //} + Debug(3, "Success connecting"); return true; -} +} // Monitor::connect Monitor::~Monitor() { if ( timestamps ) { @@ -606,17 +586,7 @@ Monitor::~Monitor() { delete image_buffer[i].image; } delete[] image_buffer; - } // end if mem_ptr - for ( int i = 0; i < n_zones; i++ ) { - delete zones[i]; - } - delete[] zones; - - delete camera; - delete storage; - - if ( mem_ptr ) { if ( purpose == ANALYSIS ) { shared_data->state = state = IDLE; shared_data->last_read_index = image_buffer_count; @@ -664,6 +634,14 @@ Monitor::~Monitor() { } #endif // ZM_MEM_MAPPED } // end if mem_ptr + + for ( int i = 0; i < n_zones; i++ ) { + delete zones[i]; + } + delete[] zones; + + delete camera; + delete storage; } void Monitor::AddZones( int p_n_zones, Zone *p_zones[] ) { @@ -702,7 +680,7 @@ int Monitor::GetImage( int index, int scale ) { if ( index < 0 || index > image_buffer_count ) { index = shared_data->last_write_index; } - +Debug(3, "GetImage"); if ( index != image_buffer_count ) { Image *image; // If we are going to be modifying the snapshot before writing, then we need to copy it @@ -712,7 +690,6 @@ int Monitor::GetImage( int index, int scale ) { alarm_image.Assign( *snap_image ); - //write_image.Assign( *snap_image ); if ( scale != ZM_SCALE_BASE ) { @@ -1263,12 +1240,15 @@ bool Monitor::Analyse() { Debug(3, "Motion detection is enabled signal(%d) signal_change(%d)", signal, signal_change); if ( trigger_data->trigger_state != TRIGGER_OFF ) { +Debug(9, "Trigger not oFF state is (%d)", trigger_data->trigger_state ); unsigned int score = 0; if ( Ready() ) { +Debug(9, "Ready"); std::string cause; Event::StringSetMap noteSetMap; if ( trigger_data->trigger_state == TRIGGER_ON ) { + score += trigger_data->trigger_score; if ( !event ) { if ( cause.length() ) @@ -1306,10 +1286,12 @@ bool Monitor::Analyse() { ref_image = *snap_image; } else if ( signal && Active() && (function == MODECT || function == MOCORD) ) { +Debug(3, "signal and active and modtect"); Event::StringSet zoneSet; int motion_score = last_motion_score; if ( !(image_count % (motion_frame_skip+1) ) ) { // Get new score. +Debug(3,"before DetectMotion"); motion_score = DetectMotion( *snap_image, zoneSet ); Debug( 3, "After motion detection, last_motion_score(%d), new motion score(%d)", last_motion_score, motion_score ); @@ -1455,6 +1437,7 @@ bool Monitor::Analyse() { } // end if ! event } if ( score ) { +Debug(9, "Score: (%d)", score ); if ( (state == IDLE || state == TAPE || state == PREALARM ) ) { if ( Event::PreAlarmCount() >= (alarm_frame_count-1) ) { Info( "%s: %03d - Gone into alarm state", name, image_count ); @@ -1621,6 +1604,8 @@ bool Monitor::Analyse() { } } } // end if ! IDLE + } else { +Debug(3,"Not ready?"); } } else { if ( event ) { @@ -1633,8 +1618,10 @@ bool Monitor::Analyse() { if ( (!signal_change && signal) && (function == MODECT || function == MOCORD) ) { if ( state == ALARM ) { +Debug(3, "blend1"); ref_image.Blend( *snap_image, alarm_ref_blend_perc ); } else { +Debug(3, "blend2"); ref_image.Blend( *snap_image, ref_blend_perc ); } } @@ -1647,7 +1634,9 @@ bool Monitor::Analyse() { if ( analysis_fps ) { // If analysis fps is set, add analysed image to dedicated pre event buffer - int pre_index = image_count%pre_event_buffer_count; +Debug(3,"analysis fps (%d) (%d)", image_count, pre_event_buffer_count ); + int pre_index = pre_event_buffer_count ? image_count%pre_event_buffer_count : 0; +Debug(3,"analysis fps pre_index(%d) = image_count(%d) %% pre_event_buffer_count(%d)", pre_index, image_count, pre_event_buffer_count ); pre_event_buffer[pre_index].image->Assign(*snap->image); memcpy( pre_event_buffer[pre_index].timestamp, snap->timestamp, sizeof(struct timeval) ); } @@ -3281,3 +3270,16 @@ Monitor::Orientation Monitor::getOrientation() const { return orientation; } Monitor::Snapshot *Monitor::getSnapshot() { return &image_buffer[ shared_data->last_write_index%image_buffer_count ]; } + +// Wait for camera to get an image, and then assign it as the base reference image. So this should be done as the first task in the analysis thread startup. +void Monitor::get_ref_image() { + while ( + ( shared_data->last_write_index == (unsigned int)image_buffer_count ) + && + ( shared_data->last_write_time == 0 ) + ) { + Warning( "Waiting for capture daemon" ); + usleep( 100000 ); + } + ref_image.Assign( width, height, camera->Colours(), camera->SubpixelOrder(), image_buffer[shared_data->last_write_index].image->Buffer(), camera->ImageSize()); +} diff --git a/web/skins/classic/js/classic.js b/web/skins/classic/js/classic.js index 61ccc984e..5a57e2c81 100644 --- a/web/skins/classic/js/classic.js +++ b/web/skins/classic/js/classic.js @@ -40,7 +40,7 @@ var popupSizes = { 'filter': { 'width': 820, 'height': 700 }, 'frame': { 'addWidth': 32, 'minWidth': 384, 'addHeight': 200 }, 'frames': { 'width': 600, 'height': 700 }, - 'function': { 'width': 300, 'height': 92 }, + 'function': { 'width': 300, 'height': 200 }, 'group': { 'width': 360, 'height': 180 }, 'groups': { 'width': 440, 'height': 220 }, 'image': { 'addWidth': 48, 'addHeight': 80 }, From 463503b763aaa13739e96131768ccbe9375a42ac Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 9 Oct 2017 14:58:07 -0400 Subject: [PATCH 0007/2339] mostly comments, deal with negative timestamps --- src/zm_event.cpp | 5 +++++ src/zm_monitor.cpp | 12 +++++++----- src/zm_monitor.h | 1 + 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 92f7f4303..1eb1325e5 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -428,6 +428,11 @@ void Event::AddFramesInternal( int n_frames, int start_frame, Image **images, st if ( !timestamps[i]->tv_sec ) { Debug( 1, "Not adding pre-capture frame %d, zero timestamp", i ); continue; + } else if ( timestamps[i]->tv_sec < 0 ) { + Warning( "Not adding pre-capture frame %d, negative timestamp", i ); + continue; + } else { + Debug( 3, "Adding pre-capture frame %d, timestamp = (%d), start_time=(%d)", i, timestamps[i]->tv_sec, start_time.tv_sec ); } frames++; diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 73b6a3dae..d314dbc2a 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1181,6 +1181,7 @@ bool Monitor::Analyse() { struct timeval *timestamp = snap->timestamp; Image *snap_image = snap->image; + // This chunk o fcode is not analysis, so shouldn't be in here. Move it up to whereever analyse is called if ( shared_data->action ) { // Can there be more than 1 bit set in the action? Shouldn't these be elseifs? if ( shared_data->action & RELOAD ) { @@ -1242,6 +1243,7 @@ bool Monitor::Analyse() { if ( trigger_data->trigger_state != TRIGGER_OFF ) { Debug(9, "Trigger not oFF state is (%d)", trigger_data->trigger_state ); unsigned int score = 0; + // Ready means that we have captured the warmpup # of frames if ( Ready() ) { Debug(9, "Ready"); std::string cause; @@ -1418,6 +1420,7 @@ Debug(3,"before DetectMotion"); if ( pre_event_images ) { if ( analysis_fps ) { +// This loop copies pre_vent_images, but what if we havn't gotten that many yet? for ( int i = 0; i < pre_event_images; i++ ) { timestamps[i] = pre_event_buffer[pre_index].timestamp; images[i] = pre_event_buffer[pre_index].image; @@ -1450,9 +1453,11 @@ Debug(9, "Score: (%d)", score ); // If analysis fps is set, // compute the index for pre event images in the dedicated buffer pre_index = image_count%pre_event_buffer_count; +Debug(3, "Pre Index = (%d) = image_count(%d) %% pre_event_buffer_count (%d)", pre_index, image_count, pre_event_buffer_count ); // Seek forward the next filled slot in to the buffer (oldest data) // from the current position + // ICON: I think this is supposed to handle when we havn't recorded enough images. while ( pre_event_images && !pre_event_buffer[pre_index].timestamp->tv_sec ) { pre_index = (pre_index + 1)%pre_event_buffer_count; // Slot is empty, removing image from counter @@ -1618,10 +1623,8 @@ Debug(3,"Not ready?"); if ( (!signal_change && signal) && (function == MODECT || function == MOCORD) ) { if ( state == ALARM ) { -Debug(3, "blend1"); ref_image.Blend( *snap_image, alarm_ref_blend_perc ); } else { -Debug(3, "blend2"); ref_image.Blend( *snap_image, ref_blend_perc ); } } @@ -1629,12 +1632,11 @@ Debug(3, "blend2"); } // end if Enabled() shared_data->last_read_index = index % image_buffer_count; - //shared_data->last_read_time = image_buffer[index].timestamp->tv_sec; shared_data->last_read_time = now.tv_sec; if ( analysis_fps ) { // If analysis fps is set, add analysed image to dedicated pre event buffer -Debug(3,"analysis fps (%d) (%d)", image_count, pre_event_buffer_count ); +Debug(3,"analysis fps image_count(%d) pre_event_buffer_count(%d)", image_count, pre_event_buffer_count ); int pre_index = pre_event_buffer_count ? image_count%pre_event_buffer_count : 0; Debug(3,"analysis fps pre_index(%d) = image_count(%d) %% pre_event_buffer_count(%d)", pre_index, image_count, pre_event_buffer_count ); pre_event_buffer[pre_index].image->Assign(*snap->image); @@ -2865,7 +2867,7 @@ int Monitor::Capture() { if ( (videowriter == H264PASSTHROUGH ) && camera->SupportsNativeVideo() ) { //Warning("ZMC: Recording: %d", video_store_data->recording); captureResult = camera->CaptureAndRecord(*capture_image, video_store_data->recording, video_store_data->event_file); - }else{ + } else { /* Capture directly into image buffer, avoiding the need to memcpy() */ captureResult = camera->Capture(*capture_image); } diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 925e0d14a..19370375f 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -460,6 +460,7 @@ public: inline void setStartupTime( time_t p_time ) { shared_data->startup_time = p_time; } + void get_ref_image(); void actionReload(); void actionEnable(); From 3be40bcc991b5843f77abb1e75630ddbb5488595 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 25 Oct 2017 13:25:44 -0700 Subject: [PATCH 0008/2339] blah --- src/zm_curl_camera.cpp | 19 +++++++------------ src/zm_curl_camera.h | 3 +-- src/zm_event.cpp | 3 ++- src/zm_ffmpeg_input.cpp | 4 ++-- src/zm_libvlc_camera.cpp | 25 ++++--------------------- src/zm_libvlc_camera.h | 9 +++------ src/zm_packet.cpp | 2 +- 7 files changed, 20 insertions(+), 45 deletions(-) diff --git a/src/zm_curl_camera.cpp b/src/zm_curl_camera.cpp index 3db890bf9..4e671ecbe 100644 --- a/src/zm_curl_camera.cpp +++ b/src/zm_curl_camera.cpp @@ -116,7 +116,7 @@ int cURLCamera::PreCapture() { return( 0 ); } -int cURLCamera::Capture( Image &image ) { +ZMPacket * cURLCamera::Capture( Image &image ) { bool frameComplete = false; /* MODE_STREAM specific variables */ @@ -144,7 +144,7 @@ int cURLCamera::Capture( Image &image ) { nRet = pthread_cond_wait(&data_available_cond,&shareddata_mutex); if(nRet != 0) { Error("Failed waiting for available data condition variable: %s",strerror(nRet)); - return -20; + return NULL; } } @@ -257,7 +257,7 @@ int cURLCamera::Capture( Image &image ) { nRet = pthread_cond_wait(&data_available_cond,&shareddata_mutex); if(nRet != 0) { Error("Failed waiting for available data condition variable: %s",strerror(nRet)); - return -18; + return NULL; } need_more_data = false; } @@ -281,7 +281,7 @@ int cURLCamera::Capture( Image &image ) { nRet = pthread_cond_wait(&request_complete_cond,&shareddata_mutex); if(nRet != 0) { Error("Failed waiting for request complete condition variable: %s",strerror(nRet)); - return -19; + return NULL; } } } else { @@ -295,9 +295,10 @@ int cURLCamera::Capture( Image &image ) { unlock(); if(!frameComplete) - return -1; + return NULL; - return 0; + ZMPacket * packet = new ZMPacket( &image ); + return packet; } int cURLCamera::PostCapture() { @@ -305,12 +306,6 @@ int cURLCamera::PostCapture() { 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) { lock(); diff --git a/src/zm_curl_camera.h b/src/zm_curl_camera.h index c9dc2e935..6f4da1bb0 100644 --- a/src/zm_curl_camera.h +++ b/src/zm_curl_camera.h @@ -76,9 +76,8 @@ public: int PrimeCapture(); int PreCapture(); - int Capture( Image &image ); + ZMPacket * 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); diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 87d0e27d2..d18727be6 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -140,6 +140,7 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string if ( symlink( time_path, id_file ) < 0 ) Error( "Can't symlink %s -> %s: %s", id_file, path, strerror(errno)); } else { + // Shallow Storage snprintf( path, sizeof(path), "%s/%d/%d", storage->Path(), monitor->Id(), id ); errno = 0; @@ -200,8 +201,8 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string } else { /* No video object */ videowriter = NULL; - } #endif + } } // Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string &p_cause, const StringSetMap &p_noteSetMap, bool p_videoEvent ) diff --git a/src/zm_ffmpeg_input.cpp b/src/zm_ffmpeg_input.cpp index 6c715b6d1..54395a027 100644 --- a/src/zm_ffmpeg_input.cpp +++ b/src/zm_ffmpeg_input.cpp @@ -116,9 +116,9 @@ AVFrame *FFmpeg_Input::get_frame( int stream_id ) { if ( (stream_id < 0 ) || ( packet.stream_index == stream_id ) ) { Debug(1,"Packet is for our stream (%d)", packet.stream_index ); - AVCodecContext *context = streams[packet.stream_index].context; - #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + AVCodecContext *context = streams[packet.stream_index].context; + ret = avcodec_send_packet( context, &packet ); if ( ret < 0 ) { av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); diff --git a/src/zm_libvlc_camera.cpp b/src/zm_libvlc_camera.cpp index a4135d352..45afca636 100644 --- a/src/zm_libvlc_camera.cpp +++ b/src/zm_libvlc_camera.cpp @@ -192,14 +192,12 @@ int LibvlcCamera::PrimeCapture() return(0); } -int LibvlcCamera::PreCapture() -{ +int LibvlcCamera::PreCapture() { return(0); } // Should not return -1 as cancels capture. Always wait for image if available. -int LibvlcCamera::Capture( Image &image ) -{ +ZMPacket * LibvlcCamera::Capture( Image &image ) { while(!mLibvlcData.newImage.getValueImmediate()) mLibvlcData.newImage.getUpdatedValue(1); @@ -208,25 +206,10 @@ int LibvlcCamera::Capture( Image &image ) mLibvlcData.newImage.setValueImmediate(false); mLibvlcData.mutex.unlock(); - return (0); + return new ZMPacket( &image ); } -// Should not return -1 as cancels capture. Always wait for image if available. -int LibvlcCamera::CaptureAndRecord(Image &image, timeval recording, char* event_directory) -{ - while(!mLibvlcData.newImage.getValueImmediate()) - mLibvlcData.newImage.getUpdatedValue(1); - - mLibvlcData.mutex.lock(); - image.Assign(width, height, colours, subpixelorder, mLibvlcData.buffer, width * height * mBpp); - mLibvlcData.newImage.setValueImmediate(false); - mLibvlcData.mutex.unlock(); - - return (0); -} - -int LibvlcCamera::PostCapture() -{ +int LibvlcCamera::PostCapture() { return(0); } diff --git a/src/zm_libvlc_camera.h b/src/zm_libvlc_camera.h index 4221bd0b7..84360a199 100644 --- a/src/zm_libvlc_camera.h +++ b/src/zm_libvlc_camera.h @@ -31,8 +31,7 @@ #endif // Used by libvlc callbacks -struct LibvlcPrivateData -{ +struct LibvlcPrivateData { uint8_t* buffer; uint8_t* prevBuffer; time_t prevTime; @@ -41,8 +40,7 @@ struct LibvlcPrivateData ThreadData newImage; }; -class LibvlcCamera : public Camera -{ +class LibvlcCamera : public Camera { protected: std::string mPath; std::string mMethod; @@ -69,8 +67,7 @@ public: int PrimeCapture(); int PreCapture(); - int Capture( Image &image ); - int CaptureAndRecord( Image &image, timeval recording, char* event_directory ); + ZMPacket *Capture( Image &image ); int PostCapture(); }; diff --git a/src/zm_packet.cpp b/src/zm_packet.cpp index 34a78bd26..e997ba348 100644 --- a/src/zm_packet.cpp +++ b/src/zm_packet.cpp @@ -108,7 +108,7 @@ int ZMPacket::decode( AVCodecContext *ctx ) { # else int frameComplete = 0; - ret = zm_avcodec_decode_video( ctx, frame, &frameComplete, &packet ); + int ret = zm_avcodec_decode_video( ctx, frame, &frameComplete, &packet ); if ( ret < 0 ) { Error( "Unable to decode frame at frame %s", av_make_error_string( ret ) ); av_frame_free( &frame ); From ec3b18f8e84c36c8fa1530814b99cf74fbe9027b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 25 Oct 2017 13:27:34 -0700 Subject: [PATCH 0009/2339] add rouhged in output --- src/zm_ffmpeg_output.cpp | 180 +++++++++++++++++++++++++++++++++++++++ src/zm_ffmpeg_output.h | 46 ++++++++++ 2 files changed, 226 insertions(+) create mode 100644 src/zm_ffmpeg_output.cpp create mode 100644 src/zm_ffmpeg_output.h diff --git a/src/zm_ffmpeg_output.cpp b/src/zm_ffmpeg_output.cpp new file mode 100644 index 000000000..423595d19 --- /dev/null +++ b/src/zm_ffmpeg_output.cpp @@ -0,0 +1,180 @@ + +#include "zm_ffmpeg_input.h" +#include "zm_logger.h" +#include "zm_ffmpeg.h" + +FFmpeg_Output::FFmpeg_Output() { + input_format_context = NULL; + video_stream_id = -1; + audio_stream_id = -1; + av_register_all(); + avcodec_register_all(); + +} +FFmpeg_Output::~FFmpeg_Output() { +} + +int FFmpeg_Output::Open( const char *filepath ) { + + int error; + + /** Open the input file to read from it. */ + if ( (error = avformat_open_input( &input_format_context, filepath, NULL, NULL)) < 0 ) { + + Error("Could not open input file '%s' (error '%s')\n", + filepath, av_make_error_string(error).c_str() ); + input_format_context = NULL; + return error; + } + + /** Get information on the input file (number of streams etc.). */ + if ( (error = avformat_find_stream_info(input_format_context, NULL)) < 0 ) { + Error( "Could not open find stream info (error '%s')\n", + av_make_error_string(error).c_str() ); + avformat_close_input(&input_format_context); + return error; + } + + for ( unsigned int i = 0; i < input_format_context->nb_streams; i += 1 ) { + if ( is_video_stream( input_format_context->streams[i] ) ) { + zm_dump_stream_format(input_format_context, i, 0, 0); + if ( video_stream_id == -1 ) { + video_stream_id = i; + // if we break, then we won't find the audio stream + } else { + Warning( "Have another video stream." ); + } + } else if ( is_audio_stream( input_format_context->streams[i] ) ) { + if ( audio_stream_id == -1 ) { + audio_stream_id = i; + } else { + Warning( "Have another audio stream." ); + } + } + + streams[i].frame_count = 0; +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + streams[i].context = avcodec_alloc_context3( NULL ); + avcodec_parameters_to_context( streams[i].context, input_format_context->streams[i]->codecpar ); +#else + streams[i].context = input_format_context->streams[i]->codec; +#endif + + if ( !(streams[i].codec = avcodec_find_decoder(streams[i].context->codec_id)) ) { + Error( "Could not find input codec\n"); + avformat_close_input(&input_format_context); + return AVERROR_EXIT; + } else { + Debug(1, "Using codec (%s) for stream %d", streams[i].codec->name, i ); + } + + if ((error = avcodec_open2( streams[i].context, streams[i].codec, NULL)) < 0) { + Error( "Could not open input codec (error '%s')\n", + av_make_error_string(error).c_str() ); +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + avcodec_free_context( &streams[i].context ); +#endif + avformat_close_input(&input_format_context); + return error; + } + } // end foreach stream + + if ( video_stream_id == -1 ) + Error( "Unable to locate video stream in %s", filepath ); + if ( audio_stream_id == -1 ) + Debug( 3, "Unable to locate audio stream in %s", filepath ); + + return 0; +} // end int FFmpeg_Output::Open( const char * filepath ) + +AVFrame *FFmpeg_Output::get_frame( int stream_id ) { + Debug(1, "Getting frame from stream %d", stream_id ); + + int frameComplete = false; + AVPacket packet; + av_init_packet( &packet ); + AVFrame *frame = zm_av_frame_alloc(); + char errbuf[AV_ERROR_MAX_STRING_SIZE]; + + while ( !frameComplete ) { + int ret = av_read_frame( input_format_context, &packet ); + if ( ret < 0 ) { + av_strerror(ret, errbuf, AV_ERROR_MAX_STRING_SIZE); + if ( + // Check if EOF. + (ret == AVERROR_EOF || (input_format_context->pb && input_format_context->pb->eof_reached)) || + // Check for Connection failure. + (ret == -110) + ) { + Info( "av_read_frame returned %s.", errbuf ); + return NULL; + } + Error( "Unable to read packet from stream %d: error %d \"%s\".", packet.stream_index, ret, errbuf ); + return NULL; + } + + if ( (stream_id < 0 ) || ( packet.stream_index == stream_id ) ) { + Debug(1,"Packet is for our stream (%d)", packet.stream_index ); + + AVCodecContext *context = streams[packet.stream_index].context; + +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + ret = avcodec_send_packet( context, &packet ); + if ( ret < 0 ) { + av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); + Error( "Unable to send packet at frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf ); + zm_av_packet_unref( &packet ); + continue; + } else { + Debug(1, "Success getting a packet"); + } + +#if HAVE_AVUTIL_HWCONTEXT_H + if ( hwaccel ) { + ret = avcodec_receive_frame( context, hwFrame ); + if ( ret < 0 ) { + av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); + Error( "Unable to receive frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf ); + zm_av_packet_unref( &packet ); + continue; + } + ret = av_hwframe_transfer_data(frame, hwFrame, 0); + if (ret < 0) { + av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); + Error( "Unable to transfer frame at frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf ); + zm_av_packet_unref( &packet ); + continue; + } + } else { +#endif + Debug(1,"Getting a frame?"); + ret = avcodec_receive_frame( context, frame ); + if ( ret < 0 ) { + av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); + Error( "Unable to send packet at frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf ); + zm_av_packet_unref( &packet ); + continue; + } + +#if HAVE_AVUTIL_HWCONTEXT_H + } +#endif + + frameComplete = 1; +# else + ret = zm_avcodec_decode_video( streams[packet.stream_index].context, frame, &frameComplete, &packet ); + if ( ret < 0 ) { + av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); + Error( "Unable to decode frame at frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf ); + zm_av_packet_unref( &packet ); + continue; + } +#endif + } // end if it's the right stream + + zm_av_packet_unref( &packet ); + + } // end while ! frameComplete + return frame; + +} // end AVFrame *FFmpeg_Output::get_frame diff --git a/src/zm_ffmpeg_output.h b/src/zm_ffmpeg_output.h new file mode 100644 index 000000000..76afad0d7 --- /dev/null +++ b/src/zm_ffmpeg_output.h @@ -0,0 +1,46 @@ +#ifndef ZM_FFMPEG_INPUT_H +#define ZM_FFMPEG_INPUT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "libavformat/avformat.h" +#include "libavformat/avio.h" +#include "libavcodec/avcodec.h" + +#ifdef __cplusplus +} +#endif + +class FFmpeg_Output { + + public: + FFmpeg_Output(); + ~FFmpeg_Output(); + + int Open( const char *filename ); + int Close(); + AVFrame *put_frame( int stream_id=-1 ); + AVFrame *put_packet( int stream_id=-1 ); + int get_video_stream_id() { + return video_stream_id; + } + int get_audio_stream_id() { + return audio_stream_id; + } + + private: + typedef struct { + AVCodecContext *context; + AVCodec *codec; + int frame_count; + } stream; + + stream streams[2]; + int video_stream_id; + int audio_stream_id; + AVFormatContext *input_format_context; +}; + +#endif From 0265a48a3049b842f7c2f20de7c95b4e2c8bb173 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 26 Oct 2017 10:12:56 -0700 Subject: [PATCH 0010/2339] fix seg fault, fix pkt pts dts/duration. Stil wrong framerate --- db/zm_create.sql.in | 2 + src/zm_event.cpp | 3 +- src/zm_ffmpeg_camera.cpp | 23 ++- src/zm_ffmpeg_camera.h | 1 + src/zm_monitor.cpp | 4 +- src/zm_monitor.h | 2 + src/zm_videostore.cpp | 427 ++++++++++++++++++++++++++------------- src/zm_videostore.h | 8 + web/includes/Event.php | 31 +-- 9 files changed, 329 insertions(+), 172 deletions(-) diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index 01176eb43..6c271292d 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -384,6 +384,8 @@ CREATE TABLE `Monitors` ( `Deinterlacing` int(10) unsigned NOT NULL default '0', `SaveJPEGs` TINYINT NOT NULL DEFAULT '3' , `VideoWriter` TINYINT NOT NULL DEFAULT '0', + `OutputCodec` enum('h264','mjpeg'), + `OutputContainer` enum('mp4','mkv'), `EncoderParameters` TEXT, `RecordAudio` TINYINT NOT NULL DEFAULT '0', `RTSPDescribe` tinyint(1) unsigned, diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 9b98ea4c1..4a4c841fb 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -168,7 +168,7 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string snprintf( video_name, sizeof(video_name), "%d-%s", id, "video.mp4" ); snprintf( video_file, sizeof(video_file), staticConfig.video_file_format, path, video_name ); Debug(1,"Writing video file to %s", video_file ); - +#if 0 /* X264 MP4 video writer */ if ( monitor->GetOptVideoWriter() == Monitor::X264ENCODE ) { #if ZM_HAVE_VIDEOWRITER_X264MP4 @@ -196,6 +196,7 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string Error("Failed creating timecodes file"); } } +#endif } else { /* No video object */ videowriter = NULL; diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 3339f2958..dfcdd1b05 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -527,6 +527,18 @@ int FfmpegCamera::OpenFfmpeg() { } } + if ( mVideoCodecContext->codec_id != AV_CODEC_ID_H264 ) { +#ifdef AV_CODEC_ID_H265 + if ( mVideoCodecContext->codec_id == AV_CODEC_ID_H265 ) { + Debug( 1, "Input stream appears to be h265. The stored event file may not be viewable in browser." ); + } else { +#endif + Warning( "Input stream is not h264. The stored event file may not be viewable in browser." ); +#ifdef AV_CODEC_ID_H265 + } +#endif + } + if (mVideoCodecContext->hwaccel != NULL) { Debug(1, "HWACCEL in use"); } else { @@ -735,17 +747,6 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event mReopenThread = 0; } - if ( mVideoCodecContext->codec_id != AV_CODEC_ID_H264 ) { -#ifdef AV_CODEC_ID_H265 - if ( mVideoCodecContext->codec_id == AV_CODEC_ID_H265 ) { - Debug( 1, "Input stream appears to be h265. The stored event file may not be viewable in browser." ); - } else { -#endif - Error( "Input stream is not h264. The stored event file may not be viewable in browser." ); -#ifdef AV_CODEC_ID_H265 - } -#endif - } int frameComplete = false; while ( ! frameComplete ) { diff --git a/src/zm_ffmpeg_camera.h b/src/zm_ffmpeg_camera.h index 9e10b76bf..3ed5d39aa 100644 --- a/src/zm_ffmpeg_camera.h +++ b/src/zm_ffmpeg_camera.h @@ -41,6 +41,7 @@ class FfmpegCamera : public Camera { std::string mPath; std::string mMethod; std::string mOptions; + std::string encoder_options; int frameCount; diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index e51c2ca7d..1b3ed85ac 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1378,12 +1378,12 @@ bool Monitor::Analyse() { if ( event ) { //TODO: We shouldn't have to do this every time. Not sure why it clears itself if this isn't here?? //snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "%s", event->getEventFile()); - Debug( 3, "Detected new event at (%d.%d)", timestamp->tv_sec,timestamp->tv_usec ); + //Debug( 3, "Detected new event at (%d.%d)", timestamp->tv_sec,timestamp->tv_usec ); if ( section_length ) { // TODO: Wouldn't this be clearer if we just did something like if now - event->start > section_length ? int section_mod = timestamp->tv_sec % section_length; - Debug( 3, "Section length (%d) Last Section Mod(%d), new section mod(%d)", section_length, last_section_mod, section_mod ); + Debug( 4, "Section length (%d) Last Section Mod(%d), new section mod(%d)", section_length, last_section_mod, section_mod ); if ( section_mod < last_section_mod ) { //if ( state == IDLE || state == TAPE || event_close_mode == CLOSE_TIME ) { //if ( state == TAPE ) { diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 925e0d14a..c28bc389f 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -432,6 +432,8 @@ public: int GetOptSaveJPEGs() const { return( savejpegspref ); } VideoWriter GetOptVideoWriter() const { return( videowriter ); } const std::vector* GetOptEncoderParams() const { return( &encoderparamsvec ); } + const std::string &GetEncoderOptions() const { return( encoderparams ); } + uint32_t GetLastEventId() const { return shared_data->last_event; } uint32_t GetVideoWriterEventId() const { return video_store_data->current_event; } void SetVideoWriterEventId( uint32_t p_event_id ) { video_store_data->current_event = p_event_id; } diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 208f64818..bc6c49e6f 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -31,10 +31,12 @@ extern "C" { #include "libavutil/time.h" } -VideoStore::VideoStore(const char *filename_in, const char *format_in, - AVStream *p_video_in_stream, - AVStream *p_audio_in_stream, int64_t nStartTime, - Monitor *monitor) { +VideoStore::VideoStore( + const char *filename_in, const char *format_in, + AVStream *p_video_in_stream, + AVStream *p_audio_in_stream, int64_t nStartTime, + Monitor *monitor + ) { video_in_stream = p_video_in_stream; audio_in_stream = p_audio_in_stream; @@ -50,9 +52,12 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, // store ins in variables local to class filename = filename_in; format = format_in; + packets_written = 0; + frame_count = 0; Info("Opening video storage stream %s format: %s", filename, format); +#if 0 ret = avformat_alloc_output_context2(&oc, NULL, NULL, filename); if (ret < 0) { Warning( @@ -65,6 +70,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, // Couldn't deduce format from filename, trying from format name if (!oc) { +#endif avformat_alloc_output_context2(&oc, NULL, format, filename); if (!oc) { Fatal( @@ -72,9 +78,11 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, " could not be assigned based on filename or format %s", filename, format); } else { - Debug(4, "Success alocateing out ctx"); + Debug(4, "Success alocating out ctx"); } +#if 0 } // end if ! oc +#endif AVDictionary *pmetadata = NULL; int dsr = @@ -84,15 +92,14 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, oc->metadata = pmetadata; out_format = oc->oformat; + in_frame = NULL; #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - - // Since we are not re-encoding, all we have to do is copy the parameters video_out_ctx = avcodec_alloc_context3(NULL); // Copy params from instream to ctx ret = avcodec_parameters_to_context(video_out_ctx, video_in_stream->codecpar); - if (ret < 0) { + if ( ret < 0 ) { Error("Could not initialize ctx parameteres"); return; } else { @@ -106,7 +113,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, Debug(2, "Success creating video out stream"); } - if (!video_out_ctx->codec_tag) { + if ( !video_out_ctx->codec_tag ) { video_out_ctx->codec_tag = av_codec_get_tag(oc->oformat->codec_tag, video_in_ctx->codec_id); Debug(2, "No codec_tag, setting to %d", video_out_ctx->codec_tag); @@ -124,22 +131,80 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, zm_dump_codecpar(video_out_stream->codecpar); #else - video_out_stream = - avformat_new_stream(oc,(const AVCodec *)(video_in_ctx->codec)); - if (!video_out_stream) { + if ( video_in_ctx->codec_id == AV_CODEC_ID_H264 ) { + // Same codec, just copy the packets, otherwise we have to decode/encode + video_out_codec = (AVCodec *)video_in_ctx->codec; + video_out_stream = avformat_new_stream(oc, video_out_codec); + if ( !video_out_stream ) { + Fatal("Unable to create video out stream\n"); + } else { + Debug(2, "Success creating video out stream"); + } + video_out_ctx = video_out_stream->codec; + // Just copy them from the in, no reason to choose different + video_out_ctx->time_base = video_in_ctx->time_base; + video_out_stream->time_base = video_in_stream->time_base; + } else { + /** Create a new frame to store the audio samples. */ + if ( !(in_frame = zm_av_frame_alloc()) ) { + Error("Could not allocate in frame"); + return; + } + video_out_codec = avcodec_find_encoder(AV_CODEC_ID_H264); + if (!video_out_codec) { + Fatal("Could not find codec for H264"); + } + Debug(2, "Have video out codec"); + } + video_out_stream = avformat_new_stream(oc, video_out_codec); + if ( !video_out_stream ) { Fatal("Unable to create video out stream\n"); } else { Debug(2, "Success creating video out stream"); } video_out_ctx = video_out_stream->codec; - ret = avcodec_copy_context(video_out_ctx, video_in_ctx); - if (ret < 0) { - Fatal("Unable to copy in video ctx to out video ctx %s\n", - av_make_error_string(ret).c_str()); + + // * Copy over the useful; parameters + video_out_ctx->height = video_in_ctx->height; + video_out_ctx->width = video_in_ctx->width; + video_out_ctx->sample_aspect_ratio = video_in_ctx->sample_aspect_ratio; + /* take first format from list of supported formats */ + video_out_ctx->pix_fmt = video_out_codec->pix_fmts[0]; + /* video time_base can be set to whatever is handy and supported by encoder */ + //video_out_ctx->time_base = video_in_ctx->time_base; + video_out_ctx->time_base = (AVRational){1, 1000}; // Milliseconds as base frame rate + video_out_ctx->framerate = (AVRational){0,1}; // Unknown framerate + + AVDictionary *opts = 0; + std::string Options = monitor->GetEncoderOptions(); + ret = av_dict_parse_string(&opts, Options.c_str(), "=", ",#\n", 0); + if ( ret < 0 ) { + Warning("Could not parse ffmpeg encoder options list '%s'\n", Options.c_str()); } else { - Debug(3, "Success copying ctx"); + AVDictionaryEntry *e = NULL; + while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { + Debug( 3, "Encoder Option %s=%s", e->key, e->value ); + } } - if (!video_out_ctx->codec_tag) { + ret = avcodec_open2(video_out_ctx, video_out_codec, &opts ); + if (ret < 0) { + Error("Can't open video codec!"); + return; + } + AVDictionaryEntry *e = NULL; + while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { + Warning( "Encoder Option %s not recognized by ffmpeg codec", e->key); + } + av_dict_free(&opts); + //ret = avcodec_copy_context(video_out_ctx, video_in_ctx); + //if ( ret < 0 ) { + //Fatal("Unable to copy in video ctx to out video ctx %s\n", + //av_make_error_string(ret).c_str()); + ////} else { + //Debug(3, "Success copying ctx"); + //} +#if 0 + if ( !video_out_ctx->codec_tag ) { Debug(2, "No codec_tag"); if (!oc->oformat->codec_tag || av_codec_get_id(oc->oformat->codec_tag, @@ -152,10 +217,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, } } #endif - - // Just copy them from the in, no reason to choose different - video_out_ctx->time_base = video_in_ctx->time_base; - video_out_stream->time_base = video_in_stream->time_base; +#endif Debug(3, "Time bases: VIDEO in stream (%d/%d) in codec: (%d/%d) out " @@ -192,7 +254,6 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, audio_out_codec = NULL; audio_in_ctx = NULL; audio_out_stream = NULL; - in_frame = NULL; out_frame = NULL; #ifdef HAVE_LIBAVRESAMPLE resample_ctx = NULL; @@ -329,17 +390,86 @@ bool VideoStore::open() { return true; } +void VideoStore::write_audio_packet( AVPacket &pkt ) { + Debug(2, "writing flushed packet pts(%d) dts(%d) duration(%d)", pkt.pts, + pkt.dts, pkt.duration); + pkt.pts = audio_next_pts; + pkt.dts = audio_next_dts; + + if (pkt.duration > 0) + pkt.duration = + av_rescale_q(pkt.duration, audio_out_ctx->time_base, + audio_out_stream->time_base); + audio_next_pts += pkt.duration; + audio_next_dts += pkt.duration; + + Debug(2, "writing flushed packet pts(%d) dts(%d) duration(%d)", pkt.pts, + pkt.dts, pkt.duration); + pkt.stream_index = audio_out_stream->index; + av_interleaved_write_frame(oc, &pkt); +} + VideoStore::~VideoStore() { + if ( video_out_ctx->codec_id != video_in_ctx->codec_id ) { + + if (video_out_ctx->codec->capabilities & AV_CODEC_CAP_DELAY) { + // The codec queues data. We need to send a flush command and out + // whatever we get. Failures are not fatal. + AVPacket pkt; + av_init_packet(&pkt); + +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + // Put encoder into flushing mode + avcodec_send_frame(video_out_ctx, NULL); + while (1) { + ret = avcodec_receive_packet(video_out_ctx, &pkt); + if (ret < 0) { + if (AVERROR_EOF != ret) { + Error("ERror encoding audio while flushing (%d) (%s)", ret, + av_err2str(ret)); + } + break; + } +#else + while (1) { + // WIthout these we seg fault I don't know why. + pkt.data = NULL; + pkt.size = 0; + av_init_packet(&pkt); + int got_packet = 0; + ret = avcodec_encode_video2(video_out_ctx, &pkt, NULL, &got_packet); + if ( ret < 0 ) { + Error("ERror encoding video while flushing (%d) (%s)", ret, + av_err2str(ret)); + break; + } + if (!got_packet) { + break; + } +#endif +Debug(3, "(%d, %d)", video_next_dts, video_next_pts ); + pkt.dts = video_next_dts; + pkt.pts = video_next_pts; + pkt.duration = video_last_duration; + write_video_packet(pkt); + zm_av_packet_unref(&pkt); + } // while have buffered frames + } // end if have delay capability + } // end if have buffered video + if (audio_out_codec) { // The codec queues data. We need to send a flush command and out // whatever we get. Failures are not fatal. AVPacket pkt; + // WIthout these we seg fault I don't know why. + pkt.data = NULL; + pkt.size = 0; av_init_packet(&pkt); - while (1) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - // Put encoder into flushing mode - avcodec_send_frame(audio_out_ctx, NULL); + // Put encoder into flushing mode + avcodec_send_frame(audio_out_ctx, NULL); + while (1) { ret = avcodec_receive_packet(audio_out_ctx, &pkt); if (ret < 0) { if (AVERROR_EOF != ret) { @@ -349,6 +479,7 @@ VideoStore::~VideoStore() { break; } #else + while (1) { int got_packet = 0; ret = avcodec_encode_audio2(audio_out_ctx, &pkt, NULL, &got_packet); @@ -362,22 +493,7 @@ VideoStore::~VideoStore() { break; } #endif - Debug(2, "writing flushed packet pts(%d) dts(%d) duration(%d)", pkt.pts, - pkt.dts, pkt.duration); - pkt.pts = audio_next_pts; - pkt.dts = audio_next_dts; - - if (pkt.duration > 0) - pkt.duration = - av_rescale_q(pkt.duration, audio_out_ctx->time_base, - audio_out_stream->time_base); - audio_next_pts += pkt.duration; - audio_next_dts += pkt.duration; - - Debug(2, "writing flushed packet pts(%d) dts(%d) duration(%d)", pkt.pts, - pkt.dts, pkt.duration); - pkt.stream_index = audio_out_stream->index; - av_interleaved_write_frame(oc, &pkt); + write_audio_packet(pkt); zm_av_packet_unref(&pkt); } // while have buffered frames } // end if audio_out_codec @@ -402,6 +518,11 @@ VideoStore::~VideoStore() { video_out_ctx = NULL; Debug(4, "Success freeing video_out_ctx"); } +// Used by both audio and video conversions + if (in_frame) { + av_frame_free(&in_frame); + in_frame = NULL; + } if (audio_out_stream) { avcodec_close(audio_out_ctx); audio_out_ctx = NULL; @@ -410,10 +531,6 @@ VideoStore::~VideoStore() { avresample_close(resample_ctx); avresample_free(&resample_ctx); } - if (in_frame) { - av_frame_free(&in_frame); - in_frame = NULL; - } if (out_frame) { av_frame_free(&out_frame); out_frame = NULL; @@ -547,10 +664,12 @@ bool VideoStore::setup_resampler() { audio_out_ctx->channel_layout, audio_out_ctx->frame_size); /** Create a new frame to store the audio samples. */ + if ( ! in_frame ) { if (!(in_frame = zm_av_frame_alloc())) { Error("Could not allocate in frame"); return false; } + } /** Create a new frame to store the audio samples. */ if (!(out_frame = zm_av_frame_alloc())) { @@ -675,92 +794,117 @@ void VideoStore::dumpPacket(AVPacket *pkt) { int VideoStore::writeVideoFramePacket(AVPacket *ipkt) { av_init_packet(&opkt); + frame_count += 1; + if ( video_out_ctx->codec_id != video_in_ctx->codec_id ) { + Debug(3, "Have encoding video frmae count (%d)", frame_count); - opkt.pts = video_next_pts; - opkt.dts = video_next_dts; - opkt.duration = 0; - - int duration; - if (!video_last_pts) { - duration = 0; - } else { - duration = - av_rescale_q(ipkt->pts - video_last_pts, video_in_stream->time_base, - video_out_stream->time_base); - Debug(1, "duration calc: pts(%d) - last_pts(%d) = (%d)", ipkt->pts, - video_last_pts, duration); - if (duration < 0) { - duration = ipkt->duration; +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + ret = avcodec_send_packet(video_in_ctx, ipkt); + if (ret < 0) { + Error("avcodec_send_packet fail %s", av_make_error_string(ret).c_str()); + return 0; } - } - //#if ( 0 && video_last_pts && ( ipkt->duration == AV_NOPTS_VALUE || ! - //ipkt->duration ) ) { - // Video packets don't really have a duration. Audio does. - // opkt.duration = av_rescale_q(duration, video_in_stream->time_base, - // video_out_stream->time_base); - // opkt.duration = 0; - //} else { - // duration = opkt.duration = av_rescale_q(ipkt->duration, - // video_in_stream->time_base, video_out_stream->time_base); - //} - video_last_pts = ipkt->pts; - video_last_dts = ipkt->dts; + ret = avcodec_receive_frame(video_in_ctx, in_frame); + if ( ret < 0 ) { + Error("avcodec_receive_frame fail %s", av_make_error_string(ret).c_str()); + return 0; + } + if ((ret = avcodec_send_frame(video_out_ctx, in_frame)) < 0) { + Error("Could not send frame (error '%s')", + av_make_error_string(ret).c_str()); + zm_av_packet_unref(&opkt); + return 0; + } -#if 0 - //Scale the PTS of the outgoing packet to be the correct time base - if ( ipkt->pts != AV_NOPTS_VALUE ) { - - if ( ! video_last_pts ) { - // This is the first packet. - opkt.pts = 0; - Debug(2, "Starting video video_last_pts will become (%d)", ipkt->pts); + if ((ret = avcodec_receive_packet(video_out_ctx, &opkt)) < 0) { + if (AVERROR(EAGAIN) == ret) { + // THe codec may need more samples than it has, perfectly valid + Debug(3, "Could not recieve packet (error '%s')", + av_make_error_string(ret).c_str()); + } else { + Error("Could not recieve packet (error %d = '%s')", ret, + av_make_error_string(ret).c_str()); + } + zm_av_packet_unref(&opkt); + av_frame_unref(in_frame); + return 0; + } +#else + /** + * Decode the video frame stored in the packet. + * The in video stream decoder is used to do this. + * If we are at the end of the file, pass an empty packet to the decoder + * to flush it. + */ + if ((ret = avcodec_decode_video2(video_in_ctx, in_frame, + &data_present, ipkt)) < 0) { + Error("Could not decode frame (error '%s')\n", + av_make_error_string(ret).c_str()); + dumpPacket(ipkt); + av_frame_free(&in_frame); + return 0; } else { - if ( ipkt->pts < video_last_pts ) { - Debug(1, "Resetting video_last_pts from (%d) to (%d)", video_last_pts, ipkt->pts); - // wrap around, need to figure out the distance FIXME having this wrong should cause a jump, but then play ok? - opkt.pts = video_next_pts + av_rescale_q( ipkt->pts, video_in_stream->time_base, video_out_stream->time_base); - } else { - opkt.pts = video_next_pts + av_rescale_q( ipkt->pts - video_last_pts, video_in_stream->time_base, video_out_stream->time_base); - } + Debug(3, "Decoded frame data_present(%d)", data_present); } - Debug(3, "opkt.pts = %d from ipkt->pts(%d) - last_pts(%d)", opkt.pts, ipkt->pts, video_last_pts); - video_last_pts = ipkt->pts; - } else { - Debug(3, "opkt.pts = undef"); - opkt.pts = AV_NOPTS_VALUE; - } - // Just because the in stream wraps, doesn't mean the out needs to. Really, if we are limiting ourselves to 10min segments I can't imagine every wrapping in the out. So need to handle in wrap, without causing out wrap. - if ( !video_last_dts ) { - // This is the first packet. - opkt.dts = 0; - Debug(1, "Starting video video_last_dts will become (%lu)", ipkt->dts); - video_last_dts = ipkt->dts; - } else { - // Scale the DTS of the outgoing packet to be the correct time base - - if ( ipkt->dts == AV_NOPTS_VALUE ) { - // why are we using cur_dts instead of packet.dts? I think cur_dts is in AV_TIME_BASE_Q, but ipkt.dts is in video_in_stream->time_base - if ( video_in_stream->cur_dts < video_last_dts ) { - Debug(1, "Resetting video_last_dts from (%d) to (%d) p.dts was (%d)", video_last_dts, video_in_stream->cur_dts, ipkt->dts); - opkt.dts = video_next_dts + av_rescale_q(video_in_stream->cur_dts, AV_TIME_BASE_Q, video_out_stream->time_base); - } else { - opkt.dts = video_next_dts + av_rescale_q(video_in_stream->cur_dts - video_last_dts, AV_TIME_BASE_Q, video_out_stream->time_base); - } - Debug(3, "opkt.dts = %d from video_in_stream->cur_dts(%d) - previus_dts(%d)", opkt.dts, video_in_stream->cur_dts, video_last_dts); - video_last_dts = video_in_stream->cur_dts; - } else { - if ( ipkt->dts < video_last_dts ) { - Debug(1, "Resetting video_last_dts from (%d) to (%d)", video_last_dts, ipkt->dts); - opkt.dts = video_next_dts + av_rescale_q( ipkt->dts, video_in_stream->time_base, video_out_stream->time_base); - } else { - opkt.dts = video_next_dts + av_rescale_q( ipkt->dts - video_last_dts, video_in_stream->time_base, video_out_stream->time_base); - } - Debug(3, "opkt.dts = %d from ipkt.dts(%d) - previus_dts(%d)", opkt.dts, ipkt->dts, video_last_dts); - video_last_dts = ipkt->dts; + if ( !data_present ) { + Debug(2, "Not ready to transcode a frame yet."); + return 0; + } + if ((ret = avcodec_encode_video2(video_out_ctx, &opkt, in_frame, + &data_present)) < 0) { + Error("Could not encode frame (error '%s')", + av_make_error_string(ret).c_str()); + zm_av_packet_unref(&opkt); + return 0; + } + if (!data_present) { + Debug(2, "Not ready to out a frame yet."); + zm_av_packet_unref(&opkt); + return 0; } - } #endif + } else { + Debug(3, "Doing passthrough, just copy packet"); + // Just copy it because the codec is the same + opkt.data = ipkt->data; + opkt.size = ipkt->size; + opkt.flags = ipkt->flags; + } + + opkt.dts = video_next_dts; + opkt.pts = video_next_pts; + + int duration; + if ( !video_last_pts ) { + duration = 0; + } else { + duration = av_rescale_q( + ipkt->pts - video_last_pts, + video_in_stream->time_base, + video_out_stream->time_base + ); + Debug(1, "duration calc: pts(%d) - last_pts(%d) = (%d)", ipkt->pts, + video_last_pts, duration); + if ( duration < 0 ) { + duration = ipkt->duration; + } + } + + Debug(1, "ipkt.dts(%d) ipkt.pts(%d)", ipkt->dts, ipkt->pts); + video_last_pts = ipkt->pts; + video_last_dts = ipkt->dts; + video_last_duration = duration; + opkt.duration = duration; + + write_video_packet( opkt ); + zm_av_packet_unref(&opkt); + + return 0; +} // end int VideoStore::writeVideoFramePacket( AVPacket *ipkt ) + +void VideoStore::write_video_packet( AVPacket &opkt ) { + if (opkt.dts > opkt.pts) { Debug(1, "opkt.dts(%d) must be <= opkt.pts(%d). Decompression must happen " @@ -769,36 +913,30 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) { opkt.dts = opkt.pts; } - opkt.flags = ipkt->flags; int keyframe = opkt.flags & AV_PKT_FLAG_KEY; opkt.pos = -1; - - opkt.data = ipkt->data; - opkt.size = ipkt->size; - opkt.stream_index = video_out_stream->index; + video_next_dts += opkt.duration; + video_next_pts += opkt.duration; + AVPacket safepkt; memcpy(&safepkt, &opkt, sizeof(AVPacket)); Debug(1, - "writing video packet keyframe(%d) pts(%d) dts(%d) duration(%d) " - "ipkt.duration(%d)", - keyframe, opkt.pts, opkt.dts, duration, ipkt->duration); - if ((opkt.data == NULL) || (opkt.size < 1)) { + "writing video packet keyframe(%d) pts(%d) dts(%d) duration(%d) packet_count(%d)", + keyframe, opkt.pts, opkt.dts, opkt.duration, packets_written ); + if ( (opkt.data == NULL) || (opkt.size < 1) ) { Warning("%s:%d: Mangled AVPacket: discarding frame", __FILE__, __LINE__); - dumpPacket(ipkt); dumpPacket(&opkt); - } else if ((video_next_dts > 0) && (video_next_dts > opkt.dts)) { - Warning("%s:%d: DTS out of order: %lld \u226E %lld; discarding frame", - __FILE__, __LINE__, video_next_dts, opkt.dts); - video_next_dts = opkt.dts; - dumpPacket(&opkt); + //} else if ((video_next_dts > 0) && (video_next_dts > opkt.dts)) { + //Warning("%s:%d: DTS out of order: next:%lld \u226E opkt.dts %lld; discarding frame", + //__FILE__, __LINE__, video_next_dts, opkt.dts); + //video_next_dts = opkt.dts; + //dumpPacket(&opkt); } else { - video_next_dts = opkt.dts + duration; - video_next_pts = opkt.pts + duration; ret = av_interleaved_write_frame(oc, &opkt); if (ret < 0) { // There's nothing we can really do if the frame is rejected, just drop it @@ -812,13 +950,12 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) { zm_dump_codecpar(video_in_stream->codecpar); zm_dump_codecpar(video_out_stream->codecpar); #endif + } else { + packets_written += 1; } } - zm_av_packet_unref(&opkt); - - return 0; -} // end int VideoStore::writeVideoFramePacket( AVPacket *ipkt ) +} // end void VideoStore::write_video_packet int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { Debug(4, "writeAudioFrame"); diff --git a/src/zm_videostore.h b/src/zm_videostore.h index 0751114f8..292b91daa 100644 --- a/src/zm_videostore.h +++ b/src/zm_videostore.h @@ -17,11 +17,14 @@ extern "C" { class VideoStore { private: unsigned int packets_written; + unsigned int frame_count; AVOutputFormat *out_format; AVFormatContext *oc; AVStream *video_out_stream; AVStream *audio_out_stream; + + AVCodec *video_out_codec; AVCodecContext *video_out_ctx; AVStream *video_in_stream; @@ -30,6 +33,7 @@ private: // Move this into the object so that we aren't constantly allocating/deallocating it on the stack AVPacket opkt; // we are transcoding + AVFrame *video_in_frame; AVFrame *in_frame; AVFrame *out_frame; @@ -57,12 +61,14 @@ AVAudioResampleContext* resample_ctx; // These are for in int64_t video_last_pts; int64_t video_last_dts; + int64_t video_last_duration; int64_t audio_last_pts; int64_t audio_last_dts; // These are for out, should start at zero. We assume they do not wrap because we just aren't going to save files that big. int64_t video_next_pts; int64_t video_next_dts; +; int64_t audio_next_pts; int64_t audio_next_dts; @@ -81,6 +87,8 @@ public: bool open(); ~VideoStore(); + void write_video_packet( AVPacket &pkt ); + void write_audio_packet( AVPacket &pkt ); int writeVideoFramePacket( AVPacket *pkt ); int writeAudioFramePacket( AVPacket *pkt ); void dumpPacket( AVPacket *pkt ); diff --git a/web/includes/Event.php b/web/includes/Event.php index 392973a6a..9f775f039 100644 --- a/web/includes/Event.php +++ b/web/includes/Event.php @@ -198,14 +198,6 @@ class Event { } function createListThumbnail( $overwrite=false ) { - # Load the frame with the highest score to use as a thumbnail - if ( !($frame = dbFetchOne( 'SELECT * FROM Frames WHERE EventId=? AND Score=? ORDER BY FrameId LIMIT 1', NULL, array( $this->{'Id'}, $this->{'MaxScore'} ) )) ) { - Error("Unable to find a Frame matching max score " . $this->{'MaxScore'} . ' for event ' . $this->{'Id'} ); - // FIXME: What if somehow the db frame was lost or score was changed? Should probably try another search for any frame. - return( false ); - } - - $frameId = $frame['FrameId']; if ( ZM_WEB_LIST_THUMB_WIDTH ) { $thumbWidth = ZM_WEB_LIST_THUMB_WIDTH; @@ -219,12 +211,25 @@ class Event { Fatal( "No thumbnail width or height specified, please check in Options->Web" ); } - $imageData = $this->getImageSrc( $frame, $scale, false, $overwrite ); - if ( ! $imageData ) { - return ( false ); + $eventPath = $this->Path(); + if ( file_exists( $eventPath.'/snapshot.jpg' ) ) { + $frame = 'snapshot'; + $humbData = array('Path'=>$eventPath.'/snapshot.jpg'); + } else { +# Load the frame with the highest score to use as a thumbnail + if ( !($frame = dbFetchOne( 'SELECT * FROM Frames WHERE EventId=? AND Score=? ORDER BY FrameId LIMIT 1', NULL, array( $this->{'Id'}, $this->{'MaxScore'} ) )) ) { + Error("Unable to find a Frame matching max score " . $this->{'MaxScore'} . ' for event ' . $this->{'Id'} ); + // FIXME: What if somehow the db frame was lost or score was changed? Should probably try another search for any frame. + return( false ); + } + + $imageData = $this->getImageSrc( $frame, $scale, false, $overwrite ); + if ( ! $imageData ) { + return ( false ); + } + $thumbData = $frame; + $thumbData['Path'] = $imageData['thumbPath']; } - $thumbData = $frame; - $thumbData['Path'] = $imageData['thumbPath']; $thumbData['Width'] = (int)$thumbWidth; $thumbData['Height'] = (int)$thumbHeight; From 230daa74da1488000d16ef77de0ca9ecd23ab864 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Oct 2017 09:05:07 -0700 Subject: [PATCH 0011/2339] add apache log style aliases --- scripts/ZoneMinder/lib/ZoneMinder/Logger.pm | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm index 031a2b7b6..d0d6b234b 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm @@ -678,6 +678,8 @@ sub Dump { fetch()->logPrint( DEBUG, Data::Dumper->Dump( [ $var ], [ $label ] ) ); } +sub debug { fetch()->logPrint( DEBUG, @_ ); } + sub Debug( @ ) { fetch()->logPrint( DEBUG, @_ ); } @@ -685,14 +687,24 @@ sub Debug( @ ) { sub Info( @ ) { fetch()->logPrint( INFO, @_ ); } +sub info { + fetch()->logPrint( INFO, @_ ); +} + sub Warning( @ ) { fetch()->logPrint( WARNING, @_ ); } +sub warn { + fetch()->logPrint( WARNING, @_ ); +} sub Error( @ ) { fetch()->logPrint( ERROR, @_ ); } +sub error { + fetch()->logPrint( ERROR, @_ ); +} sub Fatal( @ ) { fetch()->logPrint( FATAL, @_ ); From e84bf6260bee9c649cdb9322bb66d656329d840a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Oct 2017 09:05:25 -0700 Subject: [PATCH 0012/2339] add save, set, transform, and some globals pointing to dbh and log --- scripts/ZoneMinder/lib/ZoneMinder/Object.pm | 269 +++++++++++++++++++- 1 file changed, 268 insertions(+), 1 deletion(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Object.pm b/scripts/ZoneMinder/lib/ZoneMinder/Object.pm index 63193bccf..af4d9fd21 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Object.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Object.pm @@ -42,7 +42,12 @@ use ZoneMinder::Config qw(:all); use ZoneMinder::Logger qw(:all); use ZoneMinder::Database qw(:all); -use vars qw/ $AUTOLOAD /; +use vars qw/ $AUTOLOAD $log $dbh/; + +*log = \$ZoneMinder::Logger::logger; +*dbh = \$ZoneMinder::Database::dbh; + +my $debug = 1; sub new { my ( $parent, $id, $data ) = @_; @@ -110,7 +115,269 @@ sub AUTOLOAD { return $_[0]{$name}; } +sub save { + my ( $self, $data, $force_insert ) = @_; + my $type = ref $self; + if ( ! $type ) { + my ( $caller, undef, $line ) = caller; + $log->error("No type in Object::save. self:$self from $caller:$line"); + } + my $local_dbh = eval '$'.$type.'::dbh'; + $local_dbh = $ZoneMinder::Database::dbh if ! $local_dbh; + $self->set( $data ? $data : {} ); + if ( $debug or DEBUG_ALL ) { + if ( $data ) { + foreach my $k ( keys %$data ) { + $log->debug("Object::save after set $k => $$data{$k} $$self{$k}"); + } + } else { + $log->debug("No data after set"); + } + } +#$debug = 0; + + my $table = eval '$'.$type.'::table'; + my $fields = eval '\%'.$type.'::fields'; + my $debug = eval '$'.$type.'::debug'; + #$debug = DEBUG_ALL if ! $debug; + + my %sql; + foreach my $k ( keys %$fields ) { + $sql{$$fields{$k}} = $$self{$k} if defined $$fields{$k}; + } # end foreach + if ( ! $force_insert ) { + $sql{$$fields{updated_on}} = 'NOW()' if exists $$fields{updated_on}; + } # end if + my $serial = eval '$'.$type.'::serial'; + my @identified_by = eval '@'.$type.'::identified_by'; + + my $ac = sql::start_transaction( $local_dbh ); + if ( ! $serial ) { + my $insert = $force_insert; + my %serial = eval '%'.$type.'::serial'; + if ( ! %serial ) { +$log->debug("No serial") if $debug; + # No serial columns defined, which means that we will do saving by delete/insert instead of insert/update + if ( @identified_by ) { + my $where = join(' AND ', map { $$fields{$_}.'=?' } @identified_by ); + if ( $debug ) { + $log->debug("DELETE FROM $table WHERE $where"); + } # end if + + if ( ! ( ( $_ = $local_dbh->prepare("DELETE FROM $table WHERE $where") ) and $_->execute( @$self{@identified_by} ) ) ) { + $where =~ s/\?/\%s/g; + $log->error("Error deleting: DELETE FROM $table WHERE " . sprintf($where, map { defined $_ ? $_ : 'undef' } ( @$self{@identified_by}) ).'):' . $local_dbh->errstr); + $local_dbh->rollback(); + sql::end_transaction( $local_dbh, $ac ); + return $local_dbh->errstr; + } elsif ( $debug ) { + $log->debug("SQL succesful DELETE FROM $table WHERE $where"); + } # end if + } # end if + $insert = 1; + } else { + foreach my $id ( @identified_by ) { + if ( ! $serial{$id} ) { + my ( $caller, undef, $line ) = caller; + $log->error("$id nor in serial for $type from $caller:$line") if $debug; + next; + } + if ( ! $$self{$id} ) { + ($$self{$id}) = ($sql{$$fields{$id}}) = $local_dbh->selectrow_array( q{SELECT nextval('} . $serial{$id} . q{')} ); + $log->debug("SQL statement execution SELECT nextval('$serial{$id}') returned $$self{$id}") if $debug or DEBUG_ALL; + $insert = 1; + } # end if + } # end foreach + } # end if ! %serial + + if ( $insert ) { + my @keys = keys %sql; + my $command = "INSERT INTO $table (" . join(',', @keys ) . ') VALUES (' . join(',', map { '?' } @sql{@keys} ) . ')'; + if ( ! ( ( $_ = $local_dbh->prepare($command) ) and $_->execute( @sql{@keys} ) ) ) { + my $error = $local_dbh->errstr; + $command =~ s/\?/\%s/g; + $log->error('SQL statement execution failed: ('.sprintf($command, , map { defined $_ ? $_ : 'undef' } ( @sql{@keys}) ).'):' . $local_dbh->errstr); + $local_dbh->rollback(); + sql::end_transaction( $local_dbh, $ac ); + return $error; + } # end if + if ( $debug or DEBUG_ALL ) { + $command =~ s/\?/\%s/g; + $log->debug('SQL statement execution: ('.sprintf($command, , map { defined $_ ? $_ : 'undef' } ( @sql{@keys} ) ).'):' ); + } # end if + } else { + my @keys = keys %sql; + my $command = "UPDATE $table SET " . join(',', map { $_ . ' = ?' } @keys ) . ' WHERE ' . join(' AND ', map { $_ . ' = ?' } @$fields{@identified_by} ); + if ( ! ( $_ = $local_dbh->prepare($command) and $_->execute( @sql{@keys,@$fields{@identified_by}} ) ) ) { + my $error = $local_dbh->errstr; + $command =~ s/\?/\%s/g; + $log->error('SQL failed: ('.sprintf($command, , map { defined $_ ? $_ : 'undef' } ( @sql{@keys, @$fields{@identified_by}}) ).'):' . $local_dbh->errstr); + $local_dbh->rollback(); + sql::end_transaction( $local_dbh, $ac ); + return $error; + } # end if + if ( $debug or DEBUG_ALL ) { + $command =~ s/\?/\%s/g; + $log->debug('SQL DEBUG: ('.sprintf($command, map { defined $_ ? $_ : 'undef' } ( @sql{@keys,@$fields{@identified_by}} ) ).'):' ); + } # end if + } # end if + } else { # not identified_by + @identified_by = ('id') if ! @identified_by; + my $need_serial = ! ( @identified_by == map { $$self{$_} ? $_ : () } @identified_by ); + + if ( $force_insert or $need_serial ) { + + if ( $need_serial ) { + if ( $serial ) { + @$self{@identified_by} = @sql{@$fields{@identified_by}} = $local_dbh->selectrow_array( q{SELECT nextval('} . $serial . q{')} ); + if ( $local_dbh->errstr() ) { + $log->error("Error getting next id. " . $local_dbh->errstr() ); + $log->error("SQL statement execution SELECT nextval('$serial') returned ".join(',',@$self{@identified_by})); + } elsif ( $debug or DEBUG_ALL ) { + $log->debug("SQL statement execution SELECT nextval('$serial') returned ".join(',',@$self{@identified_by})); + } # end if + } # end if + } # end if + my @keys = keys %sql; + my $command = "INSERT INTO $table (" . join(',', @keys ) . ') VALUES (' . join(',', map { '?' } @sql{@keys} ) . ')'; + if ( ! ( $_ = $local_dbh->prepare($command) and $_->execute( @sql{@keys} ) ) ) { + $command =~ s/\?/\%s/g; + my $error = $local_dbh->errstr; + $log->error('SQL failed: ('.sprintf($command, map { defined $_ ? $_ : 'undef' } ( @sql{@keys}) ).'):' . $error); + $local_dbh->rollback(); + sql::end_transaction( $local_dbh, $ac ); + return $error; + } # end if + if ( $debug or DEBUG_ALL ) { + $command =~ s/\?/\%s/g; + $log->debug('SQL DEBUG: ('.sprintf($command, map { defined $_ ? $_ : 'undef' } ( @sql{@keys} ) ).'):' ); + } # end if + } else { + delete $sql{created_on}; + my @keys = keys %sql; + @keys = sets::exclude( [ @$fields{@identified_by} ], \@keys ); + my $command = "UPDATE $table SET " . join(',', map { $_ . ' = ?' } @keys ) . ' WHERE ' . join(' AND ', map { $$fields{$_} .'= ?' } @identified_by ); + if ( ! ( $_ = $local_dbh->prepare($command) and $_->execute( @sql{@keys}, @sql{@$fields{@identified_by}} ) ) ) { + my $error = $local_dbh->errstr; + $command =~ s/\?/\%s/g; + $log->error('SQL failed: ('.sprintf($command, map { defined $_ ? $_ : 'undef' } ( @sql{@keys}, @sql{@$fields{@identified_by}} ) ).'):' . $error) if $log; + $local_dbh->rollback(); + sql::end_transaction( $local_dbh, $ac ); + return $error; + } # end if + if ( $debug or DEBUG_ALL ) { + $command =~ s/\?/\%s/g; + $log->debug('SQL DEBUG: ('.sprintf($command, map { defined $_ ? ( ref $_ eq 'ARRAY' ? join(',',@{$_}) : $_ ) : 'undef' } ( @sql{@keys}, @$self{@identified_by} ) ).'):' ); + } # end if + } # end if + } # end if + sql::end_transaction( $local_dbh, $ac ); + $self->load(); + #if ( $$fields{id} ) { + #if ( ! $ZoneMinder::Object::cache{$type}{$$self{id}} ) { + #$ZoneMinder::Object::cache{$type}{$$self{id}} = $self; + #} # end if + #delete $ZoneMinder::Object::cache{$config{db_name}}{$type}{$$self{id}}; + #} # end if +#$log->debug("after delete"); + #eval 'if ( %'.$type.'::find_cache ) { %'.$type.'::find_cache = (); }'; +#$log->debug("after clear cache"); + return ''; +} # end sub save + +sub set { + my ( $self, $params ) = @_; + my @set_fields = (); + + my $type = ref $self; + my %fields = eval ('%'.$type.'::fields'); + if ( ! %fields ) { + $log->warn('ZoneMinder::Object::set called on an object with no fields'); + } # end if + my %defaults = eval('%'.$type.'::defaults'); + if ( ref $params ne 'HASH' ) { + my ( $caller, undef, $line ) = caller; + $openprint::log->error("$type -> set called with non-hash params from $caller $line"); + } + + foreach my $field ( keys %fields ) { +$log->debug("field: $field, param: ".$$params{$field}) if $debug; + if ( exists $$params{$field} ) { +$openprint::log->debug("field: $field, $$self{$field} =? param: ".$$params{$field}) if $debug; + if ( ( ! defined $$self{$field} ) or ($$self{$field} ne $params->{$field}) ) { +# Only make changes to fields that have changed + if ( defined $fields{$field} ) { + $$self{$field} = $$params{$field} if defined $fields{$field}; + push @set_fields, $fields{$field}, $$params{$field}; #mark for sql updating + } # end if +$openprint::log->debug("Running $field with $$params{$field}") if $debug; + if ( my $func = $self->can( $field ) ) { + $func->( $self, $$params{$field} ); + } # end if + } # end if + } # end if + + if ( defined $fields{$field} ) { + if ( $$self{$field} ) { + $$self{$field} = transform( $type, $field, $$self{$field} ); + } # end if $$self{field} + } + } # end foreach field + + foreach my $field ( keys %defaults ) { + + if ( ( ! exists $$self{$field} ) or (!defined $$self{$field}) or ( $$self{$field} eq '' ) ) { + $log->debug("Setting default ($field) ($$self{$field}) ($defaults{$field}) ") if $debug; + if ( defined $defaults{$field} ) { + $log->debug("Default $field is defined: $defaults{$field}") if $debug; + if ( $defaults{$field} eq 'NOW()' ) { + $$self{$field} = 'NOW()'; + } else { + $$self{$field} = eval($defaults{$field}); + $log->error( "Eval error of object default $field default ($defaults{$field}) Reason: " . $@ ) if $@; + } # end if + } else { + $$self{$field} = $defaults{$field}; + } # end if +#$$self{$field} = ( defined $defaults{$field} ) ? eval($defaults{$field}) : $defaults{$field}; + $log->debug("Setting default for ($field) using ($defaults{$field}) to ($$self{$field}) ") if $debug; + } # end if + } # end foreach default + return @set_fields; +} # end sub set + +sub transform { + my $type = ref $_[0]; + $type = $_[0] if ! $type; + my $fields = eval '\%'.$type.'::fields'; + my $value = $_[2]; + + if ( defined $$fields{$_[1]} ) { + my @transforms = eval('@{$'.$type.'::transforms{$_[1]}}'); + $openprint::log->debug("Transforms for $_[1] before $_[2]: @transforms") if $debug; + if ( @transforms ) { + foreach my $transform ( @transforms ) { + if ( $transform =~ /^s\// or $transform =~ /^tr\// ) { + eval '$value =~ ' . $transform; + } elsif ( $transform =~ /^<(\d+)/ ) { + if ( $value > $1 ) { + $value = undef; + } # end if + } else { + $openprint::log->debug("evalling $value ".$transform . " Now value is $value" ); + eval '$value '.$transform; + $openprint::log->error("Eval error $@") if $@; + } + $openprint::log->debug("After $transform: $value") if $debug; + } # end foreach + } # end if + } else { + $openprint::log->error("Object::transform ($_[1]) not in fields for $type"); + } # end if + return $value; + +} # end sub transform 1; __END__ From 11fc755db25a7128f7398cc8d51b5454b1851c68 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Oct 2017 15:21:10 -0700 Subject: [PATCH 0013/2339] fix debug_all --- scripts/ZoneMinder/lib/ZoneMinder/Object.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Object.pm b/scripts/ZoneMinder/lib/ZoneMinder/Object.pm index af4d9fd21..a2d9fa021 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Object.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Object.pm @@ -48,6 +48,7 @@ use vars qw/ $AUTOLOAD $log $dbh/; *dbh = \$ZoneMinder::Database::dbh; my $debug = 1; +use constant DEBUG_ALL=>0; sub new { my ( $parent, $id, $data ) = @_; From 476ed4c9e08141f8414b9eeb5717dd35a8a7463d Mon Sep 17 00:00:00 2001 From: APHW2 MFGENG Date: Thu, 9 Nov 2017 06:16:41 -0800 Subject: [PATCH 0014/2339] add a quick test to load omx --- src/zm_videostore.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index e3c5dac67..869256e5a 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -150,7 +150,11 @@ VideoStore::VideoStore( Error("Could not allocate in frame"); return; } - video_out_codec = avcodec_find_encoder(AV_CODEC_ID_H264); + video_out_codec = avcodec_find_encoder_by_name("h264_omx"); + if ( ! video_out_codec ) { + Debug(1, "Didn't find omx"); + video_out_codec = avcodec_find_encoder(AV_CODEC_ID_H264); + } if (!video_out_codec) { Fatal("Could not find codec for H264"); } From 626af8d2fb22fd6db193484f0ad9369204445d70 Mon Sep 17 00:00:00 2001 From: APHW2 MFGENG Date: Fri, 10 Nov 2017 10:10:51 -0800 Subject: [PATCH 0015/2339] wip --- src/zm_analysis_thread.cpp | 4 +- src/zm_monitor.cpp | 2 +- src/zm_packet.cpp | 7 + src/zm_videostore.cpp | 400 ++++++++++++++++++------------------- 4 files changed, 206 insertions(+), 207 deletions(-) diff --git a/src/zm_analysis_thread.cpp b/src/zm_analysis_thread.cpp index b5acc0e17..bb23c5d3f 100644 --- a/src/zm_analysis_thread.cpp +++ b/src/zm_analysis_thread.cpp @@ -36,10 +36,10 @@ int AnalysisThread::run() { } if ( !monitor->Analyse() ) { -Debug(2, "Sleeping for %d", monitor->Active()?ZM_SAMPLE_RATE:ZM_SUSPENDED_RATE); +Debug(4, "Sleeping for %d", monitor->Active()?ZM_SAMPLE_RATE:ZM_SUSPENDED_RATE); usleep(monitor->Active()?ZM_SAMPLE_RATE:ZM_SUSPENDED_RATE); } else if ( analysis_rate ) { -Debug(2, "Sleeping for %d", analysis_rate); +Debug(4, "Sleeping for %d", analysis_rate); usleep(analysis_rate); } diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 323dcff29..fe95023a5 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1146,7 +1146,7 @@ bool Monitor::CheckSignal( const Image *image ) { bool Monitor::Analyse() { if ( shared_data->last_read_index == shared_data->last_write_index ) { // I wonder how often this happens. Maybe if this happens we should sleep or something? - Debug(3, " shared_data->last_read_index == shared_data->last_write_index " ); + //Debug(3, " shared_data->last_read_index == shared_data->last_write_index " ); return false; } diff --git a/src/zm_packet.cpp b/src/zm_packet.cpp index 14126fffc..5056cf1c3 100644 --- a/src/zm_packet.cpp +++ b/src/zm_packet.cpp @@ -29,6 +29,7 @@ ZMPacket::ZMPacket( ) { image = NULL; frame = NULL; av_init_packet( &packet ); + packet.size = 0; gettimeofday( ×tamp, NULL ); } @@ -61,6 +62,12 @@ ZMPacket::ZMPacket( AVPacket *p, AVFrame *f, Image *i ) { ZMPacket::~ZMPacket() { zm_av_packet_unref( &packet ); + if ( frame ) { + av_frame_free( &frame ); + } + if ( image ) { + delete image; + } } int ZMPacket::decode( AVCodecContext *ctx ) { diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 2daadcb6e..c0434db2e 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -128,16 +128,12 @@ VideoStore::VideoStore( Error("Could not allocate in frame"); return; } -#if 0 video_out_codec = avcodec_find_encoder_by_name("h264_omx"); if ( ! video_out_codec ) { Debug(1, "Didn't find omx"); video_out_codec = avcodec_find_encoder(AV_CODEC_ID_H264); } -#else - video_out_codec = avcodec_find_encoder(AV_CODEC_ID_H264); -#endif - if (!video_out_codec) { + if ( !video_out_codec ) { Fatal("Could not find codec for H264"); } Debug(2, "Have video out codec"); @@ -159,6 +155,9 @@ VideoStore::VideoStore( //video_out_ctx->framerate = (AVRational){0,1}; // Unknown framerate video_out_ctx->gop_size = 12; video_out_ctx->bit_rate = 4000000; + video_out_ctx->qmin = 10; + video_out_ctx->qmax = 51; + video_out_ctx->qcompress = 0.6; if (oc->oformat->flags & AVFMT_GLOBALHEADER) { #if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) @@ -179,14 +178,26 @@ VideoStore::VideoStore( Debug( 3, "Encoder Option %s=%s", e->key, e->value ); } } - ret = avcodec_open2(video_out_ctx, video_out_codec, &opts ); - if ( ret < 0 ) { - Error("Can't open video codec! %s, ", av_make_error_string(ret).c_str()); - ret = avcodec_open2(video_out_ctx, video_out_codec, NULL ); - if ( ret < 0 ) { - Error("Can't open video codec! %s, ", av_make_error_string(ret).c_str()); - return; - } + if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) { + Warning("Can't open video codec (%s)! %s, trying h264", + video_out_codec->name, + av_make_error_string(ret).c_str() + ); + video_out_codec = avcodec_find_encoder_by_name("h264"); + if ( ! video_out_codec ) { + Error("Can't find h264 encoder"); + video_out_codec = avcodec_find_encoder_by_name("libx264"); + if ( ! video_out_codec ) { + Error("Can't find libx264 encoder"); + return; + } + } + if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) { + Error("Can't open video codec (%s)! %s", + video_out_codec->name, + av_make_error_string(ret).c_str() ); + return; + } } AVDictionaryEntry *e = NULL; while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { @@ -194,7 +205,12 @@ VideoStore::VideoStore( } av_dict_free(&opts); - swscale.SetDefaults( video_in_ctx->pixfmt, video_out_ctx->pixfmt, video_out_ctx->width, video_out_ctx->height ); + swscale.SetDefaults( + video_in_ctx->pix_fmt, + video_out_ctx->pix_fmt, + video_out_ctx->width, + video_out_ctx->height + ); } // end if copying or trasncoding if ( !video_out_ctx->codec_tag ) { @@ -247,8 +263,6 @@ Debug(2, "%dx%d", video_out_stream->codec->width, video_out_stream->codec->heigh } else { Warning("Unsupported Orientation(%d)", orientation); } - - } converted_in_samples = NULL; @@ -272,7 +286,7 @@ Debug(2, "%dx%d", video_out_stream->codec->width, video_out_stream->codec->heigh audio_in_ctx = audio_in_stream->codec; #endif - if (audio_in_ctx->codec_id != AV_CODEC_ID_AAC) { + if ( audio_in_ctx->codec_id != AV_CODEC_ID_AAC ) { static char error_buffer[256]; avcodec_string(error_buffer, sizeof(error_buffer), audio_in_ctx, 0); @@ -520,39 +534,39 @@ Debug(3, "(%d, %d)", video_next_dts, video_next_pts ); // allocation/de-allocation constantly, or whether we can just re-use it. // Just do a file open/close/writeheader/etc. // What if we were only doing audio recording? - if (video_out_stream) { + if ( video_out_stream ) { avcodec_close(video_out_ctx); video_out_ctx = NULL; Debug(4, "Success freeing video_out_ctx"); } // Used by both audio and video conversions - if (in_frame) { + if ( in_frame ) { av_frame_free(&in_frame); in_frame = NULL; } - if (audio_out_stream) { + if ( audio_out_stream ) { avcodec_close(audio_out_ctx); audio_out_ctx = NULL; #ifdef HAVE_LIBAVRESAMPLE - if (resample_ctx) { + if ( resample_ctx ) { avresample_close(resample_ctx); avresample_free(&resample_ctx); } - if (out_frame) { + if ( out_frame ) { av_frame_free(&out_frame); out_frame = NULL; } - if (converted_in_samples) { + if ( converted_in_samples ) { av_free(converted_in_samples); converted_in_samples = NULL; } #endif } - // WHen will be not using a file ? - if (!(out_format->flags & AVFMT_NOFILE)) { + // When will be not using a file ? // Might someday use this for streaming + if ( !(out_format->flags & AVFMT_NOFILE) ) { /* Close the out file. */ - if (int rc = avio_close(oc->pb)) { + if ( int rc = avio_close(oc->pb) ) { Error("Error closing avio %s", av_err2str(rc)); } } else { @@ -565,17 +579,15 @@ Debug(3, "(%d, %d)", video_next_dts, video_next_pts ); bool VideoStore::setup_resampler() { #ifdef HAVE_LIBAVRESAMPLE - static char error_buffer[256]; - -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) // Newer ffmpeg wants to keep everything separate... so have to lookup our own // decoder, can't reuse the one from the camera. - AVCodec *audio_in_codec = - avcodec_find_decoder(audio_in_stream->codecpar->codec_id); + AVCodec *audio_in_codec = avcodec_find_decoder( +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + audio_in_stream->codecpar->codec_id #else - AVCodec *audio_in_codec = - avcodec_find_decoder(audio_in_ctx->codec_id); + audio_in_ctx->codec_id #endif + ); ret = avcodec_open2(audio_in_ctx, audio_in_codec, NULL); if (ret < 0) { Error("Can't open in codec!"); @@ -583,7 +595,7 @@ bool VideoStore::setup_resampler() { } audio_out_codec = avcodec_find_encoder(AV_CODEC_ID_AAC); - if (!audio_out_codec) { + if ( !audio_out_codec ) { Error("Could not find codec for AAC"); return false; } @@ -591,15 +603,12 @@ bool VideoStore::setup_resampler() { // audio_out_ctx = audio_out_stream->codec; audio_out_ctx = avcodec_alloc_context3(audio_out_codec); - - if (!audio_out_ctx) { + if ( !audio_out_ctx ) { Error("could not allocate codec ctx for AAC\n"); audio_out_stream = NULL; return false; } - Debug(2, "Have audio_out_ctx"); - /* put sample parameters */ audio_out_ctx->bit_rate = audio_in_ctx->bit_rate; audio_out_ctx->sample_rate = audio_in_ctx->sample_rate; @@ -608,17 +617,16 @@ bool VideoStore::setup_resampler() { audio_out_ctx->sample_fmt = audio_in_ctx->sample_fmt; //audio_out_ctx->refcounted_frames = 1; - if (audio_out_codec->supported_samplerates) { + if ( audio_out_codec->supported_samplerates ) { int found = 0; - for (unsigned int i = 0; audio_out_codec->supported_samplerates[i]; - i++) { - if (audio_out_ctx->sample_rate == + for ( int i=0; audio_out_codec->supported_samplerates[i]; i++) { + if ( audio_out_ctx->sample_rate == audio_out_codec->supported_samplerates[i]) { found = 1; break; } } - if (found) { + if ( found ) { Debug(3, "Sample rate is good"); } else { audio_out_ctx->sample_rate = @@ -629,34 +637,31 @@ bool VideoStore::setup_resampler() { } /* check that the encoder supports s16 pcm in */ - if (!check_sample_fmt(audio_out_codec, audio_out_ctx->sample_fmt)) { + if ( !check_sample_fmt(audio_out_codec, audio_out_ctx->sample_fmt) ) { Debug(3, "Encoder does not support sample format %s, setting to FLTP", av_get_sample_fmt_name(audio_out_ctx->sample_fmt)); audio_out_ctx->sample_fmt = AV_SAMPLE_FMT_FLTP; } - audio_out_ctx->time_base = - (AVRational){1, audio_out_ctx->sample_rate}; + audio_out_ctx->time_base = (AVRational){1, audio_out_ctx->sample_rate}; // Now copy them to the out stream audio_out_stream = avformat_new_stream(oc, audio_out_codec); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - ret = avcodec_parameters_from_context(audio_out_stream->codecpar, - audio_out_ctx); - if (ret < 0) { + if ( (ret = avcodec_parameters_from_context(audio_out_stream->codecpar, + audio_out_ctx)) < 0 ) { Error("Could not initialize stream parameteres"); return false; } #endif AVDictionary *opts = NULL; - av_dict_set(&opts, "strict", "experimental", 0); + av_dict_set(&opts, "strict", "experimental", 0); // Needed to allow AAC ret = avcodec_open2(audio_out_ctx, audio_out_codec, &opts); av_dict_free(&opts); - if (ret < 0) { - av_strerror(ret, error_buffer, sizeof(error_buffer)); - Fatal("could not open codec (%d) (%s)\n", ret, error_buffer); + if ( ret < 0 ) { + Fatal("could not open codec (%d) (%s)\n", ret, av_make_error_string(ret).c_str()); audio_out_codec = NULL; audio_out_ctx = NULL; audio_out_stream = NULL; @@ -672,14 +677,14 @@ bool VideoStore::setup_resampler() { /** Create a new frame to store the audio samples. */ if ( ! in_frame ) { - if (!(in_frame = zm_av_frame_alloc())) { - Error("Could not allocate in frame"); - return false; - } + if (!(in_frame = zm_av_frame_alloc())) { + Error("Could not allocate in frame"); + return false; + } } /** Create a new frame to store the audio samples. */ - if (!(out_frame = zm_av_frame_alloc())) { + if ( !(out_frame = zm_av_frame_alloc()) ) { Error("Could not allocate out frame"); av_frame_free(&in_frame); return false; @@ -687,13 +692,13 @@ bool VideoStore::setup_resampler() { // Setup the audio resampler resample_ctx = avresample_alloc_context(); - if (!resample_ctx) { + if ( !resample_ctx ) { Error("Could not allocate resample ctx\n"); return false; } // Some formats (i.e. WAV) do not produce the proper channel layout - if (audio_in_ctx->channel_layout == 0) { + if ( audio_in_ctx->channel_layout == 0 ) { uint64_t layout = av_get_channel_layout("mono"); av_opt_set_int(resample_ctx, "in_channel_layout", av_get_channel_layout("mono"), 0); @@ -703,12 +708,9 @@ bool VideoStore::setup_resampler() { audio_in_ctx->channel_layout, 0); } - av_opt_set_int(resample_ctx, "in_sample_fmt", - audio_in_ctx->sample_fmt, 0); - av_opt_set_int(resample_ctx, "in_sample_rate", - audio_in_ctx->sample_rate, 0); - av_opt_set_int(resample_ctx, "in_channels", audio_in_ctx->channels, - 0); + av_opt_set_int(resample_ctx, "in_sample_fmt", audio_in_ctx->sample_fmt, 0); + av_opt_set_int(resample_ctx, "in_sample_rate", audio_in_ctx->sample_rate, 0); + av_opt_set_int(resample_ctx, "in_channels", audio_in_ctx->channels, 0); // av_opt_set_int( resample_ctx, "out_channel_layout", // audio_out_ctx->channel_layout, 0); av_opt_set_int(resample_ctx, "out_channel_layout", @@ -720,39 +722,11 @@ bool VideoStore::setup_resampler() { av_opt_set_int(resample_ctx, "out_channels", audio_out_ctx->channels, 0); - ret = avresample_open(resample_ctx); - if (ret < 0) { + if ( (ret = avresample_open(resample_ctx)) < 0 ) { Error("Could not open resample ctx\n"); return false; } -#if 0 - /** - * Allocate as many pointers as there are audio channels. - * Each pointer will later point to the audio samples of the corresponding - * channels (although it may be NULL for interleaved formats). - */ - if (!( converted_in_samples = reinterpret_castcalloc( audio_out_ctx->channels, sizeof(*converted_in_samples))) ) { - Error("Could not allocate converted in sample pointers\n"); - return; - } - /** - * Allocate memory for the samples of all channels in one consecutive - * block for convenience. - */ - if ( (ret = av_samples_alloc( &converted_in_samples, NULL, - audio_out_ctx->channels, - audio_out_ctx->frame_size, - audio_out_ctx->sample_fmt, 0)) < 0 ) { - Error("Could not allocate converted in samples (error '%s')\n", - av_make_error_string(ret).c_str()); - - av_freep(converted_in_samples); - free(converted_in_samples); - return; - } -#endif - out_frame->nb_samples = audio_out_ctx->frame_size; out_frame->format = audio_out_ctx->sample_fmt; out_frame->channel_layout = audio_out_ctx->channel_layout; @@ -764,16 +738,16 @@ bool VideoStore::setup_resampler() { audio_out_ctx->sample_fmt, 0); converted_in_samples = (uint8_t *)av_malloc(audioSampleBuffer_size); - if (!converted_in_samples) { + if ( !converted_in_samples ) { Error("Could not allocate converted in sample pointers\n"); return false; } // Setup the data pointers in the AVFrame - if (avcodec_fill_audio_frame(out_frame, audio_out_ctx->channels, + if ( avcodec_fill_audio_frame(out_frame, audio_out_ctx->channels, audio_out_ctx->sample_fmt, (const uint8_t *)converted_in_samples, - audioSampleBuffer_size, 0) < 0) { + audioSampleBuffer_size, 0) < 0 ) { Error("Could not allocate converted in sample pointers\n"); return false; } @@ -793,13 +767,15 @@ void VideoStore::dumpPacket(AVPacket *pkt) { snprintf(b, sizeof(b), " pts: %" PRId64 ", dts: %" PRId64 ", data: %p, size: %d, sindex: %d, dflags: %04x, s-pos: %" PRId64 - ", c-duration: %d\n", + ", c-duration: %" PRId64 "\n", pkt->pts, pkt->dts, pkt->data, pkt->size, pkt->stream_index, - pkt->flags, pkt->pos, pkt->duration); + pkt->flags, + pkt->pos, + pkt->duration); Debug(1, "%s:%d:DEBUG: %s", __FILE__, __LINE__, b); } @@ -819,29 +795,89 @@ Debug(2, "writing a video packet"); int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { av_init_packet(&opkt); frame_count += 1; + + // if we have to transcode if ( video_out_ctx->codec_id != video_in_ctx->codec_id ) { - Debug(3, "Have encoding video frmae count (%d)", frame_count); + Debug(3, "Have encoding video frame count (%d)", frame_count); + + if ( ! zm_packet->frame ) { + if ( zm_packet->packet.size ) { + AVPacket *ipkt = &zm_packet->packet; #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - ret = avcodec_send_packet(video_in_ctx, ipkt); - if (ret < 0) { - Error("avcodec_send_packet fail %s", av_make_error_string(ret).c_str()); - return 0; - } + if ( ( ret = avcodec_send_packet(video_in_ctx, ipkt) ) < 0 ) { + Error("avcodec_send_packet fail %s", av_make_error_string(ret).c_str()); + return 0; + } + if ( ( ret = avcodec_receive_frame(video_in_ctx, in_frame) ) < 0 ) { + Error("avcodec_receive_frame fail %s", av_make_error_string(ret).c_str()); + return 0; + } +#else + if ((ret = avcodec_decode_video2(video_in_ctx, in_frame, + &data_present, zm_packet->packet )) < 0) { + Error("Could not decode frame (error '%s')\n", + av_make_error_string(ret).c_str()); + av_frame_free(&in_frame); + return 0; + } else { + Debug(3, "Decoded frame data_present(%d)", data_present); + } + if ( !data_present ) { + Debug(2, "Not ready to transcode a frame yet."); + return 0; + } +#endif + zm_packet->frame = in_frame; + } else if ( zm_packet->image ) { + AVFrame *frame = zm_packet->frame = zm_av_frame_alloc(); + if ( ! frame ) { + Error("Unable to allocate a frame"); + return 0; + } +#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) + int codec_imgsize = av_image_get_buffer_size( + video_out_ctx->pix_fmt, + video_out_ctx->width, + video_out_ctx->height, 1); +#else + int codec_imgsize = avpicture_get_size( + video_out_ctx->pix_fmt, + video_out_ctx->width, + video_out_ctx->height); +#endif - ret = avcodec_receive_frame(video_in_ctx, in_frame); - if ( ret < 0 ) { - Error("avcodec_receive_frame fail %s", av_make_error_string(ret).c_str()); - return 0; - } - if ((ret = avcodec_send_frame(video_out_ctx, in_frame)) < 0) { - Error("Could not send frame (error '%s')", - av_make_error_string(ret).c_str()); - zm_av_packet_unref(&opkt); - return 0; - } + uint8_t *buffer = (uint8_t *)av_malloc(codec_imgsize); + av_image_fill_arrays( + frame->data, + frame->linesize, + buffer, + video_out_ctx->pix_fmt, + video_out_ctx->width, + video_out_ctx->height, + 1); + frame->width = video_out_ctx->width; + frame->height = video_out_ctx->height; + frame->format = video_out_ctx->pix_fmt; + swscale.Convert(zm_packet->image, + buffer, + codec_imgsize, + (AVPixelFormat)zm_packet->image->AVPixFormat(), + video_out_ctx->pix_fmt, + video_out_ctx->width, + video_out_ctx->height + ); - if ((ret = avcodec_receive_packet(video_out_ctx, &opkt)) < 0) { + } // end if has packet or image + } // end if no frame + +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + if ( (ret = avcodec_send_frame(video_out_ctx, zm_packet->frame)) < 0 ) { + Error("Could not send frame (error '%s')", av_make_error_string(ret).c_str()); + zm_av_packet_unref(&opkt); // NOT SURE THIS IS NECCESSARY + return 0; + } + if ( (ret = avcodec_receive_packet(video_out_ctx, &opkt)) < 0 ) { if (AVERROR(EAGAIN) == ret) { // THe codec may need more samples than it has, perfectly valid Debug(3, "Could not recieve packet (error '%s')", @@ -851,62 +887,25 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { av_make_error_string(ret).c_str()); } zm_av_packet_unref(&opkt); - av_frame_unref(in_frame); return 0; } #else -// if not already decoded -if ( ! zm_packet->frame ) { - if ( zm_packet->packet ) { - /** - * Decode the video frame stored in the packet. - * The in video stream decoder is used to do this. - * If we are at the end of the file, pass an empty packet to the decoder - * to flush it. - */ - if ((ret = avcodec_decode_video2(video_in_ctx, in_frame, - &data_present, zm_packet->packet )) < 0) { - Error("Could not decode frame (error '%s')\n", - av_make_error_string(ret).c_str()); - dumpPacket(ipkt); - av_frame_free(&in_frame); - return 0; - } else { - Debug(3, "Decoded frame data_present(%d)", data_present); - } - if ( !data_present ) { - Debug(2, "Not ready to transcode a frame yet."); - return 0; - } - zm_packet->frame( in_frame ); - } else if ( zm_packet->image ) { - SwsContext *swsCtx = sws_getChangedContext( swsCtx, - video_in_ctx->width, video_in_ctx->height, video_in_ctx->pixfmt, - video_out_ctx->width, video_out_ctx->height, video_out_ctx->pixfmt, - SWS_LANCZOS | SWS_ACCURATE_RND, NUL, NULL, NULL ); - if ( sws_scale( swsCtx, zm_packet->image->buffer(), video_in_ctx->width, 0, - video_in_ctx->height, in_frame->data, in_frame->linesize ) < 0 ) { - ERror("Failed to scale image to frame"); - return 0; - } - - } -} - - if ((ret = avcodec_encode_video2(video_out_ctx, &opkt, zm_packet->frame, - &data_present)) < 0) { + if ( (ret = avcodec_encode_video2( + video_out_ctx, &opkt, zm_packet->frame, &data_present)) < 0) { Error("Could not encode frame (error '%s')", av_make_error_string(ret).c_str()); zm_av_packet_unref(&opkt); return 0; } - if (!data_present) { + if ( !data_present ) { Debug(2, "Not ready to out a frame yet."); zm_av_packet_unref(&opkt); return 0; } #endif + } else { + AVPacket *ipkt = &zm_packet->packet; Debug(3, "Doing passthrough, just copy packet"); // Just copy it because the codec is the same opkt.data = ipkt->data; @@ -914,35 +913,38 @@ if ( ! zm_packet->frame ) { opkt.flags = ipkt->flags; } - opkt.dts = video_next_dts; - opkt.pts = video_next_pts; + opkt.dts = opkt.pts = zm_packet->timestamp.tv_sec*1000000 + zm_packet->timestamp.tv_usec; +#if 0 + opkt.dts = video_next_dts; + opkt.pts = video_next_pts; - int duration; - if ( !video_last_pts ) { - duration = 0; - } else { - duration = av_rescale_q( - ipkt->pts - video_last_pts, - video_in_stream->time_base, - video_out_stream->time_base - ); - Debug(1, "duration calc: pts(%d) - last_pts(%d) = (%d)", ipkt->pts, - video_last_pts, duration); - if ( duration < 0 ) { - duration = ipkt->duration; - } + int duration; + if ( !video_last_pts ) { + duration = 0; + } else { + duration = av_rescale_q( + ipkt->pts - video_last_pts, + video_in_stream->time_base, + video_out_stream->time_base + ); + Debug(1, "duration calc: pts(%d) - last_pts(%d) = (%d)", ipkt->pts, + video_last_pts, duration); + if ( duration < 0 ) { + duration = ipkt->duration; } + } - Debug(1, "ipkt.dts(%d) ipkt.pts(%d)", ipkt->dts, ipkt->pts); - video_last_pts = ipkt->pts; - video_last_dts = ipkt->dts; - video_last_duration = duration; - opkt.duration = duration; + // our timebase is always /1000000 now, so we can use the timestamp as the pts/dts + video_last_pts = zm_packet->timestamp.tv_sec*1000000 + zm_packet->timestamp.tv_usec; + video_last_dts = video_last_pts; + video_last_duration = duration; + opkt.duration = duration; +#endif write_video_packet( opkt ); zm_av_packet_unref(&opkt); - return 0; + return 1; } // end int VideoStore::writeVideoFramePacket( AVPacket *ipkt ) void VideoStore::write_video_packet( AVPacket &opkt ) { @@ -989,7 +991,8 @@ void VideoStore::write_video_packet( AVPacket &opkt ) { __FILE__, __LINE__, av_make_error_string(ret).c_str(), (ret)); dumpPacket(&safepkt); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - zm_dump_codecpar(video_in_stream->codecpar); + if ( video_in_stream ) + zm_dump_codecpar(video_in_stream->codecpar); zm_dump_codecpar(video_out_stream->codecpar); #endif } else { @@ -1002,7 +1005,7 @@ void VideoStore::write_video_packet( AVPacket &opkt ) { int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { Debug(4, "writeAudioFrame"); - AVPacket *ipkt = zm_packet->packet; + AVPacket *ipkt = &zm_packet->packet; if ( !audio_out_stream ) { Debug(1, "Called writeAudioFramePacket when no audio_out_stream"); @@ -1015,14 +1018,11 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { #ifdef HAVE_LIBAVRESAMPLE #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - ret = avcodec_send_packet(audio_in_ctx, ipkt); - if ( ret < 0 ) { + if ( (ret = avcodec_send_packet(audio_in_ctx, ipkt)) < 0 ) { Error("avcodec_send_packet fail %s", av_make_error_string(ret).c_str()); return 0; } - - ret = avcodec_receive_frame(audio_in_ctx, in_frame); - if (ret < 0) { + if ( (ret = avcodec_receive_frame(audio_in_ctx, in_frame)) < 0 ) { Error("avcodec_receive_frame fail %s", av_make_error_string(ret).c_str()); return 0; } @@ -1038,15 +1038,15 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { * If we are at the end of the file, pass an empty packet to the decoder * to flush it. */ - if ((ret = avcodec_decode_audio4(audio_in_ctx, in_frame, - &data_present, ipkt)) < 0) { + if ( (ret = avcodec_decode_audio4(audio_in_ctx, in_frame, + &data_present, ipkt)) < 0 ) { Error("Could not decode frame (error '%s')\n", av_make_error_string(ret).c_str()); dumpPacket(ipkt); av_frame_free(&in_frame); return 0; } - if (!data_present) { + if ( !data_present ) { Debug(2, "Not ready to transcode a frame yet."); return 0; } @@ -1055,8 +1055,7 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { // Resample the in into the audioSampleBuffer until we proceed the whole // decoded data - if ((ret = - avresample_convert(resample_ctx, NULL, 0, 0, in_frame->data, + if ((ret = avresample_convert(resample_ctx, NULL, 0, 0, in_frame->data, 0, in_frame->nb_samples)) < 0) { Error("Could not resample frame (error '%s')\n", av_make_error_string(ret).c_str()); @@ -1188,7 +1187,7 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { } #endif // audio_last_dts = ipkt->dts; - if (opkt.dts > opkt.pts) { + if ( opkt.dts > opkt.pts ) { Debug(1, "opkt.dts(%d) must be <= opkt.pts(%d). Decompression must happen " "before presentation.", @@ -1196,14 +1195,7 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { opkt.dts = opkt.pts; } - // I wonder if we could just use duration instead of all the hoop jumping - // above? - // - if (out_frame) { - opkt.duration = out_frame->nb_samples; - } else { - opkt.duration = ipkt->duration; - } + opkt.duration = out_frame ? out_frame->nb_samples : ipkt->duration; // opkt.duration = av_rescale_q(ipkt->duration, audio_in_stream->time_base, // audio_out_stream->time_base); Debug(2, "opkt.pts (%d), opkt.dts(%d) opkt.duration = (%d)", opkt.pts, @@ -1226,7 +1218,7 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { Debug(2, "Success writing audio frame"); } zm_av_packet_unref(&opkt); - return 0; + return 1; } // end int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) int VideoStore::write_packets( zm_packetqueue &queue ) { From ce8350cbefca27057c9f8078a3a57e12f175757b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 10 Nov 2017 16:22:58 -0500 Subject: [PATCH 0016/2339] add :80 default --- utils/generate_apache_config.pl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utils/generate_apache_config.pl b/utils/generate_apache_config.pl index 7fac19bc3..9d9e94e10 100755 --- a/utils/generate_apache_config.pl +++ b/utils/generate_apache_config.pl @@ -37,6 +37,8 @@ if ( $$opts{protocol} eq 'https' ) { die "https requires a server_name"; } $VirtualHostPorts = ' *:443'; +} else { + $VirtualHostPorts = ' *:80'; } From 3dd8fe072d017973ee5577f99109bf429c9cc579 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 10 Nov 2017 18:59:58 -0500 Subject: [PATCH 0017/2339] add omx --- src/zm_videostore.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index e9e3f2377..a7ebf6e76 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -150,7 +150,13 @@ VideoStore::VideoStore( Error("Could not allocate in frame"); return; } - video_out_codec = avcodec_find_encoder(AV_CODEC_ID_H264); + video_out_codec = avcodec_find_encoder_by_name( "h264_omx" ); + if ( ! video_out_codec ) { + Debug(3, "omx not foudn"); + } + if ( ! video_out_codec ) + video_out_codec = avcodec_find_encoder(AV_CODEC_ID_H264); + if (!video_out_codec) { Fatal("Could not find codec for H264"); } From 3dafb5c2258a750b620e339e5cedbad09669c4cc Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 11 Nov 2017 09:25:13 -0500 Subject: [PATCH 0018/2339] don't delete image when destroying zmpacket --- src/zm_packet.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/zm_packet.cpp b/src/zm_packet.cpp index 5056cf1c3..900faff59 100644 --- a/src/zm_packet.cpp +++ b/src/zm_packet.cpp @@ -65,9 +65,8 @@ ZMPacket::~ZMPacket() { if ( frame ) { av_frame_free( &frame ); } - if ( image ) { - delete image; - } + // We assume the image was allocated elsewhere, so we just unref it. + image = NULL; } int ZMPacket::decode( AVCodecContext *ctx ) { From 0e7f475ce8fabf71d0863244486d451c16075070 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 12 Nov 2017 11:42:34 -0500 Subject: [PATCH 0019/2339] merge work from zma_to_thread, but not the zma_to_thread part --- src/zm_camera.h | 32 +- src/zm_curl_camera.cpp | 46 +- src/zm_curl_camera.h | 3 +- src/zm_ffmpeg_camera.cpp | 484 ++------------------ src/zm_ffmpeg_camera.h | 36 +- src/zm_file_camera.cpp | 64 +-- src/zm_file_camera.h | 22 +- src/zm_image.h | 20 +- src/zm_libvlc_camera.cpp | 85 ++-- src/zm_libvlc_camera.h | 9 +- src/zm_local_camera.cpp | 688 +++++++++++----------------- src/zm_local_camera.h | 18 +- src/zm_monitor.cpp | 315 +++++++------ src/zm_monitor.h | 13 +- src/zm_packet.cpp | 131 +++++- src/zm_packet.h | 15 +- src/zm_remote_camera.cpp | 1 + src/zm_remote_camera.h | 6 +- src/zm_remote_camera_http.cpp | 285 +++++------- src/zm_remote_camera_http.h | 21 +- src/zm_remote_camera_nvsocket.cpp | 204 +++------ src/zm_remote_camera_nvsocket.h | 6 +- src/zm_remote_camera_rtsp.cpp | 286 +++--------- src/zm_remote_camera_rtsp.h | 6 +- src/zm_videostore.cpp | 715 ++++++++++++++++-------------- src/zm_videostore.h | 20 +- 26 files changed, 1461 insertions(+), 2070 deletions(-) diff --git a/src/zm_camera.h b/src/zm_camera.h index 4d991d495..9d3447fe4 100644 --- a/src/zm_camera.h +++ b/src/zm_camera.h @@ -24,6 +24,7 @@ #include #include "zm_image.h" +#include "zm_packet.h" class Camera; @@ -33,8 +34,7 @@ class Camera; // Abstract base class for cameras. This is intended just to express // common attributes // -class Camera -{ +class Camera { protected: typedef enum { LOCAL_SRC, REMOTE_SRC, FILE_SRC, FFMPEG_SRC, LIBVLC_SRC, CURL_SRC } SourceType; @@ -54,8 +54,27 @@ protected: bool capture; bool record_audio; + int mVideoStreamId; + int mAudioStreamId; + AVCodecContext *mVideoCodecContext; + AVCodecContext *mAudioCodecContext; + AVStream *video_stream; + public: - 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 ); + 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(); unsigned int getId() const { return( monitor_id ); } @@ -86,9 +105,12 @@ public: virtual int PrimeCapture() { return( 0 ); } virtual int PreCapture()=0; - virtual int Capture( Image &image )=0; + virtual int Capture(ZMPacket &p)=0; virtual int PostCapture()=0; - virtual int CaptureAndRecord( Image &image, timeval recording, char* event_directory ) = 0; + AVStream *get_VideoStream() { return NULL; }; + AVStream *get_AudioStream() { return NULL; }; + int get_VideoStreamId() { return mVideoStreamId; }; + int get_AudioStreamId() { return mAudioStreamId; }; }; #endif // ZM_CAMERA_H diff --git a/src/zm_curl_camera.cpp b/src/zm_curl_camera.cpp index 3db890bf9..fe241677b 100644 --- a/src/zm_curl_camera.cpp +++ b/src/zm_curl_camera.cpp @@ -116,7 +116,7 @@ int cURLCamera::PreCapture() { return( 0 ); } -int cURLCamera::Capture( Image &image ) { +int cURLCamera::Capture( ZMPacket &zm_packet ) { bool frameComplete = false; /* MODE_STREAM specific variables */ @@ -128,10 +128,10 @@ int cURLCamera::Capture( Image &image ) { /* Grab the mutex to ensure exclusive access to the shared data */ lock(); - while (!frameComplete) { + while ( !frameComplete ) { /* If the work thread did a reset, reset our local variables */ - if(bReset) { + if ( bReset ) { SubHeadersParsingComplete = false; frame_content_length = 0; frame_content_type.clear(); @@ -139,25 +139,25 @@ int cURLCamera::Capture( Image &image ) { bReset = false; } - if(mode == MODE_UNSET) { + if ( mode == MODE_UNSET ) { /* Don't have a mode yet. Sleep while waiting for data */ nRet = pthread_cond_wait(&data_available_cond,&shareddata_mutex); - if(nRet != 0) { + if ( nRet != 0 ) { Error("Failed waiting for available data condition variable: %s",strerror(nRet)); - return -20; + return -1; } } - if(mode == MODE_STREAM) { + if ( mode == MODE_STREAM ) { /* Subheader parsing */ - while(!SubHeadersParsingComplete && !need_more_data) { + while( !SubHeadersParsingComplete && !need_more_data ) { size_t crlf_start, crlf_end, crlf_size; std::string subheader; /* Check if the buffer contains something */ - if(databuffer.empty()) { + if ( databuffer.empty() ) { /* Empty buffer, wait for data */ need_more_data = true; break; @@ -165,14 +165,14 @@ int cURLCamera::Capture( Image &image ) { /* Find crlf start */ crlf_start = memcspn(databuffer,"\r\n",databuffer.size()); - if(crlf_start == databuffer.size()) { + if ( crlf_start == databuffer.size() ) { /* Not found, wait for more data */ need_more_data = true; break; } /* See if we have enough data for determining crlf length */ - if(databuffer.size() < crlf_start+5) { + if ( databuffer.size() < crlf_start+5 ) { /* Need more data */ need_more_data = true; break; @@ -183,13 +183,13 @@ int cURLCamera::Capture( Image &image ) { crlf_size = (crlf_start + crlf_end) - crlf_start; /* Is this the end of a previous stream? (This is just before the boundary) */ - if(crlf_start == 0) { + if ( crlf_start == 0 ) { databuffer.consume(crlf_size); continue; } /* Check for invalid CRLF size */ - if(crlf_size > 4) { + if ( crlf_size > 4 ) { Error("Invalid CRLF length"); } @@ -209,7 +209,7 @@ int cURLCamera::Capture( Image &image ) { /* Find where the data in this header starts */ size_t subheader_data_start = subheader.rfind(' '); - if(subheader_data_start == std::string::npos) { + if ( subheader_data_start == std::string::npos ) { subheader_data_start = subheader.find(':'); } @@ -247,7 +247,7 @@ int cURLCamera::Capture( Image &image ) { need_more_data = true; } else { /* All good. decode the image */ - image.DecodeJpeg(databuffer.extract(frame_content_length), frame_content_length, colours, subpixelorder); + zm_packet.image->DecodeJpeg(databuffer.extract(frame_content_length), frame_content_length, colours, subpixelorder); frameComplete = true; } } @@ -257,7 +257,7 @@ int cURLCamera::Capture( Image &image ) { nRet = pthread_cond_wait(&data_available_cond,&shareddata_mutex); if(nRet != 0) { Error("Failed waiting for available data condition variable: %s",strerror(nRet)); - return -18; + return -1; } need_more_data = false; } @@ -267,7 +267,7 @@ int cURLCamera::Capture( Image &image ) { if (!single_offsets.empty()) { if( (single_offsets.front() > 0) && (databuffer.size() >= single_offsets.front()) ) { /* Extract frame */ - image.DecodeJpeg(databuffer.extract(single_offsets.front()), single_offsets.front(), colours, subpixelorder); + zm_packet.image->DecodeJpeg(databuffer.extract(single_offsets.front()), single_offsets.front(), colours, subpixelorder); single_offsets.pop_front(); frameComplete = true; } else { @@ -281,7 +281,7 @@ int cURLCamera::Capture( Image &image ) { nRet = pthread_cond_wait(&request_complete_cond,&shareddata_mutex); if(nRet != 0) { Error("Failed waiting for request complete condition variable: %s",strerror(nRet)); - return -19; + return -1; } } } else { @@ -295,9 +295,9 @@ int cURLCamera::Capture( Image &image ) { unlock(); if(!frameComplete) - return -1; + return 0; - return 0; + return 1; } int cURLCamera::PostCapture() { @@ -305,12 +305,6 @@ int cURLCamera::PostCapture() { 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) { lock(); diff --git a/src/zm_curl_camera.h b/src/zm_curl_camera.h index c9dc2e935..aff911bae 100644 --- a/src/zm_curl_camera.h +++ b/src/zm_curl_camera.h @@ -76,9 +76,8 @@ public: int PrimeCapture(); int PreCapture(); - int Capture( Image &image ); + int Capture( ZMPacket &p ); 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); diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index dfcdd1b05..af635e840 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -112,9 +112,6 @@ FfmpegCamera::FfmpegCamera( int p_id, const std::string &p_path, const std::stri mCanCapture = false; mOpenStart = 0; mReopenThread = 0; - videoStore = NULL; - video_last_pts = 0; - have_video_keyframe = false; #if HAVE_LIBSWSCALE mConvertContext = NULL; @@ -132,14 +129,10 @@ FfmpegCamera::FfmpegCamera( int p_id, const std::string &p_path, const std::stri } else { Panic("Unexpected colours: %d",colours); } - -} +} // end FFmpegCamera::FFmpegCamera FfmpegCamera::~FfmpegCamera() { - if ( videoStore ) { - delete videoStore; - } CloseFfmpeg(); if ( capture ) { @@ -184,140 +177,43 @@ int FfmpegCamera::PreCapture() { return( 0 ); } -int FfmpegCamera::Capture( Image &image ) { +int FfmpegCamera::Capture( ZMPacket &zm_packet ) { if ( ! mCanCapture ) { return -1; } + int ret; + // 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; } - int frameComplete = false; - while ( !frameComplete ) { - int ret; - int avResult = av_read_frame( mFormatContext, &packet ); - char errbuf[AV_ERROR_MAX_STRING_SIZE]; - if ( avResult < 0 ) { - 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 ); - ReopenFfmpeg(); - } - - Error( "Unable to read packet from stream %d: error %d \"%s\".", packet.stream_index, avResult, errbuf ); - return( -1 ); + ret = av_read_frame( mFormatContext, &packet ); + if ( ret < 0 ) { + 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.", av_make_error_string(ret).c_str() ); + ReopenFfmpeg(); } + Error( "Unable to read packet from stream %d: error %d \"%s\".", packet.stream_index, ret, av_make_error_string(ret).c_str() ); + return -1; + } + Debug( 5, "Got packet from stream %d dts (%d) pts(%d)", packet.stream_index, packet.pts, packet.dts ); - int keyframe = packet.flags & AV_PKT_FLAG_KEY; - if ( keyframe ) - have_video_keyframe = true; - - 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 ) && ( keyframe || have_video_keyframe ) ) { -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 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; - } - -#if HAVE_AVUTIL_HWCONTEXT_H - if ( hwaccel ) { - ret = avcodec_receive_frame( mVideoCodecContext, hwFrame ); - 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 = av_hwframe_transfer_data(mRawFrame, hwFrame, 0); - if (ret < 0) { - av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); - Error( "Unable to transfer frame at frame %d: %s, continuing", frameCount, errbuf ); - zm_av_packet_unref( &packet ); - continue; - } - } else { -#endif - 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; - } - -#if HAVE_AVUTIL_HWCONTEXT_H - } -#endif - - 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."); - 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 HAVE_LIBSWSCALE - 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"); -#endif // HAVE_LIBSWSCALE - - 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); + zm_packet.set_packet( &packet ); + zm_av_packet_unref( &packet ); + return 1; } // FfmpegCamera::Capture int FfmpegCamera::PostCapture() { @@ -333,7 +229,6 @@ int FfmpegCamera::OpenFfmpeg() { mOpenStart = time(NULL); mIsOpening = true; - have_video_keyframe = false; // Open the input, not necessarily a file #if !LIBAVFORMAT_VERSION_CHECK(53, 2, 0, 4, 0) @@ -458,7 +353,9 @@ int FfmpegCamera::OpenFfmpeg() { // 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. +#ifdef CODEC_FLAG2_FAST mVideoCodecContext->flags2 |= CODEC_FLAG2_FAST | CODEC_FLAG_LOW_DELAY; +#endif #if HAVE_AVUTIL_HWCONTEXT_H if ( mVideoCodecContext->codec_id == AV_CODEC_ID_H264 ) { @@ -495,7 +392,16 @@ int FfmpegCamera::OpenFfmpeg() { } } } - + } else { +#ifdef AV_CODEC_ID_H265 + if ( mVideoCodecContext->codec_id == AV_CODEC_ID_H265 ) { + Debug( 1, "Input stream appears to be h265. The stored event file may not be viewable in browser." ); + } else { +#endif + Error( "Input stream is not h264. The stored event file may not be viewable in browser." ); +#ifdef AV_CODEC_ID_H265 + } +#endif } // end if h264 #endif @@ -726,328 +632,4 @@ 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; - } - - - 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 keyframe = packet.flags & AV_PKT_FLAG_KEY; - - Debug( 4, "Got packet from stream %d packet pts (%u) dts(%u), key?(%d)", - packet.stream_index, packet.pts, packet.dts, - keyframe - ); - - //Video recording - if ( recording.tv_sec ) { - - uint32_t last_event_id = monitor->GetLastEventId() ; - - if ( last_event_id != monitor->GetVideoWriterEventId() ) { - Debug(2, "Have change of event. last_event(%d), our current (%d)", last_event_id, monitor->GetVideoWriterEventId() ); - - if ( videoStore ) { - 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; - have_video_keyframe = false; - - monitor->SetVideoWriterEventId( 0 ); - } // end if videoStore - } // end if end of recording - - if ( last_event_id and ! videoStore ) { - //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 - if ( ! videoStore->open() ) { - delete videoStore; - videoStore = NULL; - - } else { - strcpy(oldDirectory, event_file); - monitor->SetVideoWriterEventId( last_event_id ); - - // 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 ); - have_video_keyframe = true; - } 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; - have_video_keyframe = false; - monitor->SetVideoWriterEventId( 0 ); - } - - // 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 ( keyframe ) { - 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 ( keyframe || 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 ) { - // only do decode if we have had a keyframe, should save a few cycles. - if ( have_video_keyframe || keyframe ) { - - 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; - } - have_video_keyframe = true; - } - } // end if keyframe or have_video_keyframe - - Debug(4, "about to decode video" ); - -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 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; - } -#if HAVE_AVUTIL_HWCONTEXT_H - if ( hwaccel ) { - ret = avcodec_receive_frame( mVideoCodecContext, hwFrame ); - 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 = av_hwframe_transfer_data(mRawFrame, hwFrame, 0); - if (ret < 0) { - av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); - Error( "Unable to transfer frame at frame %d: %s, continuing", frameCount, errbuf ); - zm_av_packet_unref( &packet ); - continue; - } - } else { -#endif - 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; - } - -#if HAVE_AVUTIL_HWCONTEXT_H - } -#endif - - 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 ) { - if ( have_video_keyframe ) { - 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(3, "Not recording audio yet because we don't have a video keyframe yet"); - } - } 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 - } // end if is video or audio or something else - - // 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 diff --git a/src/zm_ffmpeg_camera.h b/src/zm_ffmpeg_camera.h index 3ed5d39aa..ef3b259ae 100644 --- a/src/zm_ffmpeg_camera.h +++ b/src/zm_ffmpeg_camera.h @@ -25,7 +25,6 @@ #include "zm_buffer.h" #include "zm_ffmpeg.h" #include "zm_videostore.h" -#include "zm_packetqueue.h" #if HAVE_AVUTIL_HWCONTEXT_H typedef struct DecodeContext { @@ -49,8 +48,6 @@ class FfmpegCamera : public Camera { AVFormatContext *mFormatContext; int mVideoStreamId; int mAudioStreamId; - AVCodecContext *mVideoCodecContext; - AVCodecContext *mAudioCodecContext; AVCodec *mVideoCodec; AVCodec *mAudioCodec; AVFrame *mRawFrame; @@ -85,11 +82,6 @@ class FfmpegCamera : public Camera { pthread_t mReopenThread; #endif // HAVE_LIBAVFORMAT - VideoStore *videoStore; - char oldDirectory[4096]; - unsigned int old_event_id; - zm_packetqueue packetqueue; - bool have_video_keyframe; #if HAVE_LIBSWSCALE struct SwsContext *mConvertContext; @@ -98,7 +90,20 @@ class FfmpegCamera : public Camera { int64_t startTime; 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( + 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(); const std::string &Path() const { return( mPath ); } @@ -110,9 +115,18 @@ class FfmpegCamera : public Camera { int PrimeCapture(); int PreCapture(); - int Capture( Image &image ); - int CaptureAndRecord( Image &image, timeval recording, char* event_directory ); + int Capture(ZMPacket &p); int PostCapture(); + AVStream *get_VideoStream() { + if ( mVideoStreamId != -1 ) + return mFormatContext->streams[mVideoStreamId]; + return NULL; + } + AVStream *get_AudioStream() { + if ( mAudioStreamId != -1 ) + return mFormatContext->streams[mAudioStreamId]; + return NULL; + } }; #endif // ZM_FFMPEG_CAMERA_H diff --git a/src/zm_file_camera.cpp b/src/zm_file_camera.cpp index b77628963..fc39ebade 100644 --- a/src/zm_file_camera.cpp +++ b/src/zm_file_camera.cpp @@ -34,58 +34,72 @@ #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, 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 ) +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 ) - { + if ( capture ) { Initialise(); } } -FileCamera::~FileCamera() -{ - if ( capture ) - { +FileCamera::~FileCamera() { + if ( capture ) { Terminate(); } } -void FileCamera::Initialise() -{ - if ( !path[0] ) - { +void FileCamera::Initialise() { + if ( !path[0] ) { Error( "No path specified for file image" ); exit( -1 ); } } -void FileCamera::Terminate() -{ +void FileCamera::Terminate() { } -int FileCamera::PreCapture() -{ +int FileCamera::PreCapture() { struct stat statbuf; - if ( stat( path, &statbuf ) < 0 ) - { + if ( stat( path, &statbuf ) < 0 ) { Error( "Can't stat %s: %s", path, strerror(errno) ); return( -1 ); } - while ( (time( 0 ) - statbuf.st_mtime) < 1 ) - { + // I think this is waiting for file change... + while ( (time( 0 ) - statbuf.st_mtime) < 1 ) { usleep( 100000 ); } return( 0 ); } -int FileCamera::Capture( Image &image ) -{ - return( image.ReadJpeg( path, colours, subpixelorder )?0:-1 ); +int FileCamera::Capture( ZMPacket &zm_packet ) { + return zm_packet.image->ReadJpeg( path, colours, subpixelorder ) ; } -int FileCamera::PostCapture() -{ - return( 0 ); +int FileCamera::PostCapture() { + return( 0 ); } diff --git a/src/zm_file_camera.h b/src/zm_file_camera.h index 6ad911755..6bf054de7 100644 --- a/src/zm_file_camera.h +++ b/src/zm_file_camera.h @@ -23,7 +23,7 @@ #include "zm_camera.h" #include "zm_buffer.h" #include "zm_regexp.h" -#include "zm_packetqueue.h" +#include "zm_packet.h" #include @@ -31,13 +31,24 @@ // Class representing 'file' cameras, i.e. those which are // accessed using a single file which contains the latest jpeg data // -class FileCamera : public Camera -{ +class FileCamera : public Camera { 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, bool p_record_audio ); + 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 ); } @@ -45,9 +56,8 @@ public: void Initialise(); void Terminate(); int PreCapture(); - int Capture( Image &image ); + int Capture( ZMPacket &p ); int PostCapture(); - int CaptureAndRecord( Image &image, timeval recording, char* event_directory ) {return(0);}; }; #endif // ZM_FILE_CAMERA_H diff --git a/src/zm_image.h b/src/zm_image.h index 934d2a682..43cae9b76 100644 --- a/src/zm_image.h +++ b/src/zm_image.h @@ -163,9 +163,23 @@ public: inline unsigned int Width() const { return( width ); } inline unsigned int Height() const { return( height ); } inline unsigned int Pixels() const { return( pixels ); } - inline unsigned int Colours() const { return( colours ); } - inline unsigned int SubpixelOrder() const { return( subpixelorder ); } - inline unsigned int Size() const { return( size ); } + inline unsigned int Colours() const { return( colours ); } + inline unsigned int SubpixelOrder() const { return( subpixelorder ); } + inline unsigned int Size() const { return( size ); } + + inline unsigned int AVPixFormat() { + if ( colours == ZM_COLOUR_RGB32 ) { + return AV_PIX_FMT_RGBA; + } else if ( colours == ZM_COLOUR_RGB24 ) { + return AV_PIX_FMT_RGB24; + } else if ( colours == ZM_COLOUR_GRAY8 ) { + return AV_PIX_FMT_GRAY8; + } else { + Error("Unknown colours (%d)",colours); + return AV_PIX_FMT_RGBA; + } + } + /* Internal buffer should not be modified from functions outside of this class */ inline const uint8_t* Buffer() const { return( buffer ); } diff --git a/src/zm_libvlc_camera.cpp b/src/zm_libvlc_camera.cpp index a4135d352..0593771d6 100644 --- a/src/zm_libvlc_camera.cpp +++ b/src/zm_libvlc_camera.cpp @@ -23,8 +23,7 @@ #if HAVE_LIBVLC // Do all the buffer checking work here to avoid unnecessary locking -void* LibvlcLockBuffer(void* opaque, void** planes) -{ +void* LibvlcLockBuffer(void* opaque, void** planes) { LibvlcPrivateData* data = (LibvlcPrivateData*)opaque; data->mutex.lock(); @@ -36,15 +35,12 @@ void* LibvlcLockBuffer(void* opaque, void** planes) return NULL; } -void LibvlcUnlockBuffer(void* opaque, void* picture, void *const *planes) -{ +void LibvlcUnlockBuffer(void* opaque, void* picture, void *const *planes) { LibvlcPrivateData* data = (LibvlcPrivateData*)opaque; bool newFrame = false; - for(uint32_t i = 0; i < data->bufferSize; i++) - { - if(data->buffer[i] != data->prevBuffer[i]) - { + for( uint32_t i = 0; i < data->bufferSize; i++ ) { + if ( data->buffer[i] != data->prevBuffer[i] ) { newFrame = true; break; } @@ -54,8 +50,7 @@ void LibvlcUnlockBuffer(void* opaque, void* picture, void *const *planes) time_t now; time(&now); // Return frames slightly faster than 1fps (if time() supports greater than one second resolution) - if(newFrame || difftime(now, data->prevTime) >= 0.8) - { + if ( newFrame || difftime(now, data->prevTime) >= 0.8 ) { data->prevTime = now; data->newImage.updateValueSignal(true); } @@ -90,58 +85,46 @@ LibvlcCamera::LibvlcCamera( int p_id, const std::string &p_path, const std::stri Panic("Unexpected colours: %d",colours); } - if ( capture ) - { + if ( capture ) { Initialise(); } } -LibvlcCamera::~LibvlcCamera() -{ - if ( capture ) - { +LibvlcCamera::~LibvlcCamera() { + if ( capture ) { Terminate(); } - if(mLibvlcMediaPlayer != NULL) - { + if ( mLibvlcMediaPlayer != NULL ) { libvlc_media_player_release(mLibvlcMediaPlayer); mLibvlcMediaPlayer = NULL; } - if(mLibvlcMedia != NULL) - { + if ( mLibvlcMedia != NULL ) { libvlc_media_release(mLibvlcMedia); mLibvlcMedia = NULL; } - if(mLibvlcInstance != NULL) - { + if ( mLibvlcInstance != NULL ) { libvlc_release(mLibvlcInstance); mLibvlcInstance = NULL; } - if (mOptArgV != NULL) - { + if ( mOptArgV != NULL ) { delete[] mOptArgV; } } -void LibvlcCamera::Initialise() -{ +void LibvlcCamera::Initialise() { } -void LibvlcCamera::Terminate() -{ +void LibvlcCamera::Terminate() { libvlc_media_player_stop(mLibvlcMediaPlayer); - if(mLibvlcData.buffer != NULL) - { + if(mLibvlcData.buffer != NULL) { zm_freealigned(mLibvlcData.buffer); } - if(mLibvlcData.prevBuffer != NULL) - { + if(mLibvlcData.prevBuffer != NULL) { zm_freealigned(mLibvlcData.prevBuffer); } } -int LibvlcCamera::PrimeCapture() -{ +int LibvlcCamera::PrimeCapture() { Info("Priming capture from %s", mPath.c_str()); StringVector opVect = split(Options(), ","); @@ -154,8 +137,7 @@ int LibvlcCamera::PrimeCapture() else if ( Method() == "rtpRtspHttp" ) opVect.push_back("--rtsp-http"); - if (opVect.size() > 0) - { + if ( opVect.size() > 0 ) { mOptArgV = new char*[opVect.size()]; Debug(2, "Number of Options: %d",opVect.size()); for (size_t i=0; i< opVect.size(); i++) { @@ -166,7 +148,7 @@ int LibvlcCamera::PrimeCapture() } mLibvlcInstance = libvlc_new (opVect.size(), (const char* const*)mOptArgV); - if(mLibvlcInstance == NULL) + if ( mLibvlcInstance == NULL ) Fatal("Unable to create libvlc instance due to: %s", libvlc_errmsg()); mLibvlcMedia = libvlc_media_new_location(mLibvlcInstance, mPath.c_str()); @@ -189,44 +171,27 @@ int LibvlcCamera::PrimeCapture() libvlc_media_player_play(mLibvlcMediaPlayer); - return(0); + return 0; } -int LibvlcCamera::PreCapture() -{ +int LibvlcCamera::PreCapture() { return(0); } // Should not return -1 as cancels capture. Always wait for image if available. -int LibvlcCamera::Capture( Image &image ) -{ +int LibvlcCamera::Capture( ZMPacket &zm_packet ) { while(!mLibvlcData.newImage.getValueImmediate()) mLibvlcData.newImage.getUpdatedValue(1); mLibvlcData.mutex.lock(); - image.Assign(width, height, colours, subpixelorder, mLibvlcData.buffer, width * height * mBpp); + zm_packet.image->Assign(width, height, colours, subpixelorder, mLibvlcData.buffer, width * height * mBpp); mLibvlcData.newImage.setValueImmediate(false); mLibvlcData.mutex.unlock(); - return (0); + return 1; } -// Should not return -1 as cancels capture. Always wait for image if available. -int LibvlcCamera::CaptureAndRecord(Image &image, timeval recording, char* event_directory) -{ - while(!mLibvlcData.newImage.getValueImmediate()) - mLibvlcData.newImage.getUpdatedValue(1); - - mLibvlcData.mutex.lock(); - image.Assign(width, height, colours, subpixelorder, mLibvlcData.buffer, width * height * mBpp); - mLibvlcData.newImage.setValueImmediate(false); - mLibvlcData.mutex.unlock(); - - return (0); -} - -int LibvlcCamera::PostCapture() -{ +int LibvlcCamera::PostCapture() { return(0); } diff --git a/src/zm_libvlc_camera.h b/src/zm_libvlc_camera.h index 4221bd0b7..aa2765dbf 100644 --- a/src/zm_libvlc_camera.h +++ b/src/zm_libvlc_camera.h @@ -31,8 +31,7 @@ #endif // Used by libvlc callbacks -struct LibvlcPrivateData -{ +struct LibvlcPrivateData { uint8_t* buffer; uint8_t* prevBuffer; time_t prevTime; @@ -41,8 +40,7 @@ struct LibvlcPrivateData ThreadData newImage; }; -class LibvlcCamera : public Camera -{ +class LibvlcCamera : public Camera { protected: std::string mPath; std::string mMethod; @@ -69,8 +67,7 @@ public: int PrimeCapture(); int PreCapture(); - int Capture( Image &image ); - int CaptureAndRecord( Image &image, timeval recording, char* event_directory ); + int Capture( ZMPacket &p ); int PostCapture(); }; diff --git a/src/zm_local_camera.cpp b/src/zm_local_camera.cpp index 52fb2c8f8..edeae3c8c 100644 --- a/src/zm_local_camera.cpp +++ b/src/zm_local_camera.cpp @@ -41,26 +41,21 @@ static unsigned int BigEndian; -static int vidioctl( int fd, int request, void *arg ) -{ +static int vidioctl( int fd, int request, void *arg ) { int result = -1; - do - { + do { result = ioctl( fd, request, arg ); } while ( result == -1 && errno == EINTR ); return( result ); } #if HAVE_LIBSWSCALE -static _AVPIXELFORMAT getFfPixFormatFromV4lPalette( int v4l_version, int palette ) -{ +static _AVPIXELFORMAT getFfPixFormatFromV4lPalette( int v4l_version, int palette ) { _AVPIXELFORMAT pixFormat = AV_PIX_FMT_NONE; #if ZM_HAS_V4L2 - if ( v4l_version == 2 ) - { - switch( palette ) - { + if ( v4l_version == 2 ) { + switch( palette ) { #if defined(V4L2_PIX_FMT_RGB444) && defined(AV_PIX_FMT_RGB444) case V4L2_PIX_FMT_RGB444 : pixFormat = AV_PIX_FMT_RGB444; @@ -183,10 +178,8 @@ static _AVPIXELFORMAT getFfPixFormatFromV4lPalette( int v4l_version, int palette } #endif // ZM_HAS_V4L2 #if ZM_HAS_V4L1 - if ( v4l_version == 1 ) - { - switch( palette ) - { + if ( v4l_version == 1 ) { + switch( palette ) { case VIDEO_PALETTE_RGB32 : if(BigEndian) pixFormat = AV_PIX_FMT_ARGB; @@ -264,7 +257,6 @@ static const uint32_t prefered_rgb24_formats[] = {V4L2_PIX_FMT_BGR24, V4L2_PIX_F static const uint32_t prefered_gray8_formats[] = {V4L2_PIX_FMT_GREY, V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_YUV422P, V4L2_PIX_FMT_YUV420}; #endif - int LocalCamera::camera_count = 0; int LocalCamera::channel_count = 0; int LocalCamera::channels[VIDEO_MAX_FRAME]; @@ -320,35 +312,29 @@ LocalCamera::LocalCamera( v4l_multi_buffer = p_v4l_multi_buffer; v4l_captures_per_frame = p_v4l_captures_per_frame; - if ( capture ) - { - if ( device_prime ) - { + if ( capture ) { + if ( device_prime ) { Debug( 2, "V4L support enabled, using V4L%d api", v4l_version ); } - if ( !last_camera || channel != last_camera->channel ) - { + if ( !last_camera || channel != last_camera->channel ) { // We are the first, or only, input that uses this channel channel_prime = true; channel_index = channel_count++; channels[channel_index] = channel; standards[channel_index] = standard; - } - else - { + } else { // We are the second, or subsequent, input using this channel channel_prime = false; } - } /* The V4L1 API doesn't care about endianness, we need to check the endianness of the machine */ uint32_t checkval = 0xAABBCCDD; - if(*(unsigned char*)&checkval == 0xDD) { + if ( *(unsigned char*)&checkval == 0xDD ) { BigEndian = 0; Debug(2,"little-endian processor detected"); - } else if(*(unsigned char*)&checkval == 0xAA) { + } else if( *(unsigned char*)&checkval == 0xAA ) { BigEndian = 1; Debug(2,"Big-endian processor detected"); } else { @@ -467,27 +453,27 @@ LocalCamera::LocalCamera( conversion_type = 2; #endif /* Our YUYV->Grayscale conversion is a lot faster than swscale's */ - if(colours == ZM_COLOUR_GRAY8 && palette == V4L2_PIX_FMT_YUYV) { + if ( colours == ZM_COLOUR_GRAY8 && palette == V4L2_PIX_FMT_YUYV ) { conversion_type = 2; } /* JPEG */ - if(palette == V4L2_PIX_FMT_JPEG || palette == V4L2_PIX_FMT_MJPEG) { + if ( palette == V4L2_PIX_FMT_JPEG || palette == V4L2_PIX_FMT_MJPEG ) { Debug(2,"Using JPEG image decoding"); conversion_type = 3; } - if(conversion_type == 2) { + if ( conversion_type == 2 ) { Debug(2,"Using ZM for image conversion"); - if(palette == V4L2_PIX_FMT_RGB32 && colours == ZM_COLOUR_GRAY8) { + if ( palette == V4L2_PIX_FMT_RGB32 && colours == ZM_COLOUR_GRAY8 ) { conversion_fptr = &std_convert_argb_gray8; subpixelorder = ZM_SUBPIX_ORDER_NONE; - } else if(palette == V4L2_PIX_FMT_BGR32 && colours == ZM_COLOUR_GRAY8) { + } else if ( palette == V4L2_PIX_FMT_BGR32 && colours == ZM_COLOUR_GRAY8 ) { conversion_fptr = &std_convert_bgra_gray8; subpixelorder = ZM_SUBPIX_ORDER_NONE; - } else if(palette == V4L2_PIX_FMT_YUYV && colours == ZM_COLOUR_GRAY8) { + } else if ( palette == V4L2_PIX_FMT_YUYV && colours == ZM_COLOUR_GRAY8 ) { /* Fast YUYV->Grayscale conversion by extracting the Y channel */ - if(config.cpu_extensions && sseversion >= 35) { + if ( config.cpu_extensions && sseversion >= 35 ) { conversion_fptr = &ssse3_convert_yuyv_gray8; Debug(2,"Using SSSE3 YUYV->grayscale fast conversion"); } else { @@ -495,22 +481,22 @@ LocalCamera::LocalCamera( Debug(2,"Using standard YUYV->grayscale fast conversion"); } subpixelorder = ZM_SUBPIX_ORDER_NONE; - } else if(palette == V4L2_PIX_FMT_YUYV && colours == ZM_COLOUR_RGB24) { + } else if ( palette == V4L2_PIX_FMT_YUYV && colours == ZM_COLOUR_RGB24 ) { conversion_fptr = &zm_convert_yuyv_rgb; subpixelorder = ZM_SUBPIX_ORDER_RGB; - } else if(palette == V4L2_PIX_FMT_YUYV && colours == ZM_COLOUR_RGB32) { + } else if ( palette == V4L2_PIX_FMT_YUYV && colours == ZM_COLOUR_RGB32 ) { conversion_fptr = &zm_convert_yuyv_rgba; subpixelorder = ZM_SUBPIX_ORDER_RGBA; - } else if(palette == V4L2_PIX_FMT_RGB555 && colours == ZM_COLOUR_RGB24) { + } else if ( palette == V4L2_PIX_FMT_RGB555 && colours == ZM_COLOUR_RGB24 ) { conversion_fptr = &zm_convert_rgb555_rgb; subpixelorder = ZM_SUBPIX_ORDER_RGB; - } else if(palette == V4L2_PIX_FMT_RGB555 && colours == ZM_COLOUR_RGB32) { + } else if ( palette == V4L2_PIX_FMT_RGB555 && colours == ZM_COLOUR_RGB32 ) { conversion_fptr = &zm_convert_rgb555_rgba; subpixelorder = ZM_SUBPIX_ORDER_RGBA; - } else if(palette == V4L2_PIX_FMT_RGB565 && colours == ZM_COLOUR_RGB24) { + } else if ( palette == V4L2_PIX_FMT_RGB565 && colours == ZM_COLOUR_RGB24 ) { conversion_fptr = &zm_convert_rgb565_rgb; subpixelorder = ZM_SUBPIX_ORDER_RGB; - } else if(palette == V4L2_PIX_FMT_RGB565 && colours == ZM_COLOUR_RGB32) { + } else if ( palette == V4L2_PIX_FMT_RGB565 && colours == ZM_COLOUR_RGB32 ) { conversion_fptr = &zm_convert_rgb565_rgba; subpixelorder = ZM_SUBPIX_ORDER_RGBA; } else { @@ -527,79 +513,80 @@ LocalCamera::LocalCamera( /* Try to find a match for the selected palette and target colourspace */ /* RGB32 palette and 32bit target colourspace */ - if(palette == VIDEO_PALETTE_RGB32 && colours == ZM_COLOUR_RGB32) { + if ( palette == VIDEO_PALETTE_RGB32 && colours == ZM_COLOUR_RGB32 ) { conversion_type = 0; - if(BigEndian) { + if ( BigEndian ) { subpixelorder = ZM_SUBPIX_ORDER_ARGB; } else { subpixelorder = ZM_SUBPIX_ORDER_BGRA; } /* RGB24 palette and 24bit target colourspace */ - } else if(palette == VIDEO_PALETTE_RGB24 && colours == ZM_COLOUR_RGB24) { + } else if ( palette == VIDEO_PALETTE_RGB24 && colours == ZM_COLOUR_RGB24 ) { conversion_type = 0; - if(BigEndian) { + if ( BigEndian ) { subpixelorder = ZM_SUBPIX_ORDER_RGB; } else { subpixelorder = ZM_SUBPIX_ORDER_BGR; } /* Grayscale palette and grayscale target colourspace */ - } else if(palette == VIDEO_PALETTE_GREY && colours == ZM_COLOUR_GRAY8) { + } else if ( palette == VIDEO_PALETTE_GREY && colours == ZM_COLOUR_GRAY8 ) { conversion_type = 0; subpixelorder = ZM_SUBPIX_ORDER_NONE; /* Unable to find a solution for the selected palette and target colourspace. Conversion required. Notify the user of performance penalty */ } else { - if( capture ) + if ( capture ) Info("No direct match for the selected palette and target colorspace. Format conversion is required, performance penalty expected"); #if HAVE_LIBSWSCALE /* Try using swscale for the conversion */ conversion_type = 1; Debug(2,"Using swscale for image conversion"); - if(colours == ZM_COLOUR_RGB32) { + if ( colours == ZM_COLOUR_RGB32 ) { subpixelorder = ZM_SUBPIX_ORDER_RGBA; imagePixFormat = AV_PIX_FMT_RGBA; - } else if(colours == ZM_COLOUR_RGB24) { + } else if ( colours == ZM_COLOUR_RGB24 ) { subpixelorder = ZM_SUBPIX_ORDER_RGB; imagePixFormat = AV_PIX_FMT_RGB24; - } else if(colours == ZM_COLOUR_GRAY8) { + } else if ( colours == ZM_COLOUR_GRAY8 ) { subpixelorder = ZM_SUBPIX_ORDER_NONE; imagePixFormat = AV_PIX_FMT_GRAY8; } else { Panic("Unexpected colours: %u",colours); } - if( capture ) { - if(!sws_isSupportedInput(capturePixFormat)) { + if ( capture ) { + if ( !sws_isSupportedInput(capturePixFormat) ) { Error("swscale does not support the used capture format"); conversion_type = 2; /* Try ZM format conversions */ } - if(!sws_isSupportedOutput(imagePixFormat)) { + if ( !sws_isSupportedOutput(imagePixFormat) ) { Error("swscale does not support the target format"); conversion_type = 2; /* Try ZM format conversions */ } } + + /* Our YUYV->Grayscale conversion is a lot faster than swscale's */ + if ( colours == ZM_COLOUR_GRAY8 && (palette == VIDEO_PALETTE_YUYV || palette == VIDEO_PALETTE_YUV422) ) { + conversion_type = 2; + } #else /* Don't have swscale, see what we can do */ conversion_type = 2; #endif - /* Our YUYV->Grayscale conversion is a lot faster than swscale's */ - if(colours == ZM_COLOUR_GRAY8 && (palette == VIDEO_PALETTE_YUYV || palette == VIDEO_PALETTE_YUV422)) { - conversion_type = 2; - } - if(conversion_type == 2) { + if ( conversion_type == 2 ) { Debug(2,"Using ZM for image conversion"); - if(palette == VIDEO_PALETTE_RGB32 && colours == ZM_COLOUR_GRAY8) { - if(BigEndian) { + if ( palette == VIDEO_PALETTE_RGB32 && colours == ZM_COLOUR_GRAY8 ) { + if ( BigEndian ) { conversion_fptr = &std_convert_argb_gray8; subpixelorder = ZM_SUBPIX_ORDER_NONE; } else { conversion_fptr = &std_convert_bgra_gray8; subpixelorder = ZM_SUBPIX_ORDER_NONE; } - } else if((palette == VIDEO_PALETTE_YUYV || palette == VIDEO_PALETTE_YUV422) && colours == ZM_COLOUR_GRAY8) { + } else if ( (palette == VIDEO_PALETTE_YUYV || palette == VIDEO_PALETTE_YUV422) && colours == ZM_COLOUR_GRAY8 ) { /* Fast YUYV->Grayscale conversion by extracting the Y channel */ - if(config.cpu_extensions && sseversion >= 35) { + if ( config.cpu_extensions && sseversion >= 35 ) { conversion_fptr = &ssse3_convert_yuyv_gray8; Debug(2,"Using SSSE3 YUYV->grayscale fast conversion"); } else { @@ -607,28 +594,28 @@ LocalCamera::LocalCamera( Debug(2,"Using standard YUYV->grayscale fast conversion"); } subpixelorder = ZM_SUBPIX_ORDER_NONE; - } else if((palette == VIDEO_PALETTE_YUYV || palette == VIDEO_PALETTE_YUV422) && colours == ZM_COLOUR_RGB24) { + } else if ( (palette == VIDEO_PALETTE_YUYV || palette == VIDEO_PALETTE_YUV422) && colours == ZM_COLOUR_RGB24 ) { conversion_fptr = &zm_convert_yuyv_rgb; subpixelorder = ZM_SUBPIX_ORDER_RGB; - } else if((palette == VIDEO_PALETTE_YUYV || palette == VIDEO_PALETTE_YUV422) && colours == ZM_COLOUR_RGB32) { + } else if ( (palette == VIDEO_PALETTE_YUYV || palette == VIDEO_PALETTE_YUV422) && colours == ZM_COLOUR_RGB32 ) { conversion_fptr = &zm_convert_yuyv_rgba; subpixelorder = ZM_SUBPIX_ORDER_RGBA; - } else if(palette == VIDEO_PALETTE_RGB555 && colours == ZM_COLOUR_RGB24) { + } else if ( palette == VIDEO_PALETTE_RGB555 && colours == ZM_COLOUR_RGB24) { conversion_fptr = &zm_convert_rgb555_rgb; subpixelorder = ZM_SUBPIX_ORDER_RGB; - } else if(palette == VIDEO_PALETTE_RGB555 && colours == ZM_COLOUR_RGB32) { + } else if ( palette == VIDEO_PALETTE_RGB555 && colours == ZM_COLOUR_RGB32) { conversion_fptr = &zm_convert_rgb555_rgba; subpixelorder = ZM_SUBPIX_ORDER_RGBA; - } else if(palette == VIDEO_PALETTE_RGB565 && colours == ZM_COLOUR_RGB24) { + } else if ( palette == VIDEO_PALETTE_RGB565 && colours == ZM_COLOUR_RGB24) { conversion_fptr = &zm_convert_rgb565_rgb; subpixelorder = ZM_SUBPIX_ORDER_RGB; - } else if(palette == VIDEO_PALETTE_RGB565 && colours == ZM_COLOUR_RGB32) { + } else if ( palette == VIDEO_PALETTE_RGB565 && colours == ZM_COLOUR_RGB32) { conversion_fptr = &zm_convert_rgb565_rgba; subpixelorder = ZM_SUBPIX_ORDER_RGBA; } else { Fatal("Unable to find a suitable format conversion for the selected palette and target colorspace."); } - } + } // end if conversion_type == 2 } } #endif // ZM_HAS_V4L1 @@ -638,7 +625,7 @@ LocalCamera::LocalCamera( #if HAVE_LIBSWSCALE /* Initialize swscale stuff */ - if(capture && conversion_type == 1) { + if ( capture && conversion_type == 1 ) { #if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) tmpPicture = av_frame_alloc(); #else @@ -652,8 +639,8 @@ LocalCamera::LocalCamera( #else int pSize = avpicture_get_size( imagePixFormat, width, height ); #endif - if( (unsigned int)pSize != imagesize) { - Fatal("Image size mismatch. Required: %d Available: %u",pSize,imagesize); + if ( (unsigned int)pSize != imagesize ) { + Fatal("Image size mismatch. Required: %d Available: %u", pSize, imagesize); } imgConversionContext = sws_getContext(width, height, capturePixFormat, width, height, imagePixFormat, SWS_BICUBIC, NULL, NULL, NULL ); @@ -661,29 +648,26 @@ LocalCamera::LocalCamera( if ( !imgConversionContext ) { Fatal( "Unable to initialise image scaling context" ); } - - } + } // end if capture and conversion_tye == swscale #endif -} +} // end LocalCamera::LocalCamera -LocalCamera::~LocalCamera() -{ +LocalCamera::~LocalCamera() { if ( device_prime && capture ) Terminate(); #if HAVE_LIBSWSCALE /* Clean up swscale stuff */ - if(capture && conversion_type == 1) { + if ( capture && conversion_type == 1 ) { sws_freeContext(imgConversionContext); imgConversionContext = NULL; av_frame_free( &tmpPicture ); } #endif -} +} // end LocalCamera::~LocalCamera -void LocalCamera::Initialise() -{ +void LocalCamera::Initialise() { #if HAVE_LIBSWSCALE if ( logDebugging() ) av_log_set_level( AV_LOG_DEBUG ); @@ -706,8 +690,7 @@ void LocalCamera::Initialise() #if ZM_HAS_V4L2 Debug( 2, "V4L2 support enabled, using V4L%d api", v4l_version ); - if ( v4l_version == 2 ) - { + if ( v4l_version == 2 ) { struct v4l2_capability vid_cap; Debug( 3, "Checking video device capabilities" ); @@ -743,12 +726,10 @@ void LocalCamera::Initialise() v4l2_data.fmt.fmt.pix.height = height; v4l2_data.fmt.fmt.pix.pixelformat = palette; - if ( (extras & 0xff) != 0 ) - { + if ( (extras & 0xff) != 0 ) { v4l2_data.fmt.fmt.pix.field = (v4l2_field)(extras & 0xff); - if ( vidioctl( vid_fd, VIDIOC_S_FMT, &v4l2_data.fmt ) < 0 ) - { + if ( vidioctl( vid_fd, VIDIOC_S_FMT, &v4l2_data.fmt ) < 0 ) { Warning( "Failed to set V4L2 field to %d, falling back to auto", (extras & 0xff) ); v4l2_data.fmt.fmt.pix.field = V4L2_FIELD_ANY; if ( vidioctl( vid_fd, VIDIOC_S_FMT, &v4l2_data.fmt ) < 0 ) { @@ -782,16 +763,16 @@ void LocalCamera::Initialise() v4l2_data.fmt.fmt.pix.sizeimage = min; v4l2_jpegcompression jpeg_comp; - if(palette == V4L2_PIX_FMT_JPEG || palette == V4L2_PIX_FMT_MJPEG) { - if( vidioctl( vid_fd, VIDIOC_G_JPEGCOMP, &jpeg_comp ) < 0 ) { - if(errno == EINVAL) { + if ( palette == V4L2_PIX_FMT_JPEG || palette == V4L2_PIX_FMT_MJPEG ) { + if ( vidioctl( vid_fd, VIDIOC_G_JPEGCOMP, &jpeg_comp ) < 0 ) { + if ( errno == EINVAL ) { Debug(2, "JPEG compression options are not available"); } else { Warning("Failed to get JPEG compression options: %s", strerror(errno) ); } } else { /* Set flags and quality. MJPEG should not have the huffman tables defined */ - if(palette == V4L2_PIX_FMT_MJPEG) { + if ( palette == V4L2_PIX_FMT_MJPEG ) { jpeg_comp.jpeg_markers |= V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI; } else { jpeg_comp.jpeg_markers |= V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI | V4L2_JPEG_MARKER_DHT; @@ -799,14 +780,14 @@ void LocalCamera::Initialise() jpeg_comp.quality = 85; /* Update the JPEG options */ - if( vidioctl( vid_fd, VIDIOC_S_JPEGCOMP, &jpeg_comp ) < 0 ) { + if ( vidioctl( vid_fd, VIDIOC_S_JPEGCOMP, &jpeg_comp ) < 0 ) { Warning("Failed to set JPEG compression options: %s", strerror(errno) ); } else { - if(vidioctl( vid_fd, VIDIOC_G_JPEGCOMP, &jpeg_comp ) < 0) { + if ( vidioctl( vid_fd, VIDIOC_G_JPEGCOMP, &jpeg_comp ) < 0 ) { Debug(3,"Failed to get updated JPEG compression options: %s", strerror(errno) ); } else { - Debug(4, "JPEG quality: %d",jpeg_comp.quality); - Debug(4, "JPEG markers: %#x",jpeg_comp.jpeg_markers); + Debug(4, "JPEG quality: %d, markers: %#x", + jpeg_comp.quality, jpeg_comp.jpeg_markers); } } } @@ -830,14 +811,10 @@ void LocalCamera::Initialise() v4l2_data.reqbufs.type = v4l2_data.fmt.type; v4l2_data.reqbufs.memory = V4L2_MEMORY_MMAP; - if ( vidioctl( vid_fd, VIDIOC_REQBUFS, &v4l2_data.reqbufs ) < 0 ) - { - if ( errno == EINVAL ) - { + if ( vidioctl( vid_fd, VIDIOC_REQBUFS, &v4l2_data.reqbufs ) < 0 ) { + if ( errno == EINVAL ) { Fatal( "Unable to initialise memory mapping, unsupported in device" ); - } - else - { + } else { Fatal( "Unable to initialise memory mapping: %s", strerror(errno) ); } } @@ -851,8 +828,7 @@ void LocalCamera::Initialise() #if HAVE_LIBSWSCALE capturePictures = new AVFrame *[v4l2_data.reqbufs.count]; #endif // HAVE_LIBSWSCALE - for ( unsigned int i = 0; i < v4l2_data.reqbufs.count; i++ ) - { + for ( unsigned int i = 0; i < v4l2_data.reqbufs.count; i++ ) { struct v4l2_buffer vid_buf; memset( &vid_buf, 0, sizeof(vid_buf) ); @@ -897,8 +873,7 @@ void LocalCamera::Initialise() Debug( 3, "Configuring video source" ); - if ( vidioctl( vid_fd, VIDIOC_S_INPUT, &channel ) < 0 ) - { + if ( vidioctl( vid_fd, VIDIOC_S_INPUT, &channel ) < 0 ) { Fatal( "Failed to set camera source %d: %s", channel, strerror(errno) ); } @@ -907,19 +882,16 @@ void LocalCamera::Initialise() memset( &input, 0, sizeof(input) ); - if ( vidioctl( vid_fd, VIDIOC_ENUMINPUT, &input ) < 0 ) - { + if ( vidioctl( vid_fd, VIDIOC_ENUMINPUT, &input ) < 0 ) { Fatal( "Failed to enumerate input %d: %s", channel, strerror(errno) ); } - if ( (input.std != V4L2_STD_UNKNOWN) && ((input.std & standard) == V4L2_STD_UNKNOWN) ) - { + if ( (input.std != V4L2_STD_UNKNOWN) && ((input.std & standard) == V4L2_STD_UNKNOWN) ) { Fatal( "Device does not support video standard %d", standard ); } stdId = standard; - if ( (input.std != V4L2_STD_UNKNOWN) && vidioctl( vid_fd, VIDIOC_S_STD, &stdId ) < 0 ) - { + if ( (input.std != V4L2_STD_UNKNOWN) && vidioctl( vid_fd, VIDIOC_S_STD, &stdId ) < 0 ) { Fatal( "Failed to set video standard %d: %s", standard, strerror(errno) ); } @@ -930,8 +902,7 @@ void LocalCamera::Initialise() } #endif // ZM_HAS_V4L2 #if ZM_HAS_V4L1 - if ( v4l_version == 1 ) - { + if ( v4l_version == 1 ) { Debug( 3, "Configuring picture attributes" ); struct video_picture vid_pic; @@ -946,8 +917,7 @@ void LocalCamera::Initialise() Debug( 4, "Old Cl:%d", vid_pic.colour ); Debug( 4, "Old Cn:%d", vid_pic.contrast ); - switch (vid_pic.palette = palette) - { + switch (vid_pic.palette = palette) { case VIDEO_PALETTE_RGB32 : { vid_pic.depth = 32; @@ -980,8 +950,7 @@ void LocalCamera::Initialise() if ( colour >= 0 ) vid_pic.colour = colour; if ( contrast >= 0 ) vid_pic.contrast = contrast; - if ( ioctl( vid_fd, VIDIOCSPICT, &vid_pic ) < 0 ) - { + if ( ioctl( vid_fd, VIDIOCSPICT, &vid_pic ) < 0 ) { Error( "Failed to set picture attributes: %s", strerror(errno) ); if ( config.strict_video_config ) exit(-1); @@ -991,8 +960,7 @@ void LocalCamera::Initialise() struct video_window vid_win; memset( &vid_win, 0, sizeof(vid_win) ); - if ( ioctl( vid_fd, VIDIOCGWIN, &vid_win) < 0 ) - { + if ( ioctl( vid_fd, VIDIOCGWIN, &vid_win) < 0 ) { Error( "Failed to get window attributes: %s", strerror(errno) ); exit(-1); } @@ -1007,8 +975,7 @@ void LocalCamera::Initialise() vid_win.height = height; vid_win.flags &= ~VIDEO_WINDOW_INTERLACE; - if ( ioctl( vid_fd, VIDIOCSWIN, &vid_win ) < 0 ) - { + if ( ioctl( vid_fd, VIDIOCSWIN, &vid_win ) < 0 ) { Error( "Failed to set window attributes: %s", strerror(errno) ); if ( config.strict_video_config ) exit(-1); @@ -1035,8 +1002,7 @@ void LocalCamera::Initialise() #if HAVE_LIBSWSCALE capturePictures = new AVFrame *[v4l1_data.frames.frames]; - for ( int i = 0; i < v4l1_data.frames.frames; i++ ) - { + for ( int i = 0; i < v4l1_data.frames.frames; i++ ) { v4l1_data.buffers[i].frame = i; v4l1_data.buffers[i].width = width; v4l1_data.buffers[i].height = height; @@ -1078,8 +1044,7 @@ void LocalCamera::Initialise() vid_src.norm = standard; vid_src.flags = 0; vid_src.type = VIDEO_TYPE_CAMERA; - if ( ioctl( vid_fd, VIDIOCSCHAN, &vid_src ) < 0 ) - { + if ( ioctl( vid_fd, VIDIOCSCHAN, &vid_src ) < 0 ) { Error( "Failed to set camera source %d: %s", channel, strerror(errno) ); if ( config.strict_video_config ) exit(-1); @@ -1110,11 +1075,9 @@ void LocalCamera::Initialise() #endif // ZM_HAS_V4L1 } -void LocalCamera::Terminate() -{ +void LocalCamera::Terminate() { #if ZM_HAS_V4L2 - if ( v4l_version == 2 ) - { + if ( v4l_version == 2 ) { Debug( 3, "Terminating video stream" ); //enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; // enum v4l2_buf_type type = v4l2_data.fmt.type; @@ -1136,14 +1099,12 @@ void LocalCamera::Terminate() Error( "Failed to munmap buffer %d: %s", i, strerror(errno) ); } - } - else + } else #endif // ZM_HAS_V4L2 #if ZM_HAS_V4L1 - if ( v4l_version == 1 ) - { + if ( v4l_version == 1 ) { #if HAVE_LIBSWSCALE for(int i=0; i < v4l1_data.frames.frames; i++) { /* Free capture pictures */ @@ -1160,12 +1121,12 @@ void LocalCamera::Terminate() Error( "Failed to munmap buffers: %s", strerror(errno) ); delete[] v4l1_data.buffers; - } + } // end if using v4l1 #endif // ZM_HAS_V4L1 close( vid_fd ); -} +} // end LocalCamera::Terminate uint32_t LocalCamera::AutoSelectFormat(int p_colours) { /* Automatic format selection */ @@ -1211,11 +1172,11 @@ uint32_t LocalCamera::AutoSelectFormat(int p_colours) { int nIndexUsed = -1; unsigned int n_preferedformats = 0; const uint32_t* preferedformats; - if(p_colours == ZM_COLOUR_RGB32) { + if ( p_colours == ZM_COLOUR_RGB32 ) { /* 32bit */ preferedformats = prefered_rgb32_formats; n_preferedformats = sizeof(prefered_rgb32_formats) / sizeof(uint32_t); - } else if(p_colours == ZM_COLOUR_GRAY8) { + } else if ( p_colours == ZM_COLOUR_GRAY8 ) { /* Grayscale */ preferedformats = prefered_gray8_formats; n_preferedformats = sizeof(prefered_gray8_formats) / sizeof(uint32_t); @@ -1224,9 +1185,9 @@ uint32_t LocalCamera::AutoSelectFormat(int p_colours) { preferedformats = prefered_rgb24_formats; n_preferedformats = sizeof(prefered_rgb24_formats) / sizeof(uint32_t); } - for( unsigned int i=0; i < n_preferedformats && nIndexUsed < 0; i++ ) { - for( unsigned int j=0; j < nIndex; j++ ) { - if( preferedformats[i] == fmt_fcc[j] ) { + for ( unsigned int i=0; i < n_preferedformats && nIndexUsed < 0; i++ ) { + for ( unsigned int j=0; j < nIndex; j++ ) { + if ( preferedformats[i] == fmt_fcc[j] ) { Debug(6, "Choosing format: %s (0x%02hhx%02hhx%02hhx%02hhx) at index %u", fmt_desc[j],fmt_fcc[j]&0xff, (fmt_fcc[j]>>8)&0xff, (fmt_fcc[j]>>16)&0xff, (fmt_fcc[j]>>24)&0xff ,j); /* Found a format! */ @@ -1240,7 +1201,7 @@ uint32_t LocalCamera::AutoSelectFormat(int p_colours) { } /* Have we found a match? */ - if(nIndexUsed >= 0) { + if ( nIndexUsed >= 0 ) { /* Found a match */ selected_palette = fmt_fcc[nIndexUsed]; strcpy(palette_desc,fmt_desc[nIndexUsed]); @@ -1251,37 +1212,30 @@ uint32_t LocalCamera::AutoSelectFormat(int p_colours) { #endif /* ZM_HAS_V4L2 */ return selected_palette; -} - +} //uint32_t LocalCamera::AutoSelectFormat(int p_colours) #define capString(test,prefix,yesString,noString,capability) \ (test) ? (prefix yesString " " capability "\n") : (prefix noString " " capability "\n") -bool LocalCamera::GetCurrentSettings( const char *device, char *output, int version, bool verbose ) -{ +bool LocalCamera::GetCurrentSettings( const char *device, char *output, int version, bool verbose ) { output[0] = 0; char queryDevice[PATH_MAX] = ""; int devIndex = 0; - do - { + do { if ( device ) strcpy( queryDevice, device ); else sprintf( queryDevice, "/dev/video%d", devIndex ); - if ( (vid_fd = open(queryDevice, O_RDWR)) <= 0 ) - { - if ( device ) - { + if ( (vid_fd = open(queryDevice, O_RDWR)) <= 0 ) { + if ( device ) { Error( "Failed to open video device %s: %s", queryDevice, strerror(errno) ); if ( verbose ) sprintf( output+strlen(output), "Error, failed to open video device %s: %s\n", queryDevice, strerror(errno) ); else sprintf( output+strlen(output), "error%d\n", errno ); return( false ); - } - else - { + } else { return( true ); } } @@ -1291,11 +1245,9 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers sprintf( output+strlen(output), "d:%s|", queryDevice ); #if ZM_HAS_V4L2 - if ( version == 2 ) - { + if ( version == 2 ) { struct v4l2_capability vid_cap; - if ( vidioctl( vid_fd, VIDIOC_QUERYCAP, &vid_cap ) < 0 ) - { + if ( vidioctl( vid_fd, VIDIOC_QUERYCAP, &vid_cap ) < 0 ) { Error( "Failed to query video device: %s", strerror(errno) ); if ( verbose ) sprintf( output, "Error, failed to query video capabilities %s: %s\n", queryDevice, strerror(errno) ); @@ -1304,8 +1256,7 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers return( false ); } - if ( verbose ) - { + if ( verbose ) { sprintf( output+strlen(output), "General Capabilities\n" ); sprintf( output+strlen(output), " Driver: %s\n", vid_cap.driver ); sprintf( output+strlen(output), " Card: %s\n", vid_cap.card ); @@ -1331,9 +1282,7 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers capString( vid_cap.capabilities&V4L2_CAP_ASYNCIO, " ", "Supports", "Does not support", "async i/o" ), capString( vid_cap.capabilities&V4L2_CAP_STREAMING, " ", "Supports", "Does not support", "streaming i/o (X)" ) ); - } - else - { + } else { sprintf( output+strlen(output), "D:%s|", vid_cap.driver ); sprintf( output+strlen(output), "C:%s|", vid_cap.card ); sprintf( output+strlen(output), "B:%s|", vid_cap.bus_info ); @@ -1347,21 +1296,16 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers sprintf( output+strlen(output), "S:" ); struct v4l2_standard standard; int standardIndex = 0; - do - { + do { memset( &standard, 0, sizeof(standard) ); standard.index = standardIndex; - if ( vidioctl( vid_fd, VIDIOC_ENUMSTD, &standard ) < 0 ) - { - if ( errno == EINVAL || errno == ENODATA || errno == ENOTTY ) - { + if ( vidioctl( vid_fd, VIDIOC_ENUMSTD, &standard ) < 0 ) { + if ( errno == EINVAL || errno == ENODATA || errno == ENOTTY ) { Debug( 6, "Done enumerating standard %d: %d %s", standard.index, errno, strerror(errno) ); standardIndex = -1; break; - } - else - { + } else { Error( "Failed to enumerate standard %d: %d %s", standard.index, errno, strerror(errno) ); if ( verbose ) sprintf( output, "Error, failed to enumerate standard %d: %d %s\n", standard.index, errno, strerror(errno) ); @@ -1374,8 +1318,8 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers sprintf( output+strlen(output), " %s\n", standard.name ); else sprintf( output+strlen(output), "%s/", standard.name ); - } - while ( standardIndex++ >= 0 ); + } while ( standardIndex++ >= 0 ); + if ( !verbose && output[strlen(output)-1] == '/') output[strlen(output)-1] = '|'; @@ -1385,21 +1329,16 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers sprintf( output+strlen(output), "F:" ); struct v4l2_fmtdesc format; int formatIndex = 0; - do - { + do { memset( &format, 0, sizeof(format) ); format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; format.index = formatIndex; - if ( vidioctl( vid_fd, VIDIOC_ENUM_FMT, &format ) < 0 ) - { - if ( errno == EINVAL ) - { + if ( vidioctl( vid_fd, VIDIOC_ENUM_FMT, &format ) < 0 ) { + if ( errno == EINVAL ) { formatIndex = -1; break; - } - else - { + } else { Error( "Failed to enumerate format %d: %s", format.index, strerror(errno) ); if ( verbose ) sprintf( output, "Error, failed to enumerate format %d: %s\n", format.index, strerror(errno) ); @@ -1414,39 +1353,35 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers else sprintf( output+strlen(output), "0x%02hhx%02hhx%02hhx%02hhx/", (format.pixelformat>>24)&0xff, (format.pixelformat>>16)&0xff, (format.pixelformat>>8)&0xff, (format.pixelformat)&0xff); - } - while ( formatIndex++ >= 0 ); - if ( !verbose ) - output[strlen(output)-1] = '|'; + } while ( formatIndex++ >= 0 ); - if(verbose) + if ( verbose ) sprintf( output+strlen(output), "Crop Capabilities\n" ); + else + output[strlen(output)-1] = '|'; struct v4l2_cropcap cropcap; memset( &cropcap, 0, sizeof(cropcap) ); cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if ( vidioctl( vid_fd, VIDIOC_CROPCAP, &cropcap ) < 0 ) - { - if(errno != EINVAL) { + if ( vidioctl( vid_fd, VIDIOC_CROPCAP, &cropcap ) < 0 ) { + if ( errno != EINVAL ) { /* Failed querying crop capability, write error to the log and continue as if crop is not supported */ Error( "Failed to query crop capabilities: %s", strerror(errno) ); } - if(verbose) { + if ( verbose ) { sprintf( output+strlen(output), " Cropping is not supported\n"); } else { /* Send fake crop bounds to not confuse things parsing this, such as monitor probe */ - sprintf( output+strlen(output), "B:%dx%d|",0,0); + sprintf( output+strlen(output), "B:%dx%d|", 0, 0 ); } } else { struct v4l2_crop crop; memset( &crop, 0, sizeof(crop) ); crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if ( vidioctl( vid_fd, VIDIOC_G_CROP, &crop ) < 0 ) - { - if ( errno != EINVAL ) - { + if ( vidioctl( vid_fd, VIDIOC_G_CROP, &crop ) < 0 ) { + if ( errno != EINVAL ) { /* Failed querying crop sizes, write error to the log and continue as if crop is not supported */ Error( "Failed to query crop: %s", strerror(errno) ); } @@ -1471,19 +1406,14 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers struct v4l2_input input; int inputIndex = 0; - do - { + do { memset( &input, 0, sizeof(input) ); input.index = inputIndex; - if ( vidioctl( vid_fd, VIDIOC_ENUMINPUT, &input ) < 0 ) - { - if ( errno == EINVAL ) - { + if ( vidioctl( vid_fd, VIDIOC_ENUMINPUT, &input ) < 0 ) { + if ( errno == EINVAL ) { break; - } - else - { + } else { Error( "Failed to enumerate input %d: %s", input.index, strerror(errno) ); if ( verbose ) sprintf( output, "Error, failed to enumerate input %d: %s\n", input.index, strerror(errno) ); @@ -1492,8 +1422,7 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers return( false ); } } - } - while ( inputIndex++ >= 0 ); + } while ( inputIndex++ >= 0 ); if ( verbose ) sprintf( output+strlen(output), "Inputs: %d\n", inputIndex ); @@ -1501,20 +1430,15 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers sprintf( output+strlen(output), "I:%d|", inputIndex ); inputIndex = 0; - do - { + do { memset( &input, 0, sizeof(input) ); input.index = inputIndex; - if ( vidioctl( vid_fd, VIDIOC_ENUMINPUT, &input ) < 0 ) - { - if ( errno == EINVAL ) - { + if ( vidioctl( vid_fd, VIDIOC_ENUMINPUT, &input ) < 0 ) { + if ( errno == EINVAL ) { inputIndex = -1; break; - } - else - { + } else { Error( "Failed to enumerate input %d: %s", input.index, strerror(errno) ); if ( verbose ) sprintf( output, "Error, failed to enumerate input %d: %s\n", input.index, strerror(errno) ); @@ -1524,8 +1448,7 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers } } - if ( vidioctl( vid_fd, VIDIOC_S_INPUT, &input.index ) < 0 ) - { + if ( vidioctl( vid_fd, VIDIOC_S_INPUT, &input.index ) < 0 ) { Error( "Failed to set video input %d: %s", input.index, strerror(errno) ); if ( verbose ) sprintf( output, "Error, failed to switch to input %d: %s\n", input.index, strerror(errno) ); @@ -1534,48 +1457,39 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers return( false ); } - if ( verbose ) - { + if ( verbose ) { sprintf( output+strlen(output), " Input %d\n", input.index ); sprintf( output+strlen(output), " Name: %s\n", input.name ); sprintf( output+strlen(output), " Type: %s\n", input.type==V4L2_INPUT_TYPE_TUNER?"Tuner":(input.type==V4L2_INPUT_TYPE_CAMERA?"Camera":"Unknown") ); sprintf( output+strlen(output), " Audioset: %08x\n", input.audioset ); sprintf( output+strlen(output), " Standards: 0x%llx\n", input.std ); - } - else - { + } else { sprintf( output+strlen(output), "i%d:%s|", input.index, input.name ); sprintf( output+strlen(output), "i%dT:%s|", input.index, input.type==V4L2_INPUT_TYPE_TUNER?"Tuner":(input.type==V4L2_INPUT_TYPE_CAMERA?"Camera":"Unknown") ); sprintf( output+strlen(output), "i%dS:%llx|", input.index, input.std ); } - if ( verbose ) - { + if ( verbose ) { sprintf( output+strlen(output), " %s", capString( input.status&V4L2_IN_ST_NO_POWER, "Power ", "off", "on", " (X)" ) ); sprintf( output+strlen(output), " %s", capString( input.status&V4L2_IN_ST_NO_SIGNAL, "Signal ", "not detected", "detected", " (X)" ) ); sprintf( output+strlen(output), " %s", capString( input.status&V4L2_IN_ST_NO_COLOR, "Colour Signal ", "not detected", "detected", "" ) ); sprintf( output+strlen(output), " %s", capString( input.status&V4L2_IN_ST_NO_H_LOCK, "Horizontal Lock ", "not detected", "detected", "" ) ); - } - else - { + } else { sprintf( output+strlen(output), "i%dSP:%d|", input.index, input.status&V4L2_IN_ST_NO_POWER?0:1 ); sprintf( output+strlen(output), "i%dSS:%d|", input.index, input.status&V4L2_IN_ST_NO_SIGNAL?0:1 ); sprintf( output+strlen(output), "i%dSC:%d|", input.index, input.status&V4L2_IN_ST_NO_COLOR?0:1 ); sprintf( output+strlen(output), "i%dHP:%d|", input.index, input.status&V4L2_IN_ST_NO_H_LOCK?0:1 ); } - } - while ( inputIndex++ >= 0 ); + } while ( inputIndex++ >= 0 ); if ( !verbose ) output[strlen(output)-1] = '\n'; } #endif // ZM_HAS_V4L2 #if ZM_HAS_V4L1 - if ( version == 1 ) - { + if ( version == 1 ) { struct video_capability vid_cap; memset( &vid_cap, 0, sizeof(video_capability) ); - if ( ioctl( vid_fd, VIDIOCGCAP, &vid_cap ) < 0 ) - { + if ( ioctl( vid_fd, VIDIOCGCAP, &vid_cap ) < 0 ) { Error( "Failed to get video capabilities: %s", strerror(errno) ); if ( verbose ) sprintf( output, "Error, failed to get video capabilities %s: %s\n", queryDevice, strerror(errno) ); @@ -1583,8 +1497,7 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers sprintf( output, "error%d\n", errno ); return( false ); } - if ( verbose ) - { + if ( verbose ) { sprintf( output+strlen(output), "Video Capabilities\n" ); sprintf( output+strlen(output), " Name: %s\n", vid_cap.name ); sprintf( output+strlen(output), " Type: %d\n%s%s%s%s%s%s%s%s%s%s%s%s%s%s", vid_cap.type, @@ -1609,9 +1522,7 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers sprintf( output+strlen(output), " Maximum Height: %d\n", vid_cap.maxheight ); sprintf( output+strlen(output), " Minimum Width: %d\n", vid_cap.minwidth ); sprintf( output+strlen(output), " Minimum Height: %d\n", vid_cap.minheight ); - } - else - { + } else { sprintf( output+strlen(output), "N:%s|", vid_cap.name ); sprintf( output+strlen(output), "T:%d|", vid_cap.type ); sprintf( output+strlen(output), "nC:%d|", vid_cap.channels ); @@ -1624,8 +1535,7 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers struct video_window vid_win; memset( &vid_win, 0, sizeof(video_window) ); - if ( ioctl( vid_fd, VIDIOCGWIN, &vid_win ) < 0 ) - { + if ( ioctl( vid_fd, VIDIOCGWIN, &vid_win ) < 0 ) { Error( "Failed to get window attributes: %s", strerror(errno) ); if ( verbose ) sprintf( output, "Error, failed to get window attributes: %s\n", strerror(errno) ); @@ -1633,16 +1543,13 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers sprintf( output, "error%d\n", errno ); return( false ); } - if ( verbose ) - { + if ( verbose ) { sprintf( output+strlen(output), "Window Attributes\n" ); sprintf( output+strlen(output), " X Offset: %d\n", vid_win.x ); sprintf( output+strlen(output), " Y Offset: %d\n", vid_win.y ); sprintf( output+strlen(output), " Width: %d\n", vid_win.width ); sprintf( output+strlen(output), " Height: %d\n", vid_win.height ); - } - else - { + } else { sprintf( output+strlen(output), "X:%d|", vid_win.x ); sprintf( output+strlen(output), "Y:%d|", vid_win.y ); sprintf( output+strlen(output), "W:%d|", vid_win.width ); @@ -1651,8 +1558,7 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers struct video_picture vid_pic; memset( &vid_cap, 0, sizeof(video_picture) ); - if ( ioctl( vid_fd, VIDIOCGPICT, &vid_pic ) < 0 ) - { + if ( ioctl( vid_fd, VIDIOCGPICT, &vid_pic ) < 0 ) { Error( "Failed to get picture attributes: %s", strerror(errno) ); if ( verbose ) sprintf( output, "Error, failed to get picture attributes: %s\n", strerror(errno) ); @@ -1660,8 +1566,7 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers sprintf( output, "error%d\n", errno ); return( false ); } - if ( verbose ) - { + if ( verbose ) { sprintf( output+strlen(output), "Picture Attributes\n" ); sprintf( output+strlen(output), " Palette: %d - %s\n", vid_pic.palette, vid_pic.palette==VIDEO_PALETTE_GREY?"Linear greyscale":( @@ -1689,9 +1594,7 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers sprintf( output+strlen(output), " Colour :%d\n", vid_pic.colour ); sprintf( output+strlen(output), " Contrast: %d\n", vid_pic.contrast ); sprintf( output+strlen(output), " Whiteness: %d\n", vid_pic.whiteness ); - } - else - { + } else { sprintf( output+strlen(output), "P:%d|", vid_pic.palette ); sprintf( output+strlen(output), "D:%d|", vid_pic.depth ); sprintf( output+strlen(output), "B:%d|", vid_pic.brightness ); @@ -1701,13 +1604,11 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers sprintf( output+strlen(output), "w:%d|", vid_pic.whiteness ); } - for ( int chan = 0; chan < vid_cap.channels; chan++ ) - { + for ( int chan = 0; chan < vid_cap.channels; chan++ ) { struct video_channel vid_src; memset( &vid_src, 0, sizeof(video_channel) ); vid_src.channel = chan; - if ( ioctl( vid_fd, VIDIOCGCHAN, &vid_src ) < 0 ) - { + if ( ioctl( vid_fd, VIDIOCGCHAN, &vid_src ) < 0 ) { Error( "Failed to get channel %d attributes: %s", chan, strerror(errno) ); if ( verbose ) sprintf( output, "Error, failed to get channel %d attributes: %s\n", chan, strerror(errno) ); @@ -1715,8 +1616,7 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers sprintf( output, "error%d\n", errno ); return( false ); } - if ( verbose ) - { + if ( verbose ) { sprintf( output+strlen(output), "Channel %d Attributes\n", chan ); sprintf( output+strlen(output), " Name: %s\n", vid_src.name ); sprintf( output+strlen(output), " Channel: %d\n", vid_src.channel ); @@ -1734,9 +1634,7 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers vid_src.norm==VIDEO_MODE_SECAM?"SECAM":( vid_src.norm==VIDEO_MODE_AUTO?"AUTO":"Unknown" )))); - } - else - { + } else { sprintf( output+strlen(output), "n%d:%s|", chan, vid_src.name ); sprintf( output+strlen(output), "C%d:%d|", chan, vid_src.channel ); sprintf( output+strlen(output), "Fl%d:%x|", chan, vid_src.flags ); @@ -1756,32 +1654,26 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers return( true ); } -int LocalCamera::Brightness( int p_brightness ) -{ +int LocalCamera::Brightness( int p_brightness ) { #if ZM_HAS_V4L2 - if ( v4l_version == 2 ) - { + if ( v4l_version == 2 ) { struct v4l2_control vid_control; memset( &vid_control, 0, sizeof(vid_control) ); vid_control.id = V4L2_CID_BRIGHTNESS; - if ( vidioctl( vid_fd, VIDIOC_G_CTRL, &vid_control ) < 0 ) - { + if ( vidioctl( vid_fd, VIDIOC_G_CTRL, &vid_control ) < 0 ) { if ( errno != EINVAL ) Error( "Unable to query brightness: %s", strerror(errno) ) else Warning( "Brightness control is not supported" ) //Info( "Brightness 1 %d", vid_control.value ); - } - else if ( p_brightness >= 0 ) - { + } else if ( p_brightness >= 0 ) { vid_control.value = p_brightness; //Info( "Brightness 2 %d", vid_control.value ); /* The driver may clamp the value or return ERANGE, ignored here */ - if ( vidioctl ( vid_fd, VIDIOC_S_CTRL, &vid_control ) ) - { + if ( vidioctl ( vid_fd, VIDIOC_S_CTRL, &vid_control ) ) { if ( errno != ERANGE ) Error( "Unable to set brightness: %s", strerror(errno) ) else @@ -1793,21 +1685,17 @@ int LocalCamera::Brightness( int p_brightness ) } #endif // ZM_HAS_V4L2 #if ZM_HAS_V4L1 - if ( v4l_version == 1 ) - { + if ( v4l_version == 1 ) { struct video_picture vid_pic; memset( &vid_pic, 0, sizeof(video_picture) ); - if ( ioctl( vid_fd, VIDIOCGPICT, &vid_pic) < 0 ) - { + if ( ioctl( vid_fd, VIDIOCGPICT, &vid_pic) < 0 ) { Error( "Failed to get picture attributes: %s", strerror(errno) ); return( -1 ); } - if ( p_brightness >= 0 ) - { + if ( p_brightness >= 0 ) { vid_pic.brightness = p_brightness; - if ( ioctl( vid_fd, VIDIOCSPICT, &vid_pic ) < 0 ) - { + if ( ioctl( vid_fd, VIDIOCSPICT, &vid_pic ) < 0 ) { Error( "Failed to set picture attributes: %s", strerror(errno) ); return( -1 ); } @@ -1818,30 +1706,24 @@ int LocalCamera::Brightness( int p_brightness ) return( -1 ); } -int LocalCamera::Hue( int p_hue ) -{ +int LocalCamera::Hue( int p_hue ) { #if ZM_HAS_V4L2 - if ( v4l_version == 2 ) - { + if ( v4l_version == 2 ) { struct v4l2_control vid_control; memset( &vid_control, 0, sizeof(vid_control) ); vid_control.id = V4L2_CID_HUE; - if ( vidioctl( vid_fd, VIDIOC_G_CTRL, &vid_control ) < 0 ) - { + if ( vidioctl( vid_fd, VIDIOC_G_CTRL, &vid_control ) < 0 ) { if ( errno != EINVAL ) Error( "Unable to query hue: %s", strerror(errno) ) else Warning( "Hue control is not supported" ) - } - else if ( p_hue >= 0 ) - { + } else if ( p_hue >= 0 ) { vid_control.value = p_hue; /* The driver may clamp the value or return ERANGE, ignored here */ - if ( vidioctl ( vid_fd, VIDIOC_S_CTRL, &vid_control ) < 0 ) - { + if ( vidioctl ( vid_fd, VIDIOC_S_CTRL, &vid_control ) < 0 ) { if ( errno != ERANGE ) Error( "Unable to set hue: %s", strerror(errno) ) else @@ -1852,21 +1734,17 @@ int LocalCamera::Hue( int p_hue ) } #endif // ZM_HAS_V4L2 #if ZM_HAS_V4L1 - if ( v4l_version == 1 ) - { + if ( v4l_version == 1 ) { struct video_picture vid_pic; memset( &vid_pic, 0, sizeof(video_picture) ); - if ( ioctl( vid_fd, VIDIOCGPICT, &vid_pic) < 0 ) - { + if ( ioctl( vid_fd, VIDIOCGPICT, &vid_pic) < 0 ) { Error( "Failed to get picture attributes: %s", strerror(errno) ); return( -1 ); } - if ( p_hue >= 0 ) - { + if ( p_hue >= 0 ) { vid_pic.hue = p_hue; - if ( ioctl( vid_fd, VIDIOCSPICT, &vid_pic ) < 0 ) - { + if ( ioctl( vid_fd, VIDIOCSPICT, &vid_pic ) < 0 ) { Error( "Failed to set picture attributes: %s", strerror(errno) ); return( -1 ); } @@ -1877,30 +1755,24 @@ int LocalCamera::Hue( int p_hue ) return( -1 ); } -int LocalCamera::Colour( int p_colour ) -{ +int LocalCamera::Colour( int p_colour ) { #if ZM_HAS_V4L2 - if ( v4l_version == 2 ) - { + if ( v4l_version == 2 ) { struct v4l2_control vid_control; memset( &vid_control, 0, sizeof(vid_control) ); vid_control.id = V4L2_CID_SATURATION; - if ( vidioctl( vid_fd, VIDIOC_G_CTRL, &vid_control ) < 0 ) - { + if ( vidioctl( vid_fd, VIDIOC_G_CTRL, &vid_control ) < 0 ) { if ( errno != EINVAL ) Error( "Unable to query saturation: %s", strerror(errno) ) else Warning( "Saturation control is not supported" ) - } - else if ( p_colour >= 0 ) - { + } else if ( p_colour >= 0 ) { vid_control.value = p_colour; /* The driver may clamp the value or return ERANGE, ignored here */ - if ( vidioctl ( vid_fd, VIDIOC_S_CTRL, &vid_control ) < 0 ) - { + if ( vidioctl ( vid_fd, VIDIOC_S_CTRL, &vid_control ) < 0 ) { if ( errno != ERANGE ) Error( "Unable to set saturation: %s", strerror(errno) ) else @@ -1911,21 +1783,17 @@ int LocalCamera::Colour( int p_colour ) } #endif // ZM_HAS_V4L2 #if ZM_HAS_V4L1 - if ( v4l_version == 1 ) - { + if ( v4l_version == 1 ) { struct video_picture vid_pic; memset( &vid_pic, 0, sizeof(video_picture) ); - if ( ioctl( vid_fd, VIDIOCGPICT, &vid_pic) < 0 ) - { + if ( ioctl( vid_fd, VIDIOCGPICT, &vid_pic) < 0 ) { Error( "Failed to get picture attributes: %s", strerror(errno) ); return( -1 ); } - if ( p_colour >= 0 ) - { + if ( p_colour >= 0 ) { vid_pic.colour = p_colour; - if ( ioctl( vid_fd, VIDIOCSPICT, &vid_pic ) < 0 ) - { + if ( ioctl( vid_fd, VIDIOCSPICT, &vid_pic ) < 0 ) { Error( "Failed to set picture attributes: %s", strerror(errno) ); return( -1 ); } @@ -1936,30 +1804,24 @@ int LocalCamera::Colour( int p_colour ) return( -1 ); } -int LocalCamera::Contrast( int p_contrast ) -{ +int LocalCamera::Contrast( int p_contrast ) { #if ZM_HAS_V4L2 - if ( v4l_version == 2 ) - { + if ( v4l_version == 2 ) { struct v4l2_control vid_control; memset( &vid_control, 0, sizeof(vid_control) ); vid_control.id = V4L2_CID_CONTRAST; - if ( vidioctl( vid_fd, VIDIOC_G_CTRL, &vid_control ) < 0 ) - { + if ( vidioctl( vid_fd, VIDIOC_G_CTRL, &vid_control ) < 0 ) { if ( errno != EINVAL ) Error( "Unable to query contrast: %s", strerror(errno) ) else Warning( "Contrast control is not supported" ) - } - else if ( p_contrast >= 0 ) - { + } else if ( p_contrast >= 0 ) { vid_control.value = p_contrast; /* The driver may clamp the value or return ERANGE, ignored here */ - if ( vidioctl ( vid_fd, VIDIOC_S_CTRL, &vid_control ) ) - { + if ( vidioctl ( vid_fd, VIDIOC_S_CTRL, &vid_control ) ) { if ( errno != ERANGE ) Error( "Unable to set contrast: %s", strerror(errno) ) else @@ -1970,21 +1832,17 @@ int LocalCamera::Contrast( int p_contrast ) } #endif // ZM_HAS_V4L2 #if ZM_HAS_V4L1 - if ( v4l_version == 1 ) - { + if ( v4l_version == 1 ) { struct video_picture vid_pic; memset( &vid_pic, 0, sizeof(video_picture) ); - if ( ioctl( vid_fd, VIDIOCGPICT, &vid_pic) < 0 ) - { + if ( ioctl( vid_fd, VIDIOCGPICT, &vid_pic) < 0 ) { Error( "Failed to get picture attributes: %s", strerror(errno) ); return( -1 ); } - if ( p_contrast >= 0 ) - { + if ( p_contrast >= 0 ) { vid_pic.contrast = p_contrast; - if ( ioctl( vid_fd, VIDIOCSPICT, &vid_pic ) < 0 ) - { + if ( ioctl( vid_fd, VIDIOCSPICT, &vid_pic ) < 0 ) { Error( "Failed to set picture attributes: %s", strerror(errno) ); return( -1 ); } @@ -1995,17 +1853,14 @@ int LocalCamera::Contrast( int p_contrast ) return( -1 ); } -int LocalCamera::PrimeCapture() -{ +int LocalCamera::PrimeCapture() { Initialise(); Debug( 2, "Priming capture" ); #if ZM_HAS_V4L2 - if ( v4l_version == 2 ) - { + if ( v4l_version == 2 ) { Debug( 3, "Queueing buffers" ); - for ( unsigned int frame = 0; frame < v4l2_data.reqbufs.count; frame++ ) - { + for ( unsigned int frame = 0; frame < v4l2_data.reqbufs.count; frame++ ) { struct v4l2_buffer vid_buf; memset( &vid_buf, 0, sizeof(vid_buf) ); @@ -2028,13 +1883,10 @@ int LocalCamera::PrimeCapture() } #endif // ZM_HAS_V4L2 #if ZM_HAS_V4L1 - if ( v4l_version == 1 ) - { - for ( int frame = 0; frame < v4l1_data.frames.frames; frame++ ) - { + if ( v4l_version == 1 ) { + for ( int frame = 0; frame < v4l1_data.frames.frames; frame++ ) { Debug( 3, "Queueing frame %d", frame ); - if ( ioctl( vid_fd, VIDIOCMCAPTURE, &v4l1_data.buffers[frame] ) < 0 ) - { + if ( ioctl( vid_fd, VIDIOCMCAPTURE, &v4l1_data.buffers[frame] ) < 0 ) { Error( "Capture failure for frame %d: %s", frame, strerror(errno) ); return( -1 ); } @@ -2045,14 +1897,14 @@ int LocalCamera::PrimeCapture() return( 0 ); } -int LocalCamera::PreCapture() -{ +int LocalCamera::PreCapture() { Debug( 2, "Pre-capturing" ); return( 0 ); } -int LocalCamera::Capture( Image &image ) -{ +int LocalCamera::Capture( ZMPacket &zm_packet ) { + + // We assume that the avpacket is allocated, and just needs to be filled Debug( 3, "Capturing" ); static uint8_t* buffer = NULL; static uint8_t* directbuffer = NULL; @@ -2067,13 +1919,10 @@ int LocalCamera::Capture( Image &image ) Warning( "Invalid Captures Per Frame setting: %d", captures_per_frame ); } - // Do the capture, unless we are the second or subsequent camera on a channel, in which case just reuse the buffer - if ( channel_prime ) - { + if ( channel_prime ) { #if ZM_HAS_V4L2 - if ( v4l_version == 2 ) - { + if ( v4l_version == 2 ) { static struct v4l2_buffer vid_buf; memset( &vid_buf, 0, sizeof(vid_buf) ); @@ -2083,60 +1932,50 @@ int LocalCamera::Capture( Image &image ) vid_buf.memory = v4l2_data.reqbufs.memory; Debug( 3, "Capturing %d frames", captures_per_frame ); - while ( captures_per_frame ) - { - if ( vidioctl( vid_fd, VIDIOC_DQBUF, &vid_buf ) < 0 ) - { + while ( captures_per_frame ) { + if ( vidioctl( vid_fd, VIDIOC_DQBUF, &vid_buf ) < 0 ) { if ( errno == EIO ) Warning( "Capture failure, possible signal loss?: %s", strerror(errno) ) else Error( "Unable to capture frame %d: %s", vid_buf.index, strerror(errno) ) - return( -1 ); + return -1; } v4l2_data.bufptr = &vid_buf; capture_frame = v4l2_data.bufptr->index; - if ( --captures_per_frame ) - { - if ( vidioctl( vid_fd, VIDIOC_QBUF, &vid_buf ) < 0 ) - { + if ( --captures_per_frame ) { + if ( vidioctl( vid_fd, VIDIOC_QBUF, &vid_buf ) < 0 ) { Error( "Unable to requeue buffer %d: %s", vid_buf.index, strerror(errno) ); - return( -1 ); + return -1; } } - } + } // while captures_per_frame Debug( 3, "Captured frame %d/%d from channel %d", capture_frame, v4l2_data.bufptr->sequence, channel ); buffer = (unsigned char *)v4l2_data.buffers[v4l2_data.bufptr->index].start; buffer_bytesused = v4l2_data.bufptr->bytesused; - if((v4l2_data.fmt.fmt.pix.width * v4l2_data.fmt.fmt.pix.height) != (width * height)) { + if ( (v4l2_data.fmt.fmt.pix.width * v4l2_data.fmt.fmt.pix.height) != (width * height) ) { Fatal("Captured image dimensions differ: V4L2: %dx%d monitor: %dx%d",v4l2_data.fmt.fmt.pix.width,v4l2_data.fmt.fmt.pix.height,width,height); } - - } + } else // end if v4l2 #endif // ZM_HAS_V4L2 #if ZM_HAS_V4L1 - if ( v4l_version == 1 ) - { + if ( v4l_version == 1 ) { Debug( 3, "Capturing %d frames", captures_per_frame ); - while ( captures_per_frame ) - { + while ( captures_per_frame ) { Debug( 3, "Syncing frame %d", v4l1_data.active_frame ); - if ( ioctl( vid_fd, VIDIOCSYNC, &v4l1_data.active_frame ) < 0 ) - { + if ( ioctl( vid_fd, VIDIOCSYNC, &v4l1_data.active_frame ) < 0 ) { Error( "Sync failure for frame %d buffer %d: %s", v4l1_data.active_frame, captures_per_frame, strerror(errno) ); - return( -1 ); + return -1; } captures_per_frame--; - if ( captures_per_frame ) - { + if ( captures_per_frame ) { Debug( 3, "Capturing frame %d", v4l1_data.active_frame ); - if ( ioctl( vid_fd, VIDIOCMCAPTURE, &v4l1_data.buffers[v4l1_data.active_frame] ) < 0 ) - { + if ( ioctl( vid_fd, VIDIOCMCAPTURE, &v4l1_data.buffers[v4l1_data.active_frame] ) < 0 ) { Error( "Capture failure for buffer %d (%d): %s", v4l1_data.active_frame, captures_per_frame, strerror(errno) ); - return( -1 ); + return -1; } } } @@ -2148,18 +1987,18 @@ int LocalCamera::Capture( Image &image ) #endif // ZM_HAS_V4L1 } /* prime capture */ - if(conversion_type != 0) { + if ( conversion_type != 0 ) { Debug( 3, "Performing format conversion" ); /* Request a writeable buffer of the target image */ - directbuffer = image.WriteBuffer(width, height, colours, subpixelorder); - if(directbuffer == NULL) { + directbuffer = zm_packet.image->WriteBuffer(width, height, colours, subpixelorder); + if ( directbuffer == NULL ) { Error("Failed requesting writeable buffer for the captured image."); - return (-1); + return -1; } #if HAVE_LIBSWSCALE - if(conversion_type == 1) { + if ( conversion_type == 1 ) { Debug( 9, "Calling sws_scale to perform the conversion" ); /* Use swscale to convert the image directly into the shared memory */ @@ -2171,63 +2010,61 @@ int LocalCamera::Capture( Image &image ) avpicture_fill( (AVPicture *)tmpPicture, directbuffer, imagePixFormat, width, height ); #endif - sws_scale( imgConversionContext, capturePictures[capture_frame]->data, capturePictures[capture_frame]->linesize, 0, height, tmpPicture->data, tmpPicture->linesize ); - } + sws_scale( + imgConversionContext, + capturePictures[capture_frame]->data, + capturePictures[capture_frame]->linesize, + 0, + height, + tmpPicture->data, + tmpPicture->linesize + ); + } else #endif - if(conversion_type == 2) { - + if ( conversion_type == 2 ) { Debug( 9, "Calling the conversion function" ); /* Call the image conversion function and convert directly into the shared memory */ (*conversion_fptr)(buffer, directbuffer, pixels); - } - else if(conversion_type == 3) { - + } else if ( conversion_type == 3 ) { + // Need to store the jpeg data too Debug( 9, "Decoding the JPEG image" ); /* JPEG decoding */ - image.DecodeJpeg(buffer, buffer_bytesused, colours, subpixelorder); + zm_packet.image->DecodeJpeg(buffer, buffer_bytesused, colours, subpixelorder); } } else { Debug( 3, "No format conversion performed. Assigning the image" ); /* No conversion was performed, the image is in the V4L buffers and needs to be copied into the shared memory */ - image.Assign( width, height, colours, subpixelorder, buffer, imagesize); + zm_packet.image->Assign(width, height, colours, subpixelorder, buffer, imagesize); + } // end if doing conversion or not - } + return 1; +} // end Capture - return( 0 ); -} - -int LocalCamera::PostCapture() -{ +int LocalCamera::PostCapture() { Debug( 2, "Post-capturing" ); // Requeue the buffer unless we need to switch or are a duplicate camera on a channel - if ( channel_count > 1 || channel_prime ) - { + if ( channel_count > 1 || channel_prime ) { #if ZM_HAS_V4L2 - if ( v4l_version == 2 ) - { - if ( channel_count > 1 ) - { + if ( v4l_version == 2 ) { + if ( channel_count > 1 ) { int next_channel = (channel_index+1)%channel_count; Debug( 3, "Switching video source to %d", channels[next_channel] ); - if ( vidioctl( vid_fd, VIDIOC_S_INPUT, &channels[next_channel] ) < 0 ) - { + if ( vidioctl( vid_fd, VIDIOC_S_INPUT, &channels[next_channel] ) < 0 ) { Error( "Failed to set camera source %d: %s", channels[next_channel], strerror(errno) ); return( -1 ); } v4l2_std_id stdId = standards[next_channel]; - if ( vidioctl( vid_fd, VIDIOC_S_STD, &stdId ) < 0 ) - { + if ( vidioctl( vid_fd, VIDIOC_S_STD, &stdId ) < 0 ) { Error( "Failed to set video format %d: %s", standards[next_channel], strerror(errno) ); return( -1 ); } } if ( v4l2_data.bufptr ) { Debug( 3, "Requeueing buffer %d", v4l2_data.bufptr->index ); - if ( vidioctl( vid_fd, VIDIOC_QBUF, v4l2_data.bufptr ) < 0 ) - { + if ( vidioctl( vid_fd, VIDIOC_QBUF, v4l2_data.bufptr ) < 0 ) { Error( "Unable to requeue buffer %d: %s", v4l2_data.bufptr->index, strerror(errno) ) return( -1 ); } @@ -2237,17 +2074,14 @@ int LocalCamera::PostCapture() } #endif // ZM_HAS_V4L2 #if ZM_HAS_V4L1 - if ( v4l_version == 1 ) - { - if ( channel_count > 1 ) - { + if ( v4l_version == 1 ) { + if ( channel_count > 1 ) { Debug( 3, "Switching video source" ); int next_channel = (channel_index+1)%channel_count; struct video_channel vid_src; memset( &vid_src, 0, sizeof(vid_src) ); vid_src.channel = channel; - if ( ioctl( vid_fd, VIDIOCGCHAN, &vid_src) < 0 ) - { + if ( ioctl( vid_fd, VIDIOCGCHAN, &vid_src) < 0 ) { Error( "Failed to get camera source %d: %s", channel, strerror(errno) ); return(-1); } @@ -2256,15 +2090,13 @@ int LocalCamera::PostCapture() vid_src.norm = standards[next_channel]; vid_src.flags = 0; vid_src.type = VIDEO_TYPE_CAMERA; - if ( ioctl( vid_fd, VIDIOCSCHAN, &vid_src ) < 0 ) - { + if ( ioctl( vid_fd, VIDIOCSCHAN, &vid_src ) < 0 ) { Error( "Failed to set camera source %d: %s", channel, strerror(errno) ); return( -1 ); } } Debug( 3, "Requeueing frame %d", v4l1_data.active_frame ); - if ( ioctl( vid_fd, VIDIOCMCAPTURE, &v4l1_data.buffers[v4l1_data.active_frame] ) < 0 ) - { + if ( ioctl( vid_fd, VIDIOCMCAPTURE, &v4l1_data.buffers[v4l1_data.active_frame] ) < 0 ) { Error( "Capture failure for frame %d: %s", v4l1_data.active_frame, strerror(errno) ); return( -1 ); } diff --git a/src/zm_local_camera.h b/src/zm_local_camera.h index dae5f830e..de1d7f9c5 100644 --- a/src/zm_local_camera.h +++ b/src/zm_local_camera.h @@ -23,7 +23,7 @@ #include "zm.h" #include "zm_camera.h" #include "zm_image.h" -#include "zm_packetqueue.h" +#include "zm_packet.h" #if ZM_HAS_V4L @@ -49,18 +49,15 @@ // directly connect to the host machine and which are accessed // via a video interface. // -class LocalCamera : public Camera -{ +class LocalCamera : public Camera { protected: #if ZM_HAS_V4L2 - struct V4L2MappedBuffer - { + struct V4L2MappedBuffer { void *start; size_t length; }; - struct V4L2Data - { + struct V4L2Data { v4l2_cropcap cropcap; v4l2_crop crop; v4l2_format fmt; @@ -71,8 +68,7 @@ protected: #endif // ZM_HAS_V4L2 #if ZM_HAS_V4L1 - struct V4L1Data - { + struct V4L1Data { int active_frame; video_mbuf frames; video_mmap *buffers; @@ -160,10 +156,8 @@ public: int PrimeCapture(); int PreCapture(); - int Capture( Image &image ); + int Capture(ZMPacket &p); int PostCapture(); - int CaptureAndRecord( Image &image, timeval recording, char* event_directory ) {return(0);}; - static bool GetCurrentSettings( const char *device, char *output, int version, bool verbose ); }; diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 1b3ed85ac..054f6ccf4 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -85,7 +85,7 @@ Monitor::MonitorLink::MonitorLink( int p_id, const char *p_name ) : id( p_id ) { mem_size = 0; mem_ptr = 0; - last_event = 0; + last_event_id = 0; last_state = IDLE; last_connect_time = 0; @@ -165,7 +165,7 @@ bool Monitor::MonitorLink::connect() { } last_state = shared_data->state; - last_event = shared_data->last_event; + last_event_id = shared_data->last_event_id; connected = true; return( true ); @@ -231,8 +231,8 @@ bool Monitor::MonitorLink::inAlarm() { bool Monitor::MonitorLink::hasAlarmed() { if ( shared_data->state == ALARM ) { return( true ); - } else if ( shared_data->last_event != (unsigned int)last_event ) { - last_event = shared_data->last_event; + } else if ( shared_data->last_event_id != (unsigned int)last_event_id ) { + last_event_id = shared_data->last_event_id; } return( false ); } @@ -410,7 +410,7 @@ Monitor::Monitor( shared_data->last_write_index = image_buffer_count; shared_data->last_read_index = image_buffer_count; shared_data->last_write_time = 0; - shared_data->last_event = 0; + shared_data->last_event_id = 0; shared_data->action = (Action)0; shared_data->brightness = -1; shared_data->hue = -1; @@ -772,7 +772,7 @@ unsigned int Monitor::GetLastWriteIndex() const { } unsigned int Monitor::GetLastEvent() const { - return( shared_data->last_event ); + return( shared_data->last_event_id ); } double Monitor::GetFPS() const { @@ -1407,7 +1407,7 @@ bool Monitor::Analyse() { // Create event event = new Event( this, *timestamp, "Continuous", noteSetMap, videoRecording ); - shared_data->last_event = event->Id(); + shared_data->last_event_id = event->Id(); //set up video store data snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "%s", event->getEventFile()); video_store_data->recording = event->StartTime(); @@ -1511,7 +1511,7 @@ bool Monitor::Analyse() { event = new Event( this, *(image_buffer[pre_index].timestamp), cause, noteSetMap ); } - shared_data->last_event = event->Id(); + shared_data->last_event_id = event->Id(); //set up video store data snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "%s", event->getEventFile()); video_store_data->recording = event->StartTime(); @@ -2857,13 +2857,14 @@ Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) { */ int Monitor::Capture() { static int FirstCapture = 1; // Used in de-interlacing to indicate whether this is the even or odd image - int captureResult; - unsigned int index = image_count%image_buffer_count; + unsigned int index = image_count % image_buffer_count; Image* capture_image = image_buffer[index].image; + ZMPacket packet; + packet.set_image(capture_image); + int captureResult = 0; unsigned int deinterlacing_value = deinterlacing & 0xff; - if ( deinterlacing_value == 4 ) { if ( FirstCapture != 1 ) { /* Copy the next image into the shared memory */ @@ -2871,147 +2872,207 @@ int Monitor::Capture() { } /* Capture a new next image */ - - //Check if FFMPEG camera - // Icon: I don't think we can support de-interlacing on ffmpeg input.... most of the time it will be h264 or mpeg4 - if ( ( videowriter == H264PASSTHROUGH ) && camera->SupportsNativeVideo() ) { - captureResult = camera->CaptureAndRecord(*(next_buffer.image), - video_store_data->recording, - video_store_data->event_file ); - } else { - captureResult = camera->Capture(*(next_buffer.image)); - } + captureResult = camera->Capture(packet); if ( FirstCapture ) { FirstCapture = 0; return 0; } - } else { - //Check if FFMPEG camera - if ( (videowriter == H264PASSTHROUGH ) && camera->SupportsNativeVideo() ) { - //Warning("ZMC: Recording: %d", video_store_data->recording); - captureResult = camera->CaptureAndRecord(*capture_image, video_store_data->recording, video_store_data->event_file); - }else{ - /* Capture directly into image buffer, avoiding the need to memcpy() */ - captureResult = camera->Capture(*capture_image); + captureResult = camera->Capture(packet); + if ( captureResult < 0 ) { + // Unable to capture image for temporary reason + // Fake a signal loss image + Rgb signalcolor; + /* HTML colour code is actually BGR in memory, we want RGB */ + signalcolor = rgb_convert(signal_check_colour, ZM_SUBPIX_ORDER_BGR); + capture_image->Fill(signalcolor); + shared_data->signal = false; + return -1; } - } - - // CaptureAndRecord returns # of frames captured I think - if ( ( videowriter == H264PASSTHROUGH ) && ( captureResult > 0 ) ) { - //video_store_data->frameNumber = captureResult; - captureResult = 0; - } - - if ( captureResult != 0 ) { - // Unable to capture image for temporary reason - // Fake a signal loss image - Rgb signalcolor; - signalcolor = rgb_convert(signal_check_colour, ZM_SUBPIX_ORDER_BGR); /* HTML colour code is actually BGR in memory, we want RGB */ - capture_image->Fill(signalcolor); - captureResult = 0; - } else { - captureResult = 1; - } - - if ( captureResult == 1 ) { - - /* Deinterlacing */ - if ( deinterlacing_value == 1 ) { - capture_image->Deinterlace_Discard(); - } else if ( deinterlacing_value == 2 ) { - capture_image->Deinterlace_Linear(); - } else if ( deinterlacing_value == 3 ) { - capture_image->Deinterlace_Blend(); - } else if ( deinterlacing_value == 4 ) { - capture_image->Deinterlace_4Field( next_buffer.image, (deinterlacing>>8)&0xff ); - } else if ( deinterlacing_value == 5 ) { - capture_image->Deinterlace_Blend_CustomRatio( (deinterlacing>>8)&0xff ); - } - - if ( orientation != ROTATE_0 ) { - switch ( orientation ) { - case ROTATE_0 : { - // No action required - break; - } - case ROTATE_90 : - case ROTATE_180 : - case ROTATE_270 : { - capture_image->Rotate( (orientation-1)*90 ); - break; - } - case FLIP_HORI : - case FLIP_VERT : { - capture_image->Flip( orientation==FLIP_HORI ); - break; + + int video_stream_id = camera->get_VideoStreamId(); + + //Video recording + if ( video_store_data->recording.tv_sec ) { + if ( shared_data->last_event_id != this->GetVideoWriterEventId() ) { + Debug(2, "Have change of event. last_event(%d), our current (%d)", + shared_data->last_event_id, + this->GetVideoWriterEventId() + ); + if ( videoStore ) { + Debug(2, "Have videostore already?"); + // 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. + int ret = videoStore->writePacket( &packet ); + if ( ret < 0 ) { //Less than zero and we skipped a frame + Warning("Error writing last packet to videostore."); + } + + delete videoStore; + videoStore = NULL; + this->SetVideoWriterEventId( 0 ); + } // end if videoStore + } // end if end of recording + + if ( shared_data->last_event_id and ! videoStore ) { + Debug(2,"New videostore"); + videoStore = new VideoStore( + (const char *) video_store_data->event_file, + "mp4", + camera->get_VideoStream(), + ( record_audio ? camera->get_AudioStream() : NULL ), + video_store_data->recording.tv_sec, + this ); + + if ( ! videoStore->open() ) { + delete videoStore; + videoStore = NULL; + } else { + this->SetVideoWriterEventId(shared_data->last_event_id); + + Debug(2, "Clearing packets"); + // Clear all packets that predate the moment when the recording began + packetqueue.clear_unwanted_packets(&video_store_data->recording, video_stream_id); + videoStore->write_packets(packetqueue); + } // success opening + } // end if ! was recording + } else { // Not recording + if ( videoStore ) { + Info("Deleting videoStore instance"); + delete videoStore; + videoStore = NULL; + this->SetVideoWriterEventId( 0 ); + } + + // Buffer video packets, since we are not recording. + // All audio packets are keyframes, so only if it's a video keyframe + if ( ( packet.packet.stream_index == video_stream_id ) && ( packet.keyframe ) ) { + packetqueue.clearQueue( this->GetPreEventCount(), video_stream_id ); + } + // The following lines should ensure that the queue always begins with a video keyframe + if ( packet.packet.stream_index == camera->get_AudioStreamId() ) { + //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.packet.stream_index == video_stream_id ) { + if ( packet.keyframe || packetqueue.size() ) // it's a keyframe or we already have something in the queue + packetqueue.queuePacket( &packet ); + } // end if audio or video + } // end if recording or not + + if ( videoStore ) { + //Write the packet to our video store, it will be smart enough to know what to do + int ret = videoStore->writePacket( &packet ); + if ( ret < 0 ) { //Less than zero and we skipped a frame + Warning("problem writing packet"); } } + } // end if deinterlacing - if ( capture_image->Size() > camera->ImageSize() ) { - Error( "Captured image %d does not match expected size %d check width, height and colour depth",capture_image->Size(),camera->ImageSize() ); - return( -1 ); + /* Deinterlacing */ + if ( deinterlacing_value == 1 ) { + capture_image->Deinterlace_Discard(); + } else if ( deinterlacing_value == 2 ) { + capture_image->Deinterlace_Linear(); + } else if ( deinterlacing_value == 3 ) { + capture_image->Deinterlace_Blend(); + } else if ( deinterlacing_value == 4 ) { + capture_image->Deinterlace_4Field( next_buffer.image, (deinterlacing>>8)&0xff ); + } else if ( deinterlacing_value == 5 ) { + capture_image->Deinterlace_Blend_CustomRatio( (deinterlacing>>8)&0xff ); + } + + if ( orientation != ROTATE_0 ) { + switch ( orientation ) { + case ROTATE_0 : { + // No action required + break; + } + case ROTATE_90 : + case ROTATE_180 : + case ROTATE_270 : { + capture_image->Rotate( (orientation-1)*90 ); + break; + } + case FLIP_HORI : + case FLIP_VERT : { + capture_image->Flip( orientation==FLIP_HORI ); + break; + } } + } - if ( (index == shared_data->last_read_index) && (function > MONITOR) ) { - Warning( "Buffer overrun at index %d, image %d, slow down capture, speed up analysis or increase ring buffer size", index, image_count ); - time_t now = time(0); - double approxFps = double(image_buffer_count)/double(now-image_buffer[index].timestamp->tv_sec); - time_t last_read_delta = now - shared_data->last_read_time; - if ( last_read_delta > (image_buffer_count/approxFps) ) { - Warning( "Last image read from shared memory %ld seconds ago, zma may have gone away", last_read_delta ) + if ( capture_image->Size() > camera->ImageSize() ) { + Error( "Captured image %d does not match expected size %d check width, height and colour depth",capture_image->Size(),camera->ImageSize() ); + return( -1 ); + } + + if ( (index == shared_data->last_read_index) && (function > MONITOR) ) { + Warning( "Buffer overrun at index %d, image %d, slow down capture, speed up analysis or increase ring buffer size", index, image_count ); + time_t now = time(0); + double approxFps = double(image_buffer_count)/double(now-image_buffer[index].timestamp->tv_sec); + time_t last_read_delta = now - shared_data->last_read_time; + if ( last_read_delta > (image_buffer_count/approxFps) ) { + Warning( "Last image read from shared memory %ld seconds ago, zma may have gone away", last_read_delta ) shared_data->last_read_index = image_buffer_count; - } + } + } + + if ( privacy_bitmask ) + capture_image->MaskPrivacy( privacy_bitmask ); + + gettimeofday( image_buffer[index].timestamp, NULL ); + if ( config.timestamp_on_capture ) { + TimestampImage( capture_image, image_buffer[index].timestamp ); + } + shared_data->signal = CheckSignal(capture_image); + shared_data->last_write_index = index; + shared_data->last_write_time = image_buffer[index].timestamp->tv_sec; + + image_count++; + + if ( image_count && fps_report_interval && !(image_count%fps_report_interval) ) { + struct timeval now; + if ( !captureResult ) { + gettimeofday( &now, NULL ); + } else { + now.tv_sec = image_buffer[index].timestamp->tv_sec; } - if ( privacy_bitmask ) - capture_image->MaskPrivacy( privacy_bitmask ); - - gettimeofday( image_buffer[index].timestamp, NULL ); - if ( config.timestamp_on_capture ) { - TimestampImage( capture_image, image_buffer[index].timestamp ); - } - shared_data->signal = CheckSignal(capture_image); - shared_data->last_write_index = index; - shared_data->last_write_time = image_buffer[index].timestamp->tv_sec; - - image_count++; - - if ( image_count && fps_report_interval && !(image_count%fps_report_interval) ) { - time_t now = image_buffer[index].timestamp->tv_sec; - fps = double(fps_report_interval)/(now-last_fps_time); + // If we are too fast, we get div by zero. This seems to happen in the case of audio packets. + if ( now.tv_sec != last_fps_time ) { + fps = double(fps_report_interval)/(now.tv_sec-last_fps_time); //Info( "%d -> %d -> %d", fps_report_interval, now, last_fps_time ); //Info( "%d -> %d -> %lf -> %lf", now-last_fps_time, fps_report_interval/(now-last_fps_time), double(fps_report_interval)/(now-last_fps_time), fps ); Info( "%s: %d - Capturing at %.2lf fps", name, image_count, fps ); - last_fps_time = now; + last_fps_time = now.tv_sec; static char sql[ZM_SQL_SML_BUFSIZ]; snprintf( sql, sizeof(sql), "UPDATE Monitors SET CaptureFPS = '%.2lf' WHERE Id = '%d'", fps, id ); if ( mysql_query( &dbconn, sql ) ) { Error( "Can't run query: %s", mysql_error( &dbconn ) ); } - } + } // end if too fast + } // end if should report fps - // Icon: I'm not sure these should be here. They have nothing to do with capturing - if ( shared_data->action & GET_SETTINGS ) { - shared_data->brightness = camera->Brightness(); - shared_data->hue = camera->Hue(); - shared_data->colour = camera->Colour(); - shared_data->contrast = camera->Contrast(); - shared_data->action &= ~GET_SETTINGS; - } - if ( shared_data->action & SET_SETTINGS ) { - camera->Brightness( shared_data->brightness ); - camera->Hue( shared_data->hue ); - camera->Colour( shared_data->colour ); - camera->Contrast( shared_data->contrast ); - shared_data->action &= ~SET_SETTINGS; - } - return( 0 ); - } // end if captureResults == 1 which is success I think - shared_data->signal = false; - return( -1 ); + // Icon: I'm not sure these should be here. They have nothing to do with capturing + if ( shared_data->action & GET_SETTINGS ) { + shared_data->brightness = camera->Brightness(); + shared_data->hue = camera->Hue(); + shared_data->colour = camera->Colour(); + shared_data->contrast = camera->Contrast(); + shared_data->action &= ~GET_SETTINGS; + } + if ( shared_data->action & SET_SETTINGS ) { + camera->Brightness( shared_data->brightness ); + camera->Hue( shared_data->hue ); + camera->Colour( shared_data->colour ); + camera->Contrast( shared_data->contrast ); + shared_data->action &= ~SET_SETTINGS; + } + return captureResult; } void Monitor::TimestampImage( Image *ts_image, const struct timeval *ts_time ) const { diff --git a/src/zm_monitor.h b/src/zm_monitor.h index c28bc389f..23d665f50 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -29,6 +29,9 @@ #include "zm_rgb.h" #include "zm_zone.h" #include "zm_event.h" +#include "zm_videostore.h" +#include "zm_packetqueue.h" + class Monitor; #include "zm_camera.h" #include "zm_storage.h" @@ -102,7 +105,7 @@ protected: uint32_t last_write_index; /* +4 */ uint32_t last_read_index; /* +8 */ uint32_t state; /* +12 */ - uint32_t last_event; /* +16 */ + uint32_t last_event_id; /* +16 */ uint32_t action; /* +20 */ int32_t brightness; /* +24 */ int32_t hue; /* +28 */ @@ -158,7 +161,6 @@ protected: }; //TODO: Technically we can't exclude this struct when people don't have avformat as the Memory.pm module doesn't know about avformat -#if 1 //sizeOf(VideoStoreData) expected to be 4104 bytes on 32bit and 64bit typedef struct { uint32_t size; @@ -168,7 +170,8 @@ protected: //uint32_t frameNumber; } VideoStoreData; -#endif // HAVE_LIBAVFORMAT + VideoStore *videoStore; + zm_packetqueue packetqueue; class MonitorLink { protected: @@ -192,7 +195,7 @@ protected: volatile VideoStoreData *video_store_data; int last_state; - int last_event; + int last_event_id; public: @@ -434,7 +437,7 @@ public: const std::vector* GetOptEncoderParams() const { return( &encoderparamsvec ); } const std::string &GetEncoderOptions() const { return( encoderparams ); } - uint32_t GetLastEventId() const { return shared_data->last_event; } + uint32_t GetLastEventId() const { return shared_data->last_event_id; } uint32_t GetVideoWriterEventId() const { return video_store_data->current_event; } void SetVideoWriterEventId( uint32_t p_event_id ) { video_store_data->current_event = p_event_id; } diff --git a/src/zm_packet.cpp b/src/zm_packet.cpp index 7c08d4158..e9fcf9c58 100644 --- a/src/zm_packet.cpp +++ b/src/zm_packet.cpp @@ -24,23 +24,140 @@ using namespace std; +ZMPacket::ZMPacket( ) { + keyframe = 0; + image = NULL; + frame = NULL; + av_init_packet( &packet ); + packet.size = 0; + gettimeofday( ×tamp, NULL ); +} + +ZMPacket::ZMPacket( Image *i ) { + keyframe = 1; + image = i; + frame = NULL; + av_init_packet( &packet ); + gettimeofday( ×tamp, NULL ); +} + ZMPacket::ZMPacket( AVPacket *p ) { av_init_packet( &packet ); - if ( zm_av_packet_ref( &packet, p ) < 0 ) { - Error("error refing packet"); - } - gettimeofday( ×tamp, NULL ); + set_packet( p ); + keyframe = p->flags & AV_PKT_FLAG_KEY; } ZMPacket::ZMPacket( AVPacket *p, struct timeval *t ) { av_init_packet( &packet ); - if ( zm_av_packet_ref( &packet, p ) < 0 ) { - Error("error refing packet"); - } + set_packet( p ); timestamp = *t; + keyframe = p->flags & AV_PKT_FLAG_KEY; +} +ZMPacket::ZMPacket( AVPacket *p, AVFrame *f, Image *i ) { + av_init_packet( &packet ); + set_packet( p ); + image = i; + frame = f; } ZMPacket::~ZMPacket() { zm_av_packet_unref( &packet ); + if ( frame ) { + av_frame_free( &frame ); + } + image = NULL; + //if ( image ) { + //delete image; + //} } +int ZMPacket::decode( AVCodecContext *ctx ) { + Debug(4, "about to decode video" ); + + if ( frame ) { + Error("Already have a frame?"); + } else { + frame = zm_av_frame_alloc(); + } + +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + int ret = avcodec_send_packet( ctx, &packet ); + if ( ret < 0 ) { + Error( "Unable to send packet: %s", av_make_error_string(ret).c_str() ); + av_frame_free( &frame ); + return 0; + } + +#if HAVE_AVUTIL_HWCONTEXT_H + if ( hwaccel ) { + ret = avcodec_receive_frame( ctx, hwFrame ); + if ( ret < 0 ) { + Error( "Unable to receive frame: %s", av_make_error_string(ret).c_str() ); + av_frame_free( &frame ); + return 0; + } + ret = av_hwframe_transfer_data(frame, hwFrame, 0); + if ( ret < 0 ) { + Error( "Unable to transfer frame: %s", av_make_error_string(ret).c_str() ); + av_frame_free( &frame ); + return 0; + } + } else { +#endif + ret = avcodec_receive_frame( ctx, frame ); + if ( ret < 0 ) { + Error( "Unable to receive frame: %s", av_make_error_string(ret).c_str() ); + av_frame_free( &frame ); + return 0; + } + +#if HAVE_AVUTIL_HWCONTEXT_H + } +#endif + +# else + int frameComplete = 0; + int ret = zm_avcodec_decode_video( ctx, frame, &frameComplete, &packet ); + if ( ret < 0 ) { + Error( "Unable to decode frame at frame %s", av_make_error_string(ret).c_str() ); + av_frame_free( &frame ); + return 0; + } + if ( ! frameComplete ) { + Debug(1, "incomplete frame?"); + av_frame_free( &frame ); + return 0; + } +#endif + return 1; +} // end ZMPacket::decode + +Image * ZMPacket::get_image( Image *i = NULL ) { + if ( ! frame ) { + Error("Can't get image without frame.. maybe need to decode first"); + return NULL; + } + if ( ! image ) { + if ( ! i ) { + Error("Need a pre-allocated image buffer"); + return NULL; + } + image = i; + } + image->Assign( frame ); + return image; +} + +Image *ZMPacket::set_image( Image *i ) { + image = i; + return image; +} + +AVPacket *ZMPacket::set_packet( AVPacket *p ) { + if ( zm_av_packet_ref( &packet, p ) < 0 ) { + Error("error refing packet"); + } + gettimeofday( ×tamp, NULL ); + keyframe = p->flags & AV_PKT_FLAG_KEY; + return &packet; +} diff --git a/src/zm_packet.h b/src/zm_packet.h index 1758b0106..bf1b65d4c 100644 --- a/src/zm_packet.h +++ b/src/zm_packet.h @@ -27,20 +27,33 @@ extern "C" { #ifdef __FreeBSD__ #include #endif // __FreeBSD__ + #include "zm_image.h" class ZMPacket { public: + int keyframe; AVPacket packet; // Input packet, undecoded - AVFrame *frame; // Input image, decoded + AVFrame *frame; // Input image, decoded Theoretically only filled if needed. Image *image; // Our internal image oject representing this frame struct timeval timestamp; public: AVPacket *av_packet() { return &packet; } + AVPacket *set_packet( AVPacket *p ) ; + AVFrame *av_frame() { return frame; } + Image *get_image( Image * ); + Image *set_image( Image * ); + + int is_keyframe() { return keyframe; }; + int decode( AVCodecContext *ctx ); ZMPacket( AVPacket *packet, struct timeval *timestamp ); ZMPacket( AVPacket *packet ); + ZMPacket( AVPacket *packet, AVFrame *frame, Image *image ); + ZMPacket( Image *image ); + ZMPacket(); ~ZMPacket(); + }; #endif /* ZM_PACKET_H */ diff --git a/src/zm_remote_camera.cpp b/src/zm_remote_camera.cpp index 6afc7251b..58d92b73d 100644 --- a/src/zm_remote_camera.cpp +++ b/src/zm_remote_camera.cpp @@ -103,6 +103,7 @@ int RemoteCamera::Read( int fd, char *buf, int size ) { int bytes_to_recv = size - ReceivedBytes; if ( SOCKET_BUF_SIZE < bytes_to_recv ) bytes_to_recv = SOCKET_BUF_SIZE; +//Debug(3, "Aiming to receive %d of %d bytes", bytes_to_recv, size ); bytes = recv(fd, &buf[ReceivedBytes], bytes_to_recv, 0); //socket, buffer, len, flags if ( bytes <= 0 ) { Error("RemoteCamera::Read Recv error. Closing Socket\n"); diff --git a/src/zm_remote_camera.h b/src/zm_remote_camera.h index a0d391d9b..545fce48f 100644 --- a/src/zm_remote_camera.h +++ b/src/zm_remote_camera.h @@ -87,10 +87,10 @@ public: virtual void Terminate() = 0; virtual int Connect() = 0; virtual int Disconnect() = 0; - virtual int PreCapture() = 0; - virtual int Capture( Image &image ) = 0; + virtual int PreCapture() { return 0; }; + virtual int PrimeCapture() { return 0; }; + virtual int Capture( ZMPacket &p ) = 0; virtual int PostCapture() = 0; - virtual int CaptureAndRecord( Image &image, timeval recording, char* event_directory )=0; int Read( int fd, char*buf, int size ); }; diff --git a/src/zm_remote_camera_http.cpp b/src/zm_remote_camera_http.cpp index 95c8ae507..56b3e459e 100644 --- a/src/zm_remote_camera_http.cpp +++ b/src/zm_remote_camera_http.cpp @@ -75,26 +75,22 @@ RemoteCameraHttp::RemoteCameraHttp( method = REGEXP; else Fatal( "Unrecognised method '%s' when creating HTTP camera %d", p_method.c_str(), monitor_id ); - if ( capture ) - { + if ( capture ) { Initialise(); } + video_stream = NULL; } -RemoteCameraHttp::~RemoteCameraHttp() -{ - if ( capture ) - { +RemoteCameraHttp::~RemoteCameraHttp() { + if ( capture ) { Terminate(); } } -void RemoteCameraHttp::Initialise() -{ +void RemoteCameraHttp::Initialise() { RemoteCamera::Initialise(); - if ( request.empty() ) - { + if ( request.empty() ) { request = stringtf( "GET %s HTTP/%s\r\n", path.c_str(), config.http_version ); request += stringtf( "User-Agent: %s/%s\r\n", config.http_ua, ZM_VERSION ); request += stringtf( "Host: %s\r\n", host.c_str()); @@ -106,8 +102,7 @@ void RemoteCameraHttp::Initialise() Debug( 2, "Request: %s", request.c_str() ); } - if ( !timeout.tv_sec ) - { + if ( !timeout.tv_sec ) { timeout.tv_sec = config.http_timeout/1000; timeout.tv_usec = (config.http_timeout%1000)*1000; } @@ -121,21 +116,17 @@ void RemoteCameraHttp::Initialise() state = HEADER; } -int RemoteCameraHttp::Connect() -{ +int RemoteCameraHttp::Connect() { struct addrinfo *p; - for(p = hp; p != NULL; p = p->ai_next) - { + for ( p = hp; p != NULL; p = p->ai_next ) { sd = socket( p->ai_family, p->ai_socktype, p->ai_protocol ); - if ( sd < 0 ) - { + if ( sd < 0 ) { Warning("Can't create socket: %s", strerror(errno) ); continue; } - if ( connect( sd, p->ai_addr, p->ai_addrlen ) < 0 ) - { + if ( connect( sd, p->ai_addr, p->ai_addrlen ) < 0 ) { close(sd); sd = -1; char buf[sizeof(struct in6_addr)]; @@ -151,7 +142,7 @@ int RemoteCameraHttp::Connect() break; } - if(p == NULL) { + if ( p == NULL ) { Error("Unable to connect to the remote camera, aborting"); return( -1 ); } @@ -160,16 +151,14 @@ int RemoteCameraHttp::Connect() return( sd ); } -int RemoteCameraHttp::Disconnect() -{ +int RemoteCameraHttp::Disconnect() { close( sd ); sd = -1; Debug( 3, "Disconnected from host" ); return( 0 ); } -int RemoteCameraHttp::SendRequest() -{ +int RemoteCameraHttp::SendRequest() { Debug( 2, "Sending request: %s", request.c_str() ); if ( write( sd, request.data(), request.length() ) < 0 ) { @@ -250,12 +239,12 @@ int RemoteCameraHttp::ReadData( Buffer &buffer, unsigned int bytes_expected ) { // There can be lots of bytes available. I've seen 4MB or more. This will vastly inflate our buffer size unnecessarily. if ( total_bytes_to_read > ZM_NETWORK_BUFSIZ ) { total_bytes_to_read = ZM_NETWORK_BUFSIZ; - Debug(3, "Just getting 32K" ); + Debug(4, "Just getting 32K" ); } else { - Debug(3, "Just getting %d", total_bytes_to_read ); + Debug(4, "Just getting %d", total_bytes_to_read ); } } // end if bytes_expected or not - Debug( 3, "Expecting %d bytes", total_bytes_to_read ); + Debug( 4, "Expecting %d bytes", total_bytes_to_read ); int total_bytes_read = 0; do { @@ -281,12 +270,10 @@ int RemoteCameraHttp::ReadData( Buffer &buffer, unsigned int bytes_expected ) { return( total_bytes_read ); } -int RemoteCameraHttp::GetResponse() -{ +int RemoteCameraHttp::GetResponse() { int buffer_len; #if HAVE_LIBPCRE - if ( method == REGEXP ) - { + if ( method == REGEXP ) { const char *header = 0; int header_len = 0; const char *http_version = 0; @@ -301,10 +288,8 @@ int RemoteCameraHttp::GetResponse() //int subcontent_length = 0; //const char *subcontent_type = ""; - while ( true ) - { - switch( state ) - { + while ( true ) { + switch( state ) { case HEADER : { static RegExpr *header_expr = 0; @@ -322,16 +307,14 @@ int RemoteCameraHttp::GetResponse() } if ( !header_expr ) header_expr = new RegExpr( "^(.+?\r?\n\r?\n)", PCRE_DOTALL ); - if ( header_expr->Match( (char*)buffer, buffer.size() ) == 2 ) - { + if ( header_expr->Match( (char*)buffer, buffer.size() ) == 2 ) { header = header_expr->MatchString( 1 ); header_len = header_expr->MatchLength( 1 ); Debug( 4, "Captured header (%d bytes):\n'%s'", header_len, header ); if ( !status_expr ) status_expr = new RegExpr( "^HTTP/(1\\.[01]) +([0-9]+) +(.+?)\r?\n", PCRE_CASELESS ); - if ( status_expr->Match( header, header_len ) < 4 ) - { + if ( status_expr->Match( header, header_len ) < 4 ) { Error( "Unable to extract HTTP status from header" ); return( -1 ); } @@ -370,59 +353,47 @@ int RemoteCameraHttp::GetResponse() if ( !connection_expr ) connection_expr = new RegExpr( "Connection: ?(.+?)\r?\n", PCRE_CASELESS ); - if ( connection_expr->Match( header, header_len ) == 2 ) - { + if ( connection_expr->Match( header, header_len ) == 2 ) { connection_type = connection_expr->MatchString( 1 ); Debug( 3, "Got connection '%s'", connection_type ); } if ( !content_length_expr ) content_length_expr = new RegExpr( "Content-length: ?([0-9]+)\r?\n", PCRE_CASELESS ); - if ( content_length_expr->Match( header, header_len ) == 2 ) - { + if ( content_length_expr->Match( header, header_len ) == 2 ) { content_length = atoi( content_length_expr->MatchString( 1 ) ); Debug( 3, "Got content length '%d'", content_length ); } if ( !content_type_expr ) content_type_expr = new RegExpr( "Content-type: ?(.+?)(?:; ?boundary=\x22?(.+?)\x22?)?\r?\n", PCRE_CASELESS ); - if ( content_type_expr->Match( header, header_len ) >= 2 ) - { + if ( content_type_expr->Match( header, header_len ) >= 2 ) { content_type = content_type_expr->MatchString( 1 ); Debug( 3, "Got content type '%s'\n", content_type ); - if ( content_type_expr->MatchCount() > 2 ) - { + if ( content_type_expr->MatchCount() > 2 ) { content_boundary = content_type_expr->MatchString( 2 ); Debug( 3, "Got content boundary '%s'", content_boundary ); } } - if ( !strcasecmp( content_type, "image/jpeg" ) || !strcasecmp( content_type, "image/jpg" ) ) - { + if ( !strcasecmp( content_type, "image/jpeg" ) || !strcasecmp( content_type, "image/jpg" ) ) { // Single image mode = SINGLE_IMAGE; format = JPEG; state = CONTENT; - } - else if ( !strcasecmp( content_type, "image/x-rgb" ) ) - { + } else if ( !strcasecmp( content_type, "image/x-rgb" ) ) { // Single image mode = SINGLE_IMAGE; format = X_RGB; state = CONTENT; - } - else if ( !strcasecmp( content_type, "image/x-rgbz" ) ) - { + } else if ( !strcasecmp( content_type, "image/x-rgbz" ) ) { // Single image mode = SINGLE_IMAGE; format = X_RGBZ; state = CONTENT; - } - else if ( !strcasecmp( content_type, "multipart/x-mixed-replace" ) ) - { + } else if ( !strcasecmp( content_type, "multipart/x-mixed-replace" ) ) { // Image stream, so start processing - if ( !content_boundary[0] ) - { + if ( !content_boundary[0] ) { Error( "No content boundary found in header '%s'", header ); return( -1 ); } @@ -433,15 +404,12 @@ int RemoteCameraHttp::GetResponse() //{ //// MPEG stream, coming soon! //} - else - { + else { Error( "Unrecognised content type '%s'", content_type ); return( -1 ); } buffer.consume( header_len ); - } - else - { + } else { Debug( 3, "Unable to extract header from stream, retrying" ); //return( -1 ); } @@ -453,39 +421,33 @@ int RemoteCameraHttp::GetResponse() static RegExpr *subcontent_length_expr = 0; static RegExpr *subcontent_type_expr = 0; - if ( !subheader_expr ) - { + if ( !subheader_expr ) { char subheader_pattern[256] = ""; snprintf( subheader_pattern, sizeof(subheader_pattern), "^((?:\r?\n){0,2}?(?:--)?%s\r?\n.+?\r?\n\r?\n)", content_boundary ); subheader_expr = new RegExpr( subheader_pattern, PCRE_DOTALL ); } - if ( subheader_expr->Match( (char *)buffer, (int)buffer ) == 2 ) - { + if ( subheader_expr->Match( (char *)buffer, (int)buffer ) == 2 ) { subheader = subheader_expr->MatchString( 1 ); subheader_len = subheader_expr->MatchLength( 1 ); Debug( 4, "Captured subheader (%d bytes):'%s'", subheader_len, subheader ); if ( !subcontent_length_expr ) subcontent_length_expr = new RegExpr( "Content-length: ?([0-9]+)\r?\n", PCRE_CASELESS ); - if ( subcontent_length_expr->Match( subheader, subheader_len ) == 2 ) - { + if ( subcontent_length_expr->Match( subheader, subheader_len ) == 2 ) { content_length = atoi( subcontent_length_expr->MatchString( 1 ) ); Debug( 3, "Got subcontent length '%d'", content_length ); } if ( !subcontent_type_expr ) subcontent_type_expr = new RegExpr( "Content-type: ?(.+?)\r?\n", PCRE_CASELESS ); - if ( subcontent_type_expr->Match( subheader, subheader_len ) == 2 ) - { + if ( subcontent_type_expr->Match( subheader, subheader_len ) == 2 ) { content_type = subcontent_type_expr->MatchString( 1 ); Debug( 3, "Got subcontent type '%s'", content_type ); } buffer.consume( subheader_len ); state = CONTENT; - } - else - { + } else { Debug( 3, "Unable to extract subheader from stream, retrying" ); while ( ! ( buffer_len = ReadData( buffer ) ) ) { Debug(4, "Timeout waiting to extract subheader"); @@ -506,28 +468,19 @@ int RemoteCameraHttp::GetResponse() *semicolon = '\0'; } - if ( !strcasecmp( content_type, "image/jpeg" ) || !strcasecmp( content_type, "image/jpg" ) ) - { + if ( !strcasecmp( content_type, "image/jpeg" ) || !strcasecmp( content_type, "image/jpg" ) ) { format = JPEG; - } - else if ( !strcasecmp( content_type, "image/x-rgb" ) ) - { + } else if ( !strcasecmp( content_type, "image/x-rgb" ) ) { format = X_RGB; - } - else if ( !strcasecmp( content_type, "image/x-rgbz" ) ) - { + } else if ( !strcasecmp( content_type, "image/x-rgbz" ) ) { format = X_RGBZ; - } - else - { + } else { Error( "Found unsupported content type '%s'", content_type ); return( -1 ); } - if ( content_length ) - { - while ( (long)buffer.size() < content_length ) - { + if ( content_length ) { + while ( (long)buffer.size() < content_length ) { Debug(3, "Need more data buffer %d < content length %d", buffer.size(), content_length ); if ( ReadData( buffer ) < 0 ) { Error( "Unable to read content" ); @@ -535,42 +488,33 @@ int RemoteCameraHttp::GetResponse() } } Debug( 3, "Got end of image by length, content-length = %d", content_length ); - } - else - { - while ( !content_length ) - { + } else { + while ( !content_length ) { while ( ! ( buffer_len = ReadData( buffer ) ) ) { - Debug(4, "Timeout waiting for content"); + Debug(4, "Timeout waiting for content"); } if ( buffer_len < 0 ) { Error( "Unable to read content" ); return( -1 ); } static RegExpr *content_expr = 0; - if ( mode == MULTI_IMAGE ) - { - if ( !content_expr ) - { + if ( mode == MULTI_IMAGE ) { + if ( !content_expr ) { char content_pattern[256] = ""; snprintf( content_pattern, sizeof(content_pattern), "^(.+?)(?:\r?\n)*(?:--)?%s\r?\n", content_boundary ); content_expr = new RegExpr( content_pattern, PCRE_DOTALL ); } - if ( content_expr->Match( buffer, buffer.size() ) == 2 ) - { + if ( content_expr->Match( buffer, buffer.size() ) == 2 ) { content_length = content_expr->MatchLength( 1 ); Debug( 3, "Got end of image by pattern, content-length = %d", content_length ); } } } } - if ( mode == SINGLE_IMAGE ) - { + if ( mode == SINGLE_IMAGE ) { state = HEADER; Disconnect(); - } - else - { + } else { state = SUBHEADER; } Debug( 3, "Returning %d (%d) bytes of captured content", content_length, buffer.size() ); @@ -584,12 +528,10 @@ int RemoteCameraHttp::GetResponse() } } } - } - else + } else #endif // HAVE_LIBPCRE { - if ( method == REGEXP ) - { + if ( method == REGEXP ) { Warning( "Unable to use netcam regexps as not compiled with libpcre" ); } static const char *http_match = "HTTP/"; @@ -1061,92 +1003,87 @@ int RemoteCameraHttp::GetResponse() } } return( 0 ); -} +} // end RemoteCameraHttp::GetResponse -int RemoteCameraHttp::PreCapture() -{ - if ( sd < 0 ) - { +int RemoteCameraHttp::PreCapture() { + if ( sd < 0 ) { Connect(); - if ( sd < 0 ) - { + if ( sd < 0 ) { Error( "Unable to connect to camera" ); return( -1 ); } mode = SINGLE_IMAGE; buffer.clear(); } - if ( mode == SINGLE_IMAGE ) - { - if ( SendRequest() < 0 ) - { + if ( mode == SINGLE_IMAGE ) { + if ( SendRequest() < 0 ) { Error( "Unable to send request" ); Disconnect(); return( -1 ); } } return( 0 ); -} +} // end int RemoteCameraHttp::PreCapture() -int RemoteCameraHttp::Capture( Image &image ) -{ +int RemoteCameraHttp::Capture( ZMPacket &packet ) { int content_length = GetResponse(); - if ( content_length == 0 ) - { + if ( content_length == 0 ) { Warning( "Unable to capture image, retrying" ); - return( 1 ); + return 0; } - if ( content_length < 0 ) - { + if ( content_length < 0 ) { Error( "Unable to get response, disconnecting" ); Disconnect(); - return( -1 ); + return -1; } - switch( format ) - { + + Image *image = packet.image; + + switch( format ) { case JPEG : - { - if ( !image.DecodeJpeg( buffer.extract( content_length ), content_length, colours, subpixelorder ) ) - { - Error( "Unable to decode jpeg" ); - Disconnect(); - return( -1 ); - } - break; - } - case X_RGB : - { - if ( content_length != (long)image.Size() ) - { - Error( "Image length mismatch, expected %d bytes, content length was %d", image.Size(), content_length ); - Disconnect(); - return( -1 ); - } - image.Assign( width, height, colours, subpixelorder, buffer, imagesize ); - break; - } - case X_RGBZ : - { - if ( !image.Unzip( buffer.extract( content_length ), content_length ) ) - { - Error( "Unable to unzip RGB image" ); - Disconnect(); - return( -1 ); - } - image.Assign( width, height, colours, subpixelorder, buffer, imagesize ); - break; - } - default : - { - Error( "Unexpected image format encountered" ); + if ( !image->DecodeJpeg( buffer.extract( content_length ), content_length, colours, subpixelorder ) ) { + Error( "Unable to decode jpeg" ); Disconnect(); - return( -1 ); + return -1; } + break; + case X_RGB : + if ( content_length != (long)image->Size() ) { + Error( "Image length mismatch, expected %d bytes, content length was %d", image->Size(), content_length ); + Disconnect(); + return -1; + } + image->Assign( width, height, colours, subpixelorder, buffer, imagesize ); + break; + case X_RGBZ : + if ( !image->Unzip( buffer.extract( content_length ), content_length ) ) { + Error( "Unable to unzip RGB image" ); + Disconnect(); + return -1; + } + image->Assign( width, height, colours, subpixelorder, buffer, imagesize ); + break; + default : + Error( "Unexpected image format encountered" ); + Disconnect(); + return -1; } - return( 0 ); + return 1; +} // end ZmPacket *RmoteCameraHttp::Capture( &image ); + +int RemoteCameraHttp::PostCapture() { + return 0; } -int RemoteCameraHttp::PostCapture() -{ - return( 0 ); +AVStream *RemoteCameraHttp::get_VideoStream() { + if ( video_stream ) { + AVFormatContext *oc = avformat_alloc_context(); + video_stream = avformat_new_stream( oc, NULL ); + if ( video_stream ) { + video_stream->codec->width = width; + video_stream->codec->height = height; + video_stream->codec->pix_fmt = GetFFMPEGPixelFormat(colours,subpixelorder); + } + } + return video_stream; } diff --git a/src/zm_remote_camera_http.h b/src/zm_remote_camera_http.h index fe5823397..d2093c4d5 100644 --- a/src/zm_remote_camera_http.h +++ b/src/zm_remote_camera_http.h @@ -44,7 +44,22 @@ protected: enum { SIMPLE, REGEXP } method; public: - RemoteCameraHttp( unsigned int p_monitor_id, const std::string &method, const std::string &host, const std::string &port, const std::string &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 ); + RemoteCameraHttp( + unsigned int p_monitor_id, + const std::string &method, + const std::string &host, + const std::string &port, + const std::string &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 + ); ~RemoteCameraHttp(); void Initialise(); @@ -55,9 +70,9 @@ public: int ReadData( Buffer &buffer, unsigned int bytes_expected=0 ); int GetResponse(); int PreCapture(); - int Capture( Image &image ); + int Capture( ZMPacket &p ); int PostCapture(); - int CaptureAndRecord( Image &image, timeval recording, char* event_directory ) {return(0);}; +AVStream* get_VideoStream(); }; #endif // ZM_REMOTE_CAMERA_HTTP_H diff --git a/src/zm_remote_camera_nvsocket.cpp b/src/zm_remote_camera_nvsocket.cpp index 78f65bd92..88227735b 100644 --- a/src/zm_remote_camera_nvsocket.cpp +++ b/src/zm_remote_camera_nvsocket.cpp @@ -67,6 +67,7 @@ RemoteCameraNVSocket::RemoteCameraNVSocket( timeout.tv_sec = 0; timeout.tv_usec = 0; + subpixelorder = ZM_SUBPIX_ORDER_BGR; if ( capture ) { Initialise(); @@ -97,43 +98,39 @@ void RemoteCameraNVSocket::Initialise() { } int RemoteCameraNVSocket::Connect() { + int port_num = atoi(port.c_str()); //struct addrinfo *p; -struct sockaddr_in servaddr; - bzero( &servaddr, sizeof(servaddr)); - servaddr.sin_family = AF_INET; - servaddr.sin_addr.s_addr = htons(INADDR_ANY); - servaddr.sin_port = htons(atoi(port.c_str())); + struct sockaddr_in servaddr; + bzero( &servaddr, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = htons(INADDR_ANY); + servaddr.sin_port = htons(port_num); - - sd = socket(AF_INET, SOCK_STREAM, 0); + sd = socket(AF_INET, SOCK_STREAM, 0); //for(p = hp; p != NULL; p = p->ai_next) { - //sd = socket( p->ai_family, p->ai_socktype, p->ai_protocol ); - if ( sd < 0 ) { - Warning("Can't create socket: %s", strerror(errno) ); - //continue; - return -1; - } - - //if ( connect( sd, p->ai_addr, p->ai_addrlen ) < 0 ) { - if ( connect( sd, (struct sockaddr *)&servaddr , sizeof(servaddr) ) < 0 ) { - close(sd); - sd = -1; - - Warning("Can't connect to socket mid: %d : %s", monitor_id, strerror(errno) ); - return -1; - //continue; - //} - /* If we got here, we must have connected successfully */ - //break; + //sd = socket( p->ai_family, p->ai_socktype, p->ai_protocol ); + if ( sd < 0 ) { + Warning("Can't create socket: %s", strerror(errno) ); + //continue; + return -1; } - //if ( p == NULL ) { - //Error("Unable to connect to the remote camera, aborting"); - //return( -1 ); - //} + //if ( connect( sd, p->ai_addr, p->ai_addrlen ) < 0 ) { + if ( connect( sd, (struct sockaddr *)&servaddr , sizeof(servaddr) ) < 0 ) { + close(sd); + sd = -1; - Debug( 3, "Connected to host, socket = %d", sd ); - return( sd ); + Warning("Can't connect to socket mid: %d : %s", monitor_id, strerror(errno) ); + return -1; + } + +//if ( p == NULL ) { +//Error("Unable to connect to the remote camera, aborting"); +//return( -1 ); +//} + + Debug( 3, "Connected to host:%d, socket = %d", port_num, sd ); + return sd; } int RemoteCameraNVSocket::Disconnect() { @@ -144,132 +141,33 @@ int RemoteCameraNVSocket::Disconnect() { } int RemoteCameraNVSocket::SendRequest( std::string request ) { - Debug( 2, "Sending request: %s", request.c_str() ); + Debug( 4, "Sending request: %s", request.c_str() ); if ( write( sd, request.data(), request.length() ) < 0 ) { Error( "Can't write: %s", strerror(errno) ); Disconnect(); return( -1 ); } - Debug( 3, "Request sent" ); + Debug( 4, "Request sent" ); return( 0 ); } -/* Return codes are as follows: - * -1 means there was an error - * 0 means no bytes were returned but there wasn't actually an error. - * > 0 is the # of bytes read. - */ - -int RemoteCameraNVSocket::ReadData( Buffer &buffer, unsigned int bytes_expected ) { - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(sd, &rfds); - - struct timeval temp_timeout = timeout; - - int n_found = select(sd+1, &rfds, NULL, NULL, &temp_timeout); - if ( n_found == 0 ) { - Debug( 4, "Select timed out timeout was %d secs %d usecs", temp_timeout.tv_sec, temp_timeout.tv_usec ); - int error = 0; - socklen_t len = sizeof(error); - int retval = getsockopt(sd, SOL_SOCKET, SO_ERROR, &error, &len); - if ( retval != 0 ) { - Debug(1, "error getting socket error code %s", strerror(retval)); - } - if ( error != 0 ) { - return -1; - } - // Why are we disconnecting? It's just a timeout, meaning that data wasn't available. - //Disconnect(); - return 0; - } else if ( n_found < 0 ) { - Error("Select error: %s", strerror(errno)); - return -1; - } - - unsigned int total_bytes_to_read = 0; - - if ( bytes_expected ) { - total_bytes_to_read = bytes_expected; - } else { - if ( ioctl( sd, FIONREAD, &total_bytes_to_read ) < 0 ) { - Error( "Can't ioctl(): %s", strerror(errno) ); - return( -1 ); - } - - if ( total_bytes_to_read == 0 ) { - if ( mode == SINGLE_IMAGE ) { - int error = 0; - socklen_t len = sizeof (error); - int retval = getsockopt( sd, SOL_SOCKET, SO_ERROR, &error, &len ); - if(retval != 0 ) { - Debug( 1, "error getting socket error code %s", strerror(retval) ); - } - if (error != 0) { - return -1; - } - // Case where we are grabbing a single jpg, but no content-length was given, so the expectation is that we read until close. - return( 0 ); - } - // If socket is closed locally, then select will fail, but if it is closed remotely - // then we have an exception on our socket.. but no data. - Debug( 3, "Socket closed remotely" ); - //Disconnect(); // Disconnect is done outside of ReadData now. - return( -1 ); - } - - // There can be lots of bytes available. I've seen 4MB or more. This will vastly inflate our buffer size unnecessarily. - if ( total_bytes_to_read > ZM_NETWORK_BUFSIZ ) { - total_bytes_to_read = ZM_NETWORK_BUFSIZ; - Debug(3, "Just getting 32K" ); - } else { - Debug(3, "Just getting %d", total_bytes_to_read ); - } - } // end if bytes_expected or not - Debug( 3, "Expecting %d bytes", total_bytes_to_read ); - - int total_bytes_read = 0; - do { - int bytes_read = buffer.read_into( sd, total_bytes_to_read ); - if ( bytes_read < 0 ) { - Error( "Read error: %s", strerror(errno) ); - return( -1 ); - } else if ( bytes_read == 0 ) { - Debug( 2, "Socket closed" ); - //Disconnect(); // Disconnect is done outside of ReadData now. - return( -1 ); - } else if ( (unsigned int)bytes_read < total_bytes_to_read ) { - Error( "Incomplete read, expected %d, got %d", total_bytes_to_read, bytes_read ); - return( -1 ); - } - Debug( 3, "Read %d bytes", bytes_read ); - total_bytes_read += bytes_read; - total_bytes_to_read -= bytes_read; - } while ( total_bytes_to_read ); - - Debug( 4, buffer ); - - return( total_bytes_read ); -} - -int RemoteCameraNVSocket::PreCapture() { +int RemoteCameraNVSocket::PrimeCapture() { if ( sd < 0 ) { Connect(); if ( sd < 0 ) { Error( "Unable to connect to camera" ); return( -1 ); } - mode = SINGLE_IMAGE; - buffer.clear(); } -struct image_def { - uint16_t width; - uint16_t height; - uint16_t type; -}; -struct image_def image_def; + buffer.clear(); + struct image_def { + uint16_t width; + uint16_t height; + uint16_t type; + }; + struct image_def image_def; - if ( SendRequest("GetImageParams") < 0 ) { + if ( SendRequest("GetImageParams\n") < 0 ) { Error( "Unable to send request" ); Disconnect(); return -1; @@ -288,21 +186,29 @@ struct image_def image_def; return 0; } -int RemoteCameraNVSocket::Capture( Image &image ) { - if ( SendRequest("GetNextImage") < 0 ) { +int RemoteCameraNVSocket::Capture( ZMPacket &zm_packet ) { + if ( SendRequest("GetNextImage\n") < 0 ) { Warning( "Unable to capture image, retrying" ); - return( 1 ); + return 0; } if ( Read( sd, buffer, imagesize ) < imagesize ) { Warning( "Unable to capture image, retrying" ); - return( 1 ); + return 0; + } + uint32_t end; + if ( Read(sd, (char *) &end , sizeof(end)) < 0 ) { + Warning( "Unable to capture image, retrying" ); + return 0; + } + if ( end != 0xFFFFFFFF) { + Warning("End Bytes Failed\n"); + return 0; } - image.Assign( width, height, colours, subpixelorder, buffer, imagesize ); - return( 0 ); + zm_packet.image->Assign( width, height, colours, subpixelorder, buffer, imagesize ); + return 1; } -int RemoteCameraNVSocket::PostCapture() -{ +int RemoteCameraNVSocket::PostCapture() { return( 0 ); } diff --git a/src/zm_remote_camera_nvsocket.h b/src/zm_remote_camera_nvsocket.h index 4f62bafe3..990d34aec 100644 --- a/src/zm_remote_camera_nvsocket.h +++ b/src/zm_remote_camera_nvsocket.h @@ -65,12 +65,10 @@ bool p_record_audio ); int Connect(); int Disconnect(); int SendRequest( std::string ); - int ReadData( Buffer &buffer, unsigned int bytes_expected=0 ); int GetResponse(); - int PreCapture(); - int Capture( Image &image ); + int PrimeCapture(); + int Capture( ZMPacket &p ); int PostCapture(); - int CaptureAndRecord( Image &image, timeval recording, char* event_directory ) {return(0);}; }; #endif // ZM_REMOTE_CAMERA_NVSOCKET_H diff --git a/src/zm_remote_camera_rtsp.cpp b/src/zm_remote_camera_rtsp.cpp index 9b0b6b41d..2ca51596d 100644 --- a/src/zm_remote_camera_rtsp.cpp +++ b/src/zm_remote_camera_rtsp.cpp @@ -63,13 +63,13 @@ RemoteCameraRtsp::RemoteCameraRtsp( unsigned int p_monitor_id, const std::string mConvertContext = NULL; #endif /* Has to be located inside the constructor so other components such as zma will receive correct colours and subpixel order */ - if(colours == ZM_COLOUR_RGB32) { + if ( colours == ZM_COLOUR_RGB32 ) { subpixelorder = ZM_SUBPIX_ORDER_RGBA; imagePixFormat = AV_PIX_FMT_RGBA; - } else if(colours == ZM_COLOUR_RGB24) { + } else if ( colours == ZM_COLOUR_RGB24 ) { subpixelorder = ZM_SUBPIX_ORDER_RGB; imagePixFormat = AV_PIX_FMT_RGB24; - } else if(colours == ZM_COLOUR_GRAY8) { + } else if ( colours == ZM_COLOUR_GRAY8 ) { subpixelorder = ZM_SUBPIX_ORDER_NONE; imagePixFormat = AV_PIX_FMT_GRAY8; } else { @@ -154,13 +154,19 @@ int RemoteCameraRtsp::PrimeCapture() { // Find first video stream present mVideoStreamId = -1; mAudioStreamId = -1; + // Find the first video stream. 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 LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + AVCodecParameters *codec_context = mFormatContext->streams[i]->codecpar; #else - if ( mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO ) + AVCodecContext *codec_context = mFormatContext->streams[i]->codec; +#endif +#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) + if ( codec_context->codec_type == AVMEDIA_TYPE_VIDEO ) +#else + if ( codec_context->codec_type == CODEC_TYPE_VIDEO ) #endif { if ( mVideoStreamId == -1 ) { @@ -171,9 +177,9 @@ int RemoteCameraRtsp::PrimeCapture() { } } #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 ) + if ( codec_context->codec_type == AVMEDIA_TYPE_AUDIO ) #else - if ( mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO ) + if ( codec_context->codec_type == CODEC_TYPE_AUDIO ) #endif { if ( mAudioStreamId == -1 ) { @@ -190,7 +196,12 @@ int RemoteCameraRtsp::PrimeCapture() { Debug( 3, "Unable to locate audio stream" ); // Get a pointer to the codec context for the video stream +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + mCodecContext = avcodec_alloc_context3(NULL); + avcodec_parameters_to_context(mCodecContext, mFormatContext->streams[mVideoStreamId]->codecpar); +#else mCodecContext = mFormatContext->streams[mVideoStreamId]->codec; +#endif // Find the decoder for the video stream mCodec = avcodec_find_decoder( mCodecContext->codec_id ); @@ -219,7 +230,7 @@ int RemoteCameraRtsp::PrimeCapture() { mFrame = avcodec_alloc_frame(); #endif - if(mRawFrame == NULL || mFrame == NULL) + if ( mRawFrame == NULL || mFrame == NULL ) Fatal( "Unable to allocate frame(s)"); #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) @@ -231,6 +242,14 @@ int RemoteCameraRtsp::PrimeCapture() { if ( (unsigned int)pSize != imagesize ) { Fatal("Image size mismatch. Required: %d Available: %d",pSize,imagesize); } + +#if HAVE_LIBSWSCALE + mConvertContext = sws_getContext( mCodecContext->width, mCodecContext->height, mCodecContext->pix_fmt, width, height, imagePixFormat, SWS_BICUBIC, NULL, NULL, NULL ); + if ( mConvertContext == NULL ) + Fatal( "Unable to create conversion context"); +#else // HAVE_LIBSWSCALE + Fatal( "You must compile ffmpeg with the --enable-swscale option to use RTSP cameras" ); +#endif // HAVE_LIBSWSCALE /* #if HAVE_LIBSWSCALE if(!sws_isSupportedInput(mCodecContext->pix_fmt)) { @@ -259,22 +278,22 @@ int RemoteCameraRtsp::PreCapture() { return( 0 ); } -int RemoteCameraRtsp::Capture( Image &image ) { - AVPacket packet; +int RemoteCameraRtsp::Capture( ZMPacket &zm_packet ) { uint8_t* directbuffer; int frameComplete = false; + AVPacket *packet = &zm_packet.packet; /* Request a writeable buffer of the target image */ - directbuffer = image.WriteBuffer(width, height, colours, subpixelorder); - if(directbuffer == NULL) { + directbuffer = zm_packet.image->WriteBuffer(width, height, colours, subpixelorder); + if ( directbuffer == NULL ) { Error("Failed requesting writeable buffer for the captured image."); - return (-1); + return -1; } - while ( true ) { + while ( !frameComplete ) { buffer.clear(); if ( !rtspThread->isRunning() ) - return (-1); + return -1; if ( rtspThread->getFrame( buffer ) ) { Debug( 3, "Read frame %d bytes", buffer.size() ); @@ -282,21 +301,21 @@ int RemoteCameraRtsp::Capture( Image &image ) { Hexdump( 4, buffer.head(), 16 ); if ( !buffer.size() ) - return( -1 ); + return -1; - if(mCodecContext->codec_id == AV_CODEC_ID_H264) { + if ( mCodecContext->codec_id == AV_CODEC_ID_H264 ) { // SPS and PPS frames should be saved and appended to IDR frames int nalType = (buffer.head()[3] & 0x1f); // SPS The SPS NAL unit contains parameters that apply to a series of consecutive coded video pictures - if(nalType == 7) { + if ( nalType == 7 ) { lastSps = buffer; continue; - } else if(nalType == 8) { + } else if ( nalType == 8 ) { // PPS The PPS NAL unit contains parameters that apply to the decoding of one or more individual pictures inside a coded video sequence lastPps = buffer; continue; - } else if(nalType == 5) { + } else if ( nalType == 5 ) { // IDR buffer += lastSps; buffer += lastPps; @@ -305,17 +324,18 @@ int RemoteCameraRtsp::Capture( Image &image ) { Debug(3, "Not an h264 packet"); } - av_init_packet( &packet ); + // Don't need to do this... as zmPacket does it. + //av_init_packet( &packet ); while ( !frameComplete && buffer.size() > 0 ) { - packet.data = buffer.head(); - packet.size = buffer.size(); + packet->data = buffer.head(); + packet->size = buffer.size(); // So I think this is the magic decode step. Result is a raw image? #if LIBAVCODEC_VERSION_CHECK(52, 23, 0, 23, 0) - int len = avcodec_decode_video2( mCodecContext, mRawFrame, &frameComplete, &packet ); + int len = avcodec_decode_video2( mCodecContext, mRawFrame, &frameComplete, packet ); #else - int len = avcodec_decode_video( mCodecContext, mRawFrame, &frameComplete, packet.data, packet.size ); + int len = avcodec_decode_video( mCodecContext, mRawFrame, &frameComplete, packet->data, packet->size ); #endif if ( len < 0 ) { Error( "Error while decoding frame %d", frameCount ); @@ -324,223 +344,27 @@ int RemoteCameraRtsp::Capture( Image &image ) { continue; } Debug( 2, "Frame: %d - %d/%d", frameCount, len, buffer.size() ); - //if ( buffer.size() < 400 ) - //Hexdump( 0, buffer.head(), buffer.size() ); - buffer -= len; } // At this point, we either have a frame or ran out of buffer. What happens if we run out of buffer? if ( frameComplete ) { - Debug( 3, "Got frame %d", frameCount ); avpicture_fill( (AVPicture *)mFrame, directbuffer, imagePixFormat, width, height ); - #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) - Fatal( "Unable to create conversion context"); - } - - 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 ); - #else // HAVE_LIBSWSCALE - Fatal( "You must compile ffmpeg with the --enable-swscale option to use RTSP cameras" ); - #endif // HAVE_LIBSWSCALE - - frameCount++; - - } /* frame complete */ - - zm_av_packet_unref( &packet ); - } /* getFrame() */ - - if(frameComplete) - return (0); - - } // end while true - - // can never get here. - return (0); -} - -//Function to handle capture and store - -int RemoteCameraRtsp::CaptureAndRecord(Image &image, timeval recording, char* event_file ) { - AVPacket packet; - uint8_t* directbuffer; - int frameComplete = false; - - while ( true ) { - -// WHY Are we clearing it? Might be something good in it. - buffer.clear(); - - if ( !rtspThread->isRunning() ) - return (-1); - - //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 - // Not sure why we are only doing this on keyframe, al - if ( videoStore && (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"); - if ( videoStore ) { - delete videoStore; - videoStore = NULL; - } - } // end if changed to new event - - if ( ! videoStore ) { - //Instantiate the video storage module - - videoStore = new VideoStore((const char *)event_file, "mp4", - mFormatContext->streams[mVideoStreamId], - mAudioStreamId==-1?NULL:mFormatContext->streams[mAudioStreamId], - startTime, - this->getMonitor() ); - strcpy(oldDirectory, event_file); - } // end if ! videoStore - - } else { - if ( videoStore ) { - Info("Deleting videoStore instance"); - delete videoStore; - videoStore = NULL; - } - } // end if recording or not - - if ( rtspThread->getFrame( buffer ) ) { - Debug( 3, "Read frame %d bytes", buffer.size() ); - Debug( 4, "Address %p", buffer.head() ); - Hexdump( 4, buffer.head(), 16 ); - - if ( !buffer.size() ) - return( -1 ); - - if ( mCodecContext->codec_id == AV_CODEC_ID_H264 ) { - // SPS and PPS frames should be saved and appended to IDR frames - int nalType = (buffer.head()[3] & 0x1f); - - // SPS - if(nalType == 7) { - lastSps = buffer; - continue; - } else if(nalType == 8) { - // PPS - lastPps = buffer; - continue; - } else if(nalType == 5) { - // IDR - buffer += lastSps; - buffer += lastPps; - } - } // end if H264, what about other codecs? - - av_init_packet( &packet ); - - // Keep decoding until a complete frame is had. - while ( !frameComplete && buffer.size() > 0 ) { - packet.data = buffer.head(); - packet.size = buffer.size(); - - // Why are we checking for it being the video stream? Because it might be audio or something else. - // Um... we just initialized packet... we can't be testing for what it is yet.... - if ( packet.stream_index == mVideoStreamId ) { - // So this does the decode -#if LIBAVCODEC_VERSION_CHECK(52, 23, 0, 23, 0) - int len = avcodec_decode_video2( mCodecContext, mRawFrame, &frameComplete, &packet ); -#else - int len = avcodec_decode_video( mCodecContext, mRawFrame, &frameComplete, packet.data, packet.size ); -#endif - if ( len < 0 ) { - Error( "Error while decoding frame %d", frameCount ); - Hexdump( Logger::ERROR, buffer.head(), buffer.size()>256?256:buffer.size() ); - buffer.clear(); - continue; - } - Debug( 2, "Frame: %d - %d/%d", frameCount, len, buffer.size() ); - //if ( buffer.size() < 400 ) - //Hexdump( 0, buffer.head(), buffer.size() ); - - buffer -= len; - - if ( frameComplete ) { - - Debug( 3, "Got frame %d", frameCount ); - - /* 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); -#else - avpicture_fill( (AVPicture *)mFrame, directbuffer, - imagePixFormat, width, height); -#endif - - } // endif frameComplete - - if ( videoStore ) { - //Write the packet to our video store - int ret = videoStore->writeVideoFramePacket(&packet);//, &lastKeyframePkt); - if ( ret < 0 ) {//Less than zero and we skipped a frame -// Should not - zm_av_packet_unref( &packet ); - return 0; - } - } // end if videoStore, so we are recording - -#if HAVE_LIBSWSCALE - // Why are we re-scaling after writing out the packet? - if ( mConvertContext == NULL ) { - mConvertContext = sws_getContext( mCodecContext->width, mCodecContext->height, mCodecContext->pix_fmt, width, height, imagePixFormat, SWS_BICUBIC, NULL, NULL, NULL ); - - if ( mConvertContext == NULL ) - Fatal( "Unable to create conversion context"); - } - + if ( mConvertContext == NULL ) { 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 ); -#else // HAVE_LIBSWSCALE - Fatal( "You must compile ffmpeg with the --enable-swscale option to use RTSP cameras" ); -#endif // HAVE_LIBSWSCALE - - frameCount++; - - } else if ( packet.stream_index == mAudioStreamId ) { - Debug( 4, "Got audio packet" ); - if ( videoStore && record_audio ) { - Debug( 4, "Storing Audio packet" ); - //Write the packet to our video store - int ret = videoStore->writeAudioFramePacket( &packet ); //FIXME no relevance of last key frame - if ( ret < 0 ) { //Less than zero and we skipped a frame - zm_av_packet_unref( &packet ); - return 0; - } } - } // end if video or audio packet - - zm_av_packet_unref( &packet ); - } // end while ! framecomplete and buffer.size() - if(frameComplete) - return (0); - } /* getFrame() */ + #endif + + frameCount++; + } /* frame complete */ + } /* getFrame() */ + } // end while true -} // end while true - -// can never get here. - return (0) ; -} // int RemoteCameraRtsp::CaptureAndRecord( Image &image, bool recording, char* event_file ) + return 1; +} // end int RemoteCameraRtsp::Capture(ZMPacket &packet) int RemoteCameraRtsp::PostCapture() { return( 0 ); diff --git a/src/zm_remote_camera_rtsp.h b/src/zm_remote_camera_rtsp.h index 8ed8b713c..ddc456cfc 100644 --- a/src/zm_remote_camera_rtsp.h +++ b/src/zm_remote_camera_rtsp.h @@ -34,8 +34,7 @@ // accessed over a network connection using rtsp protocol // (Real Time Streaming Protocol) // -class RemoteCameraRtsp : public RemoteCamera -{ +class RemoteCameraRtsp : public RemoteCamera { protected: struct sockaddr_in rtsp_sa; struct sockaddr_in rtcp_sa; @@ -84,9 +83,8 @@ public: int PrimeCapture(); int PreCapture(); - int Capture( Image &image ); + int Capture( ZMPacket &p ); int PostCapture(); - int CaptureAndRecord( Image &image, timeval recording, char* event_directory ); }; #endif // ZM_REMOTE_CAMERA_RTSP_H diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index bc6c49e6f..e8f472d88 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -32,34 +32,26 @@ extern "C" { } VideoStore::VideoStore( - const char *filename_in, const char *format_in, + const char *filename_in, + const char *format_in, AVStream *p_video_in_stream, - AVStream *p_audio_in_stream, int64_t nStartTime, + AVStream *p_audio_in_stream, + int64_t nStartTime, Monitor *monitor ) { video_in_stream = p_video_in_stream; audio_in_stream = p_audio_in_stream; - -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - video_in_ctx = avcodec_alloc_context3(NULL); - avcodec_parameters_to_context(video_in_ctx, - video_in_stream->codecpar); -// zm_dump_codecpar( video_in_stream->codecpar ); -#else - video_in_ctx = video_in_stream->codec; -#endif - - // store ins in variables local to class filename = filename_in; format = format_in; + + av_register_all(); packets_written = 0; frame_count = 0; Info("Opening video storage stream %s format: %s", filename, format); -#if 0 ret = avformat_alloc_output_context2(&oc, NULL, NULL, filename); - if (ret < 0) { + if ( ret < 0 ) { Warning( "Could not create video storage stream %s as no out ctx" " could be assigned based on filename: %s", @@ -69,8 +61,7 @@ VideoStore::VideoStore( } // Couldn't deduce format from filename, trying from format name - if (!oc) { -#endif + if ( !oc ) { avformat_alloc_output_context2(&oc, NULL, format, filename); if (!oc) { Fatal( @@ -80,171 +71,195 @@ VideoStore::VideoStore( } else { Debug(4, "Success alocating out ctx"); } -#if 0 } // end if ! oc -#endif + Debug(2, "Success opening output contect"); AVDictionary *pmetadata = NULL; - int dsr = - av_dict_set(&pmetadata, "title", "Zoneminder Security Recording", 0); + int dsr = av_dict_set(&pmetadata, "title", "Zoneminder Security Recording", 0); if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__); + Debug(2, "Success setting up dictcontect"); oc->metadata = pmetadata; out_format = oc->oformat; - in_frame = NULL; + + if ( video_in_stream ) { + video_in_stream_index = video_in_stream->index; #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - video_out_ctx = avcodec_alloc_context3(NULL); + video_in_ctx = avcodec_alloc_context3(NULL); + avcodec_parameters_to_context(video_in_ctx, + video_in_stream->codecpar); + zm_dump_codecpar( video_in_stream->codecpar ); +#else + video_in_ctx = video_in_stream->codec; +#endif + } else { + Debug(2, "No input ctx"); + video_in_ctx = avcodec_alloc_context3(NULL); + video_in_stream_index = 0; + } + + video_out_ctx = NULL; // Copy params from instream to ctx - ret = avcodec_parameters_to_context(video_out_ctx, - video_in_stream->codecpar); - if ( ret < 0 ) { - Error("Could not initialize ctx parameteres"); - return; - } else { - zm_dump_codec(video_out_ctx); - } - - video_out_stream = avformat_new_stream(oc, NULL); - if (!video_out_stream) { - Fatal("Unable to create video out stream\n"); - } else { - Debug(2, "Success creating video out stream"); - } - - if ( !video_out_ctx->codec_tag ) { - video_out_ctx->codec_tag = - av_codec_get_tag(oc->oformat->codec_tag, video_in_ctx->codec_id); - Debug(2, "No codec_tag, setting to %d", video_out_ctx->codec_tag); - } - - // Now copy them to the out stream - ret = avcodec_parameters_from_context(video_out_stream->codecpar, - video_out_ctx); - if (ret < 0) { - Error("Could not initialize stream parameteres"); - return; - } else { - Debug(2, "Success setting parameters"); - } - zm_dump_codecpar(video_out_stream->codecpar); - + if ( video_in_stream && ( video_in_ctx->codec_id == AV_CODEC_ID_H264 ) ) { +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + ret = avcodec_parameters_to_context(video_out_ctx, + video_in_stream->codecpar); + if ( ret < 0 ) { + Error("Could not initialize ctx parameteres"); + return; + } else { + Debug(2, "Going to dump the outctx"); + zm_dump_codec(video_out_ctx); + } #else - if ( video_in_ctx->codec_id == AV_CODEC_ID_H264 ) { + video_out_ctx = avcodec_alloc_context3(NULL); + avcodec_copy_context( video_out_ctx, video_in_ctx ); +#endif // Same codec, just copy the packets, otherwise we have to decode/encode video_out_codec = (AVCodec *)video_in_ctx->codec; - video_out_stream = avformat_new_stream(oc, video_out_codec); - if ( !video_out_stream ) { - Fatal("Unable to create video out stream\n"); - } else { - Debug(2, "Success creating video out stream"); - } - video_out_ctx = video_out_stream->codec; - // Just copy them from the in, no reason to choose different video_out_ctx->time_base = video_in_ctx->time_base; video_out_stream->time_base = video_in_stream->time_base; } else { - /** Create a new frame to store the audio samples. */ + + /** Create a new frame to store the */ if ( !(in_frame = zm_av_frame_alloc()) ) { Error("Could not allocate in frame"); return; } - video_out_codec = avcodec_find_encoder(AV_CODEC_ID_H264); - if (!video_out_codec) { + video_out_codec = avcodec_find_encoder_by_name("h264_omx"); + if ( ! video_out_codec ) { + Debug(1, "Didn't find omx"); + video_out_codec = avcodec_find_encoder(AV_CODEC_ID_H264); + } + if ( !video_out_codec ) { Fatal("Could not find codec for H264"); } Debug(2, "Have video out codec"); + + video_out_ctx = avcodec_alloc_context3( video_out_codec ); + // Don't have an input stream, so need to tell it what we are sending it, or are transcoding + video_out_ctx->width = monitor->Width(); + video_out_ctx->height = monitor->Height(); + video_out_ctx->codec_id = AV_CODEC_ID_H264; + video_out_ctx->sample_aspect_ratio = (AVRational){4,3}; + video_out_ctx->codec_type = AVMEDIA_TYPE_VIDEO; +//video_in_ctx->sample_aspect_ratio; + /* take first format from list of supported formats */ + //video_out_ctx->pix_fmt = video_out_codec->pix_fmts[0]; + video_out_ctx->pix_fmt = AV_PIX_FMT_YUV420P; + /* video time_base can be set to whatever is handy and supported by encoder */ + //video_out_ctx->time_base = video_in_ctx->time_base; + video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate + //video_out_ctx->framerate = (AVRational){0,1}; // Unknown framerate + video_out_ctx->gop_size = 12; + video_out_ctx->bit_rate = 4000000; + video_out_ctx->qmin = 10; + video_out_ctx->qmax = 51; + video_out_ctx->qcompress = 0.6; + + if (oc->oformat->flags & AVFMT_GLOBALHEADER) { +#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) + video_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; +#else + video_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; +#endif } + + AVDictionary *opts = 0; + std::string Options = monitor->GetEncoderOptions(); + ret = av_dict_parse_string(&opts, Options.c_str(), "=", ",#\n", 0); + if ( ret < 0 ) { + Warning("Could not parse ffmpeg encoder options list '%s'\n", Options.c_str()); + } else { + AVDictionaryEntry *e = NULL; + while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { + Debug( 3, "Encoder Option %s=%s", e->key, e->value ); + } + } + if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) { + Warning("Can't open video codec (%s)! %s, trying h264", + video_out_codec->name, + av_make_error_string(ret).c_str() + ); + video_out_codec = avcodec_find_encoder_by_name("h264"); + if ( ! video_out_codec ) { + Error("Can't find h264 encoder"); + video_out_codec = avcodec_find_encoder_by_name("libx264"); + if ( ! video_out_codec ) { + Error("Can't find libx264 encoder"); + return; + } + } + if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) { + Error("Can't open video codec (%s)! %s", + video_out_codec->name, + av_make_error_string(ret).c_str() ); + return; + } + } + AVDictionaryEntry *e = NULL; + while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { + Warning( "Encoder Option %s not recognized by ffmpeg codec", e->key); + } + av_dict_free(&opts); + + swscale.SetDefaults( + video_in_ctx->pix_fmt, + video_out_ctx->pix_fmt, + video_out_ctx->width, + video_out_ctx->height + ); + } // end if copying or trasncoding + + if ( !video_out_ctx->codec_tag ) { + video_out_ctx->codec_tag = + av_codec_get_tag(oc->oformat->codec_tag, AV_CODEC_ID_H264 ); + Debug(2, "No codec_tag, setting to %d", video_out_ctx->codec_tag); + } + video_out_stream = avformat_new_stream(oc, video_out_codec); if ( !video_out_stream ) { Fatal("Unable to create video out stream\n"); } else { Debug(2, "Success creating video out stream"); } - video_out_ctx = video_out_stream->codec; - - // * Copy over the useful; parameters - video_out_ctx->height = video_in_ctx->height; - video_out_ctx->width = video_in_ctx->width; - video_out_ctx->sample_aspect_ratio = video_in_ctx->sample_aspect_ratio; - /* take first format from list of supported formats */ - video_out_ctx->pix_fmt = video_out_codec->pix_fmts[0]; - /* video time_base can be set to whatever is handy and supported by encoder */ - //video_out_ctx->time_base = video_in_ctx->time_base; - video_out_ctx->time_base = (AVRational){1, 1000}; // Milliseconds as base frame rate - video_out_ctx->framerate = (AVRational){0,1}; // Unknown framerate - - AVDictionary *opts = 0; - std::string Options = monitor->GetEncoderOptions(); - ret = av_dict_parse_string(&opts, Options.c_str(), "=", ",#\n", 0); +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + ret = avcodec_parameters_from_context(video_out_stream->codecpar, + video_out_ctx); if ( ret < 0 ) { - Warning("Could not parse ffmpeg encoder options list '%s'\n", Options.c_str()); - } else { - AVDictionaryEntry *e = NULL; - while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { - Debug( 3, "Encoder Option %s=%s", e->key, e->value ); - } - } - ret = avcodec_open2(video_out_ctx, video_out_codec, &opts ); - if (ret < 0) { - Error("Can't open video codec!"); + Error("Could not initialize stream parameteres"); return; } - AVDictionaryEntry *e = NULL; - while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { - Warning( "Encoder Option %s not recognized by ffmpeg codec", e->key); - } - av_dict_free(&opts); - //ret = avcodec_copy_context(video_out_ctx, video_in_ctx); - //if ( ret < 0 ) { - //Fatal("Unable to copy in video ctx to out video ctx %s\n", - //av_make_error_string(ret).c_str()); - ////} else { - //Debug(3, "Success copying ctx"); - //} -#if 0 - if ( !video_out_ctx->codec_tag ) { - Debug(2, "No codec_tag"); - if (!oc->oformat->codec_tag || - av_codec_get_id(oc->oformat->codec_tag, - video_in_ctx->codec_tag) == - video_out_ctx->codec_id || - av_codec_get_tag(oc->oformat->codec_tag, - video_in_ctx->codec_id) <= 0) { - Warning("Setting codec tag"); - video_out_ctx->codec_tag = video_in_ctx->codec_tag; - } - } -#endif + zm_dump_codecpar(video_out_stream->codecpar); +#else +video_out_stream->time_base.num = video_out_ctx->time_base.num; +video_out_stream->time_base.den = video_out_ctx->time_base.den; +avcodec_copy_context( video_out_stream->codec, video_out_ctx ); +Debug(2, "%dx%d", video_out_stream->codec->width, video_out_stream->codec->height ); #endif Debug(3, - "Time bases: VIDEO in stream (%d/%d) in codec: (%d/%d) out " - "stream: (%d/%d) out codec (%d/%d)", - video_in_stream->time_base.num, video_in_stream->time_base.den, - video_in_ctx->time_base.num, video_in_ctx->time_base.den, - video_out_stream->time_base.num, video_out_stream->time_base.den, + "Time bases: VIDEO out stream: (%d/%d) out codec (%d/%d)", + video_out_stream->time_base.num, + video_out_stream->time_base.den, video_out_ctx->time_base.num, video_out_ctx->time_base.den); - if (oc->oformat->flags & AVFMT_GLOBALHEADER) { - video_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; - } - Monitor::Orientation orientation = monitor->getOrientation(); Debug(3, "Have orientation"); - if (orientation) { - if (orientation == Monitor::ROTATE_0) { - } else if (orientation == Monitor::ROTATE_90) { + if ( orientation ) { + if ( orientation == Monitor::ROTATE_0 ) { + } else if ( orientation == Monitor::ROTATE_90 ) { dsr = av_dict_set(&video_out_stream->metadata, "rotate", "90", 0); - if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__); - } else if (orientation == Monitor::ROTATE_180) { + if ( dsr < 0 ) Warning("%s:%d: title set failed", __FILE__, __LINE__); + } else if ( orientation == Monitor::ROTATE_180 ) { dsr = av_dict_set(&video_out_stream->metadata, "rotate", "180", 0); - if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__); - } else if (orientation == Monitor::ROTATE_270) { + if ( dsr < 0 ) Warning("%s:%d: title set failed", __FILE__, __LINE__); + } else if ( orientation == Monitor::ROTATE_270 ) { dsr = av_dict_set(&video_out_stream->metadata, "rotate", "270", 0); - if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__); + if ( dsr < 0 ) Warning("%s:%d: title set failed", __FILE__, __LINE__); } else { Warning("Unsupported Orientation(%d)", orientation); } @@ -259,7 +274,8 @@ VideoStore::VideoStore( resample_ctx = NULL; #endif - if (audio_in_stream) { + if ( audio_in_stream ) { + audio_in_stream_index = audio_in_stream->index; Debug(3, "Have audio stream"); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) @@ -270,7 +286,7 @@ VideoStore::VideoStore( audio_in_ctx = audio_in_stream->codec; #endif - if (audio_in_ctx->codec_id != AV_CODEC_ID_AAC) { + if ( audio_in_ctx->codec_id != AV_CODEC_ID_AAC ) { static char error_buffer[256]; avcodec_string(error_buffer, sizeof(error_buffer), audio_in_ctx, 0); @@ -333,14 +349,17 @@ VideoStore::VideoStore( } // end if audio_out_stream } // end if is AAC - if (audio_out_stream) { + if ( audio_out_stream ) { if (oc->oformat->flags & AVFMT_GLOBALHEADER) { - audio_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; +#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) + audio_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; +#else + audio_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; +#endif } } } // end if audio_in_stream - video_last_pts = 0; video_last_dts = 0; audio_last_pts = 0; @@ -373,22 +392,22 @@ bool VideoStore::open() { // av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0); // av_dict_set(&opts, "movflags", // "frag_keyframe+empty_moov+default_base_moof", 0); - if ((ret = avformat_write_header(oc, &opts)) < 0) { + if ( (ret = avformat_write_header(oc, &opts)) < 0 ) { // if ((ret = avformat_write_header(oc, &opts)) < 0) { Warning("Unable to set movflags to frag_custom+dash+delay_moov"); /* Write the stream header, if any. */ ret = avformat_write_header(oc, NULL); - } else if (av_dict_count(opts) != 0) { + } else if ( av_dict_count(opts) != 0 ) { Warning("some options not set\n"); } - if (ret < 0) { + if ( ret < 0 ) { Error("Error occurred when writing out file header to %s: %s\n", filename, av_make_error_string(ret).c_str()); return false; } - if (opts) av_dict_free(&opts); + if ( opts ) av_dict_free(&opts); return true; -} +} // end bool VideoStore::open() void VideoStore::write_audio_packet( AVPacket &pkt ) { Debug(2, "writing flushed packet pts(%d) dts(%d) duration(%d)", pkt.pts, @@ -411,8 +430,15 @@ void VideoStore::write_audio_packet( AVPacket &pkt ) { VideoStore::~VideoStore() { if ( video_out_ctx->codec_id != video_in_ctx->codec_id ) { +Debug(2,"Different codecs between in and out"); - if (video_out_ctx->codec->capabilities & AV_CODEC_CAP_DELAY) { +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + if ( video_out_ctx->codec && ( video_out_ctx->codec->capabilities & AV_CODEC_CAP_DELAY ) ) { +#else + if ( video_out_ctx->codec && ( video_out_ctx->codec->capabilities & CODEC_CAP_DELAY ) ) { +#endif + +Debug(2,"May have delayed packets"); // The codec queues data. We need to send a flush command and out // whatever we get. Failures are not fatal. AVPacket pkt; @@ -513,39 +539,39 @@ Debug(3, "(%d, %d)", video_next_dts, video_next_pts ); // allocation/de-allocation constantly, or whether we can just re-use it. // Just do a file open/close/writeheader/etc. // What if we were only doing audio recording? - if (video_out_stream) { + if ( video_out_stream ) { avcodec_close(video_out_ctx); video_out_ctx = NULL; Debug(4, "Success freeing video_out_ctx"); } // Used by both audio and video conversions - if (in_frame) { + if ( in_frame ) { av_frame_free(&in_frame); in_frame = NULL; } - if (audio_out_stream) { + if ( audio_out_stream ) { avcodec_close(audio_out_ctx); audio_out_ctx = NULL; #ifdef HAVE_LIBAVRESAMPLE - if (resample_ctx) { + if ( resample_ctx ) { avresample_close(resample_ctx); avresample_free(&resample_ctx); } - if (out_frame) { + if ( out_frame ) { av_frame_free(&out_frame); out_frame = NULL; } - if (converted_in_samples) { + if ( converted_in_samples ) { av_free(converted_in_samples); converted_in_samples = NULL; } #endif } - // WHen will be not using a file ? - if (!(out_format->flags & AVFMT_NOFILE)) { + // When will be not using a file ? // Might someday use this for streaming + if ( !(out_format->flags & AVFMT_NOFILE) ) { /* Close the out file. */ - if (int rc = avio_close(oc->pb)) { + if ( int rc = avio_close(oc->pb) ) { Error("Error closing avio %s", av_err2str(rc)); } } else { @@ -558,17 +584,15 @@ Debug(3, "(%d, %d)", video_next_dts, video_next_pts ); bool VideoStore::setup_resampler() { #ifdef HAVE_LIBAVRESAMPLE - static char error_buffer[256]; - -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) // Newer ffmpeg wants to keep everything separate... so have to lookup our own // decoder, can't reuse the one from the camera. - AVCodec *audio_in_codec = - avcodec_find_decoder(audio_in_stream->codecpar->codec_id); + AVCodec *audio_in_codec = avcodec_find_decoder( +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + audio_in_stream->codecpar->codec_id #else - AVCodec *audio_in_codec = - avcodec_find_decoder(audio_in_ctx->codec_id); + audio_in_ctx->codec_id #endif + ); ret = avcodec_open2(audio_in_ctx, audio_in_codec, NULL); if (ret < 0) { Error("Can't open in codec!"); @@ -576,7 +600,7 @@ bool VideoStore::setup_resampler() { } audio_out_codec = avcodec_find_encoder(AV_CODEC_ID_AAC); - if (!audio_out_codec) { + if ( !audio_out_codec ) { Error("Could not find codec for AAC"); return false; } @@ -584,34 +608,30 @@ bool VideoStore::setup_resampler() { // audio_out_ctx = audio_out_stream->codec; audio_out_ctx = avcodec_alloc_context3(audio_out_codec); - - if (!audio_out_ctx) { + if ( !audio_out_ctx ) { Error("could not allocate codec ctx for AAC\n"); audio_out_stream = NULL; return false; } - Debug(2, "Have audio_out_ctx"); - /* put sample parameters */ audio_out_ctx->bit_rate = audio_in_ctx->bit_rate; audio_out_ctx->sample_rate = audio_in_ctx->sample_rate; audio_out_ctx->channels = audio_in_ctx->channels; audio_out_ctx->channel_layout = audio_in_ctx->channel_layout; audio_out_ctx->sample_fmt = audio_in_ctx->sample_fmt; - audio_out_ctx->refcounted_frames = 1; + //audio_out_ctx->refcounted_frames = 1; - if (audio_out_codec->supported_samplerates) { + if ( audio_out_codec->supported_samplerates ) { int found = 0; - for (unsigned int i = 0; audio_out_codec->supported_samplerates[i]; - i++) { - if (audio_out_ctx->sample_rate == + for ( int i=0; audio_out_codec->supported_samplerates[i]; i++) { + if ( audio_out_ctx->sample_rate == audio_out_codec->supported_samplerates[i]) { found = 1; break; } } - if (found) { + if ( found ) { Debug(3, "Sample rate is good"); } else { audio_out_ctx->sample_rate = @@ -622,34 +642,31 @@ bool VideoStore::setup_resampler() { } /* check that the encoder supports s16 pcm in */ - if (!check_sample_fmt(audio_out_codec, audio_out_ctx->sample_fmt)) { + if ( !check_sample_fmt(audio_out_codec, audio_out_ctx->sample_fmt) ) { Debug(3, "Encoder does not support sample format %s, setting to FLTP", av_get_sample_fmt_name(audio_out_ctx->sample_fmt)); audio_out_ctx->sample_fmt = AV_SAMPLE_FMT_FLTP; } - audio_out_ctx->time_base = - (AVRational){1, audio_out_ctx->sample_rate}; + audio_out_ctx->time_base = (AVRational){1, audio_out_ctx->sample_rate}; // Now copy them to the out stream audio_out_stream = avformat_new_stream(oc, audio_out_codec); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - ret = avcodec_parameters_from_context(audio_out_stream->codecpar, - audio_out_ctx); - if (ret < 0) { + if ( (ret = avcodec_parameters_from_context(audio_out_stream->codecpar, + audio_out_ctx)) < 0 ) { Error("Could not initialize stream parameteres"); return false; } #endif AVDictionary *opts = NULL; - av_dict_set(&opts, "strict", "experimental", 0); + av_dict_set(&opts, "strict", "experimental", 0); // Needed to allow AAC ret = avcodec_open2(audio_out_ctx, audio_out_codec, &opts); av_dict_free(&opts); - if (ret < 0) { - av_strerror(ret, error_buffer, sizeof(error_buffer)); - Fatal("could not open codec (%d) (%s)\n", ret, error_buffer); + if ( ret < 0 ) { + Fatal("could not open codec (%d) (%s)\n", ret, av_make_error_string(ret).c_str()); audio_out_codec = NULL; audio_out_ctx = NULL; audio_out_stream = NULL; @@ -665,14 +682,14 @@ bool VideoStore::setup_resampler() { /** Create a new frame to store the audio samples. */ if ( ! in_frame ) { - if (!(in_frame = zm_av_frame_alloc())) { - Error("Could not allocate in frame"); - return false; - } + if (!(in_frame = zm_av_frame_alloc())) { + Error("Could not allocate in frame"); + return false; + } } /** Create a new frame to store the audio samples. */ - if (!(out_frame = zm_av_frame_alloc())) { + if ( !(out_frame = zm_av_frame_alloc()) ) { Error("Could not allocate out frame"); av_frame_free(&in_frame); return false; @@ -680,13 +697,13 @@ bool VideoStore::setup_resampler() { // Setup the audio resampler resample_ctx = avresample_alloc_context(); - if (!resample_ctx) { + if ( !resample_ctx ) { Error("Could not allocate resample ctx\n"); return false; } // Some formats (i.e. WAV) do not produce the proper channel layout - if (audio_in_ctx->channel_layout == 0) { + if ( audio_in_ctx->channel_layout == 0 ) { uint64_t layout = av_get_channel_layout("mono"); av_opt_set_int(resample_ctx, "in_channel_layout", av_get_channel_layout("mono"), 0); @@ -696,12 +713,9 @@ bool VideoStore::setup_resampler() { audio_in_ctx->channel_layout, 0); } - av_opt_set_int(resample_ctx, "in_sample_fmt", - audio_in_ctx->sample_fmt, 0); - av_opt_set_int(resample_ctx, "in_sample_rate", - audio_in_ctx->sample_rate, 0); - av_opt_set_int(resample_ctx, "in_channels", audio_in_ctx->channels, - 0); + av_opt_set_int(resample_ctx, "in_sample_fmt", audio_in_ctx->sample_fmt, 0); + av_opt_set_int(resample_ctx, "in_sample_rate", audio_in_ctx->sample_rate, 0); + av_opt_set_int(resample_ctx, "in_channels", audio_in_ctx->channels, 0); // av_opt_set_int( resample_ctx, "out_channel_layout", // audio_out_ctx->channel_layout, 0); av_opt_set_int(resample_ctx, "out_channel_layout", @@ -713,39 +727,11 @@ bool VideoStore::setup_resampler() { av_opt_set_int(resample_ctx, "out_channels", audio_out_ctx->channels, 0); - ret = avresample_open(resample_ctx); - if (ret < 0) { + if ( (ret = avresample_open(resample_ctx)) < 0 ) { Error("Could not open resample ctx\n"); return false; } -#if 0 - /** - * Allocate as many pointers as there are audio channels. - * Each pointer will later point to the audio samples of the corresponding - * channels (although it may be NULL for interleaved formats). - */ - if (!( converted_in_samples = reinterpret_castcalloc( audio_out_ctx->channels, sizeof(*converted_in_samples))) ) { - Error("Could not allocate converted in sample pointers\n"); - return; - } - /** - * Allocate memory for the samples of all channels in one consecutive - * block for convenience. - */ - if ( (ret = av_samples_alloc( &converted_in_samples, NULL, - audio_out_ctx->channels, - audio_out_ctx->frame_size, - audio_out_ctx->sample_fmt, 0)) < 0 ) { - Error("Could not allocate converted in samples (error '%s')\n", - av_make_error_string(ret).c_str()); - - av_freep(converted_in_samples); - free(converted_in_samples); - return; - } -#endif - out_frame->nb_samples = audio_out_ctx->frame_size; out_frame->format = audio_out_ctx->sample_fmt; out_frame->channel_layout = audio_out_ctx->channel_layout; @@ -757,16 +743,16 @@ bool VideoStore::setup_resampler() { audio_out_ctx->sample_fmt, 0); converted_in_samples = (uint8_t *)av_malloc(audioSampleBuffer_size); - if (!converted_in_samples) { + if ( !converted_in_samples ) { Error("Could not allocate converted in sample pointers\n"); return false; } // Setup the data pointers in the AVFrame - if (avcodec_fill_audio_frame(out_frame, audio_out_ctx->channels, + if ( avcodec_fill_audio_frame(out_frame, audio_out_ctx->channels, audio_out_ctx->sample_fmt, (const uint8_t *)converted_in_samples, - audioSampleBuffer_size, 0) < 0) { + audioSampleBuffer_size, 0) < 0 ) { Error("Could not allocate converted in sample pointers\n"); return false; } @@ -786,38 +772,125 @@ void VideoStore::dumpPacket(AVPacket *pkt) { snprintf(b, sizeof(b), " pts: %" PRId64 ", dts: %" PRId64 ", data: %p, size: %d, sindex: %d, dflags: %04x, s-pos: %" PRId64 - ", c-duration: %d\n", - pkt->pts, pkt->dts, pkt->data, pkt->size, pkt->stream_index, - pkt->flags, pkt->pos, pkt->duration); + ", c-duration: %" PRId64 "\n", + pkt->pts, + pkt->dts, + pkt->data, + pkt->size, + pkt->stream_index, + pkt->flags, + pkt->pos, + pkt->duration); Debug(1, "%s:%d:DEBUG: %s", __FILE__, __LINE__, b); } -int VideoStore::writeVideoFramePacket(AVPacket *ipkt) { +int VideoStore::writePacket( ZMPacket *ipkt ) { + if ( ipkt->packet.stream_index == video_in_stream_index ) { +Debug(2, "writing a video packet"); + return writeVideoFramePacket( ipkt ); + } else if ( ipkt->packet.stream_index == audio_in_stream_index ) { + return writeAudioFramePacket( ipkt ); + } + Error("Unknown stream type in packet (%d) out input video stream is (%d) and audio is (%d)", + ipkt->packet.stream_index, video_in_stream_index, ( audio_in_stream ? audio_in_stream_index : -1 ) + ); + return 0; +} + +int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { av_init_packet(&opkt); frame_count += 1; + + // if we have to transcode if ( video_out_ctx->codec_id != video_in_ctx->codec_id ) { - Debug(3, "Have encoding video frmae count (%d)", frame_count); + Debug(3, "Have encoding video frame count (%d)", frame_count); + + if ( ! zm_packet->frame ) { + if ( zm_packet->packet.size ) { + AVPacket *ipkt = &zm_packet->packet; #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - ret = avcodec_send_packet(video_in_ctx, ipkt); - if (ret < 0) { - Error("avcodec_send_packet fail %s", av_make_error_string(ret).c_str()); - return 0; - } + if ( ( ret = avcodec_send_packet(video_in_ctx, ipkt) ) < 0 ) { + Error("avcodec_send_packet fail %s", av_make_error_string(ret).c_str()); + return 0; + } + if ( ( ret = avcodec_receive_frame(video_in_ctx, in_frame) ) < 0 ) { + Error("avcodec_receive_frame fail %s", av_make_error_string(ret).c_str()); + return 0; + } +#else + if ((ret = avcodec_decode_video2(video_in_ctx, in_frame, + &data_present, ipkt )) < 0) { + Error("Could not decode frame (error '%s')\n", + av_make_error_string(ret).c_str()); + av_frame_free(&in_frame); + return 0; + } else { + Debug(3, "Decoded frame data_present(%d)", data_present); + } + if ( !data_present ) { + Debug(2, "Not ready to transcode a frame yet."); + return 0; + } +#endif + zm_packet->frame = in_frame; + } else if ( zm_packet->image ) { + AVFrame *frame = zm_packet->frame = zm_av_frame_alloc(); + if ( ! frame ) { + Error("Unable to allocate a frame"); + return 0; + } +#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) + int codec_imgsize = av_image_get_buffer_size( + video_out_ctx->pix_fmt, + video_out_ctx->width, + video_out_ctx->height, 1); + uint8_t *buffer = (uint8_t *)av_malloc(codec_imgsize); + av_image_fill_arrays( + frame->data, + frame->linesize, + buffer, + video_out_ctx->pix_fmt, + video_out_ctx->width, + video_out_ctx->height, + 1); +#else + int codec_imgsize = avpicture_get_size( + video_out_ctx->pix_fmt, + video_out_ctx->width, + video_out_ctx->height); + uint8_t *buffer = (uint8_t *)av_malloc(codec_imgsize); + avpicture_fill( + (AVPicture *)frame, + buffer, + video_out_ctx->pix_fmt, + video_out_ctx->width, + video_out_ctx->height + ); +#endif - ret = avcodec_receive_frame(video_in_ctx, in_frame); - if ( ret < 0 ) { - Error("avcodec_receive_frame fail %s", av_make_error_string(ret).c_str()); - return 0; - } - if ((ret = avcodec_send_frame(video_out_ctx, in_frame)) < 0) { - Error("Could not send frame (error '%s')", - av_make_error_string(ret).c_str()); - zm_av_packet_unref(&opkt); - return 0; - } + frame->width = video_out_ctx->width; + frame->height = video_out_ctx->height; + frame->format = video_out_ctx->pix_fmt; + swscale.Convert(zm_packet->image, + buffer, + codec_imgsize, + (AVPixelFormat)zm_packet->image->AVPixFormat(), + video_out_ctx->pix_fmt, + video_out_ctx->width, + video_out_ctx->height + ); - if ((ret = avcodec_receive_packet(video_out_ctx, &opkt)) < 0) { + } // end if has packet or image + } // end if no frame + +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + if ( (ret = avcodec_send_frame(video_out_ctx, zm_packet->frame)) < 0 ) { + Error("Could not send frame (error '%s')", av_make_error_string(ret).c_str()); + zm_av_packet_unref(&opkt); // NOT SURE THIS IS NECCESSARY + return 0; + } + if ( (ret = avcodec_receive_packet(video_out_ctx, &opkt)) < 0 ) { if (AVERROR(EAGAIN) == ret) { // THe codec may need more samples than it has, perfectly valid Debug(3, "Could not recieve packet (error '%s')", @@ -827,44 +900,25 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) { av_make_error_string(ret).c_str()); } zm_av_packet_unref(&opkt); - av_frame_unref(in_frame); return 0; } #else - /** - * Decode the video frame stored in the packet. - * The in video stream decoder is used to do this. - * If we are at the end of the file, pass an empty packet to the decoder - * to flush it. - */ - if ((ret = avcodec_decode_video2(video_in_ctx, in_frame, - &data_present, ipkt)) < 0) { - Error("Could not decode frame (error '%s')\n", - av_make_error_string(ret).c_str()); - dumpPacket(ipkt); - av_frame_free(&in_frame); - return 0; - } else { - Debug(3, "Decoded frame data_present(%d)", data_present); - } - if ( !data_present ) { - Debug(2, "Not ready to transcode a frame yet."); - return 0; - } - if ((ret = avcodec_encode_video2(video_out_ctx, &opkt, in_frame, - &data_present)) < 0) { + if ( (ret = avcodec_encode_video2( + video_out_ctx, &opkt, zm_packet->frame, &data_present)) < 0) { Error("Could not encode frame (error '%s')", av_make_error_string(ret).c_str()); zm_av_packet_unref(&opkt); return 0; } - if (!data_present) { + if ( !data_present ) { Debug(2, "Not ready to out a frame yet."); zm_av_packet_unref(&opkt); return 0; } #endif + } else { + AVPacket *ipkt = &zm_packet->packet; Debug(3, "Doing passthrough, just copy packet"); // Just copy it because the codec is the same opkt.data = ipkt->data; @@ -872,35 +926,38 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) { opkt.flags = ipkt->flags; } - opkt.dts = video_next_dts; - opkt.pts = video_next_pts; + opkt.dts = opkt.pts = zm_packet->timestamp.tv_sec*1000000 + zm_packet->timestamp.tv_usec; +#if 0 + opkt.dts = video_next_dts; + opkt.pts = video_next_pts; - int duration; - if ( !video_last_pts ) { - duration = 0; - } else { - duration = av_rescale_q( - ipkt->pts - video_last_pts, - video_in_stream->time_base, - video_out_stream->time_base - ); - Debug(1, "duration calc: pts(%d) - last_pts(%d) = (%d)", ipkt->pts, - video_last_pts, duration); - if ( duration < 0 ) { - duration = ipkt->duration; - } + int duration; + if ( !video_last_pts ) { + duration = 0; + } else { + duration = av_rescale_q( + ipkt->pts - video_last_pts, + video_in_stream->time_base, + video_out_stream->time_base + ); + Debug(1, "duration calc: pts(%d) - last_pts(%d) = (%d)", ipkt->pts, + video_last_pts, duration); + if ( duration < 0 ) { + duration = ipkt->duration; } + } - Debug(1, "ipkt.dts(%d) ipkt.pts(%d)", ipkt->dts, ipkt->pts); - video_last_pts = ipkt->pts; - video_last_dts = ipkt->dts; - video_last_duration = duration; - opkt.duration = duration; + // our timebase is always /1000000 now, so we can use the timestamp as the pts/dts + video_last_pts = zm_packet->timestamp.tv_sec*1000000 + zm_packet->timestamp.tv_usec; + video_last_dts = video_last_pts; + video_last_duration = duration; + opkt.duration = duration; +#endif write_video_packet( opkt ); zm_av_packet_unref(&opkt); - return 0; + return 1; } // end int VideoStore::writeVideoFramePacket( AVPacket *ipkt ) void VideoStore::write_video_packet( AVPacket &opkt ) { @@ -947,7 +1004,8 @@ void VideoStore::write_video_packet( AVPacket &opkt ) { __FILE__, __LINE__, av_make_error_string(ret).c_str(), (ret)); dumpPacket(&safepkt); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - zm_dump_codecpar(video_in_stream->codecpar); + if ( video_in_stream ) + zm_dump_codecpar(video_in_stream->codecpar); zm_dump_codecpar(video_out_stream->codecpar); #endif } else { @@ -957,28 +1015,27 @@ void VideoStore::write_video_packet( AVPacket &opkt ) { } // end void VideoStore::write_video_packet -int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { +int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { Debug(4, "writeAudioFrame"); - if (!audio_out_stream) { + AVPacket *ipkt = &zm_packet->packet; + + if ( !audio_out_stream ) { Debug(1, "Called writeAudioFramePacket when no audio_out_stream"); return 0; // FIXME -ve return codes do not free packet in ffmpeg_camera at // the moment } - if (audio_out_codec) { + if ( audio_out_codec ) { Debug(3, "Have audio codec"); #ifdef HAVE_LIBAVRESAMPLE #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - ret = avcodec_send_packet(audio_in_ctx, ipkt); - if (ret < 0) { + if ( (ret = avcodec_send_packet(audio_in_ctx, ipkt)) < 0 ) { Error("avcodec_send_packet fail %s", av_make_error_string(ret).c_str()); return 0; } - - ret = avcodec_receive_frame(audio_in_ctx, in_frame); - if (ret < 0) { + if ( (ret = avcodec_receive_frame(audio_in_ctx, in_frame)) < 0 ) { Error("avcodec_receive_frame fail %s", av_make_error_string(ret).c_str()); return 0; } @@ -994,15 +1051,15 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { * If we are at the end of the file, pass an empty packet to the decoder * to flush it. */ - if ((ret = avcodec_decode_audio4(audio_in_ctx, in_frame, - &data_present, ipkt)) < 0) { + if ( (ret = avcodec_decode_audio4(audio_in_ctx, in_frame, + &data_present, ipkt)) < 0 ) { Error("Could not decode frame (error '%s')\n", av_make_error_string(ret).c_str()); dumpPacket(ipkt); av_frame_free(&in_frame); return 0; } - if (!data_present) { + if ( !data_present ) { Debug(2, "Not ready to transcode a frame yet."); return 0; } @@ -1011,8 +1068,7 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { // Resample the in into the audioSampleBuffer until we proceed the whole // decoded data - if ((ret = - avresample_convert(resample_ctx, NULL, 0, 0, in_frame->data, + if ((ret = avresample_convert(resample_ctx, NULL, 0, 0, in_frame->data, 0, in_frame->nb_samples)) < 0) { Error("Could not resample frame (error '%s')\n", av_make_error_string(ret).c_str()); @@ -1144,7 +1200,7 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { } #endif // audio_last_dts = ipkt->dts; - if (opkt.dts > opkt.pts) { + if ( opkt.dts > opkt.pts ) { Debug(1, "opkt.dts(%d) must be <= opkt.pts(%d). Decompression must happen " "before presentation.", @@ -1152,14 +1208,7 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { opkt.dts = opkt.pts; } - // I wonder if we could just use duration instead of all the hoop jumping - // above? - // - if (out_frame) { - opkt.duration = out_frame->nb_samples; - } else { - opkt.duration = ipkt->duration; - } + opkt.duration = out_frame ? out_frame->nb_samples : ipkt->duration; // opkt.duration = av_rescale_q(ipkt->duration, audio_in_stream->time_base, // audio_out_stream->time_base); Debug(2, "opkt.pts (%d), opkt.dts(%d) opkt.duration = (%d)", opkt.pts, @@ -1182,5 +1231,27 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { Debug(2, "Success writing audio frame"); } zm_av_packet_unref(&opkt); - return 0; + return 1; } // end int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) + +int VideoStore::write_packets( zm_packetqueue &queue ) { + // 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; + + while ( ( queued_packet = queue.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, queue.size() ); + int ret = this->writePacket( queued_packet ); + 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 ); + return packet_count; +} // end int VideoStore::write_packets( PacketQueue &queue ) { diff --git a/src/zm_videostore.h b/src/zm_videostore.h index 292b91daa..e0e4eec41 100644 --- a/src/zm_videostore.h +++ b/src/zm_videostore.h @@ -12,7 +12,10 @@ extern "C" { #if HAVE_LIBAVCODEC +class VideoStore; #include "zm_monitor.h" +#include "zm_packet.h" +#include "zm_packetqueue.h" class VideoStore { private: @@ -23,6 +26,8 @@ private: AVFormatContext *oc; AVStream *video_out_stream; AVStream *audio_out_stream; +int video_in_stream_index; +int audio_in_stream_index; AVCodec *video_out_codec; AVCodecContext *video_out_ctx; @@ -41,6 +46,8 @@ private: AVCodecContext *audio_in_ctx; int ret; + SWScale swscale; + // The following are used when encoding the audio stream to AAC AVCodec *audio_out_codec; AVCodecContext *audio_out_ctx; @@ -82,16 +89,19 @@ public: const char *format_in, AVStream *video_in_stream, AVStream *audio_in_stream, - int64_t nStartTime, - Monitor * p_monitor); - bool open(); + int64_t starttime, + Monitor * p_monitor + ); ~VideoStore(); + bool open(); void write_video_packet( AVPacket &pkt ); void write_audio_packet( AVPacket &pkt ); - int writeVideoFramePacket( AVPacket *pkt ); - int writeAudioFramePacket( AVPacket *pkt ); + int writeVideoFramePacket( ZMPacket *pkt ); + int writeAudioFramePacket( ZMPacket *pkt ); + int writePacket( ZMPacket *pkt ); void dumpPacket( AVPacket *pkt ); + int write_packets( zm_packetqueue &queue ); }; #endif //havelibav From 50d3b168fad86de339046ca1fa81e1664329954f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 12 Nov 2017 11:50:07 -0500 Subject: [PATCH 0020/2339] wip --- src/zm_analysis_thread.cpp | 5 ++- src/zm_local_camera.cpp | 10 +++--- src/zm_monitor.cpp | 67 +++++++++++++++++++++++++------------- src/zmc.cpp | 11 +++++-- 4 files changed, 62 insertions(+), 31 deletions(-) diff --git a/src/zm_analysis_thread.cpp b/src/zm_analysis_thread.cpp index bb23c5d3f..b08632ac9 100644 --- a/src/zm_analysis_thread.cpp +++ b/src/zm_analysis_thread.cpp @@ -29,10 +29,13 @@ int AnalysisThread::run() { if ( analysis_update_delay ) { cur_time = time( 0 ); if ( (unsigned int)( cur_time - last_analysis_update_time ) > analysis_update_delay ) { +Debug(4, "Updating " ); analysis_rate = monitor->GetAnalysisRate(); monitor->UpdateAdaptiveSkip(); last_analysis_update_time = cur_time; } + } else { +Debug(4, "Not Updating " ); } if ( !monitor->Analyse() ) { @@ -44,6 +47,6 @@ Debug(4, "Sleeping for %d", analysis_rate); } //sigprocmask(SIG_UNBLOCK, &block_set, 0); - } + } // end while ! terminate return 0; } // end in AnalysisThread::run() diff --git a/src/zm_local_camera.cpp b/src/zm_local_camera.cpp index edeae3c8c..b0e45df29 100644 --- a/src/zm_local_camera.cpp +++ b/src/zm_local_camera.cpp @@ -1898,14 +1898,14 @@ int LocalCamera::PrimeCapture() { } int LocalCamera::PreCapture() { - Debug( 2, "Pre-capturing" ); + Debug( 4, "Pre-capturing" ); return( 0 ); } int LocalCamera::Capture( ZMPacket &zm_packet ) { // We assume that the avpacket is allocated, and just needs to be filled - Debug( 3, "Capturing" ); + Debug( 2, "Capturing" ); static uint8_t* buffer = NULL; static uint8_t* directbuffer = NULL; static int capture_frame = -1; @@ -2000,7 +2000,7 @@ int LocalCamera::Capture( ZMPacket &zm_packet ) { #if HAVE_LIBSWSCALE if ( conversion_type == 1 ) { - Debug( 9, "Calling sws_scale to perform the conversion" ); + Debug( 9, "Setting up a frame" ); /* Use swscale to convert the image directly into the shared memory */ #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) av_image_fill_arrays(tmpPicture->data, @@ -2010,6 +2010,7 @@ int LocalCamera::Capture( ZMPacket &zm_packet ) { avpicture_fill( (AVPicture *)tmpPicture, directbuffer, imagePixFormat, width, height ); #endif + Debug( 9, "Calling sws_scale to perform the conversion" ); sws_scale( imgConversionContext, capturePictures[capture_frame]->data, @@ -2019,6 +2020,7 @@ int LocalCamera::Capture( ZMPacket &zm_packet ) { tmpPicture->data, tmpPicture->linesize ); + Debug( 9, "Done sws_scale to perform the conversion" ); } else #endif if ( conversion_type == 2 ) { @@ -2071,7 +2073,7 @@ int LocalCamera::PostCapture() { } else { Error( "Unable to requeue buffer due to not v4l2_data" ) } - } + } else #endif // ZM_HAS_V4L2 #if ZM_HAS_V4L1 if ( v4l_version == 1 ) { diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index fe95023a5..213b043de 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1149,6 +1149,7 @@ bool Monitor::Analyse() { //Debug(3, " shared_data->last_read_index == shared_data->last_write_index " ); return false; } + Debug(3, "ANal"); struct timeval now; gettimeofday( &now, NULL ); @@ -2870,6 +2871,7 @@ int Monitor::Capture() { } } else { captureResult = camera->Capture(packet); + Debug(2,"Capture result (%d)", captureResult ); if ( captureResult < 0 ) { // Unable to capture image for temporary reason // Fake a signal loss image @@ -2882,13 +2884,15 @@ int Monitor::Capture() { } int video_stream_id = camera->get_VideoStreamId(); + Debug(2,"Video stream is (%d)", video_stream_id ); //Video recording if ( video_store_data->recording.tv_sec ) { - if ( shared_data->last_event_id != this->GetVideoWriterEventId() ) { + Debug(2,"Recording since (%d)", video_store_data->recording.tv_sec ); + if ( shared_data->last_event_id != video_store_data->current_event ) { Debug(2, "Have change of event. last_event(%d), our current (%d)", shared_data->last_event_id, - this->GetVideoWriterEventId() + video_store_data->current_event ); if ( videoStore ) { Debug(2, "Have videostore already?"); @@ -2903,6 +2907,8 @@ Debug(2, "Have videostore already?"); videoStore = NULL; this->SetVideoWriterEventId( 0 ); } // end if videoStore + } else { + Debug(2, "No change of event"); } // end if end of recording if ( shared_data->last_event_id and ! videoStore ) { @@ -2933,27 +2939,34 @@ Debug(2,"New videostore"); delete videoStore; videoStore = NULL; this->SetVideoWriterEventId( 0 ); + } else { + Debug(2,"Not recording"); } // Buffer video packets, since we are not recording. // All audio packets are keyframes, so only if it's a video keyframe - if ( ( packet.packet.stream_index == video_stream_id ) && ( packet.keyframe ) ) { - packetqueue.clearQueue( this->GetPreEventCount(), video_stream_id ); - } - // The following lines should ensure that the queue always begins with a video keyframe - if ( packet.packet.stream_index == camera->get_AudioStreamId() ) { + if ( packet.packet.stream_index == video_stream_id ) { + if ( packet.keyframe ) { + packetqueue.clearQueue( this->GetPreEventCount(), video_stream_id ); + packetqueue.queuePacket( &packet ); + } else if ( packetqueue.size() ) { + // it's a keyframe or we already have something in the queue + packetqueue.queuePacket( &packet ); + } + } else if ( packet.packet.stream_index == camera->get_AudioStreamId() ) { + // The following lines should ensure that the queue always begins with a video keyframe //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.packet.stream_index == video_stream_id ) { - if ( packet.keyframe || packetqueue.size() ) // it's a keyframe or we already have something in the queue - packetqueue.queuePacket( &packet ); + } else { + Debug(2,"Unknown stream"); } // end if audio or video } // end if recording or not if ( videoStore ) { + Debug(2, "Writing packet"); //Write the packet to our video store, it will be smart enough to know what to do int ret = videoStore->writePacket( &packet ); if ( ret < 0 ) { //Less than zero and we skipped a frame @@ -2962,20 +2975,24 @@ Debug(2,"New videostore"); } } // end if de-interlacing or not - /* Deinterlacing */ - if ( deinterlacing_value == 1 ) { - capture_image->Deinterlace_Discard(); - } else if ( deinterlacing_value == 2 ) { - capture_image->Deinterlace_Linear(); - } else if ( deinterlacing_value == 3 ) { - capture_image->Deinterlace_Blend(); - } else if ( deinterlacing_value == 4 ) { - capture_image->Deinterlace_4Field( next_buffer.image, (deinterlacing>>8)&0xff ); - } else if ( deinterlacing_value == 5 ) { - capture_image->Deinterlace_Blend_CustomRatio( (deinterlacing>>8)&0xff ); + if ( deinterlacing_value ) { + Debug(2,"Deinterlace"); + /* Deinterlacing */ + if ( deinterlacing_value == 1 ) { + capture_image->Deinterlace_Discard(); + } else if ( deinterlacing_value == 2 ) { + capture_image->Deinterlace_Linear(); + } else if ( deinterlacing_value == 3 ) { + capture_image->Deinterlace_Blend(); + } else if ( deinterlacing_value == 4 ) { + capture_image->Deinterlace_4Field( next_buffer.image, (deinterlacing>>8)&0xff ); + } else if ( deinterlacing_value == 5 ) { + capture_image->Deinterlace_Blend_CustomRatio( (deinterlacing>>8)&0xff ); + } } if ( orientation != ROTATE_0 ) { + Debug(2,"Rotate"); switch ( orientation ) { case ROTATE_0 : { // No action required @@ -3006,13 +3023,17 @@ Debug(2,"New videostore"); } } - if ( privacy_bitmask ) + if ( privacy_bitmask ) { + Debug(2,"privacy"); capture_image->MaskPrivacy( privacy_bitmask ); + } gettimeofday( image_buffer[index].timestamp, NULL ); if ( config.timestamp_on_capture ) { + Debug(2,"Timestamping"); TimestampImage( capture_image, image_buffer[index].timestamp ); } + Debug(2,"Check signal"); shared_data->signal = CheckSignal(capture_image); shared_data->last_write_index = index; shared_data->last_write_time = image_buffer[index].timestamp->tv_sec; @@ -3039,7 +3060,7 @@ Debug(2,"New videostore"); Error( "Can't run query: %s", mysql_error( &dbconn ) ); } } - } + } // end if report fps // Icon: I'm not sure these should be here. They have nothing to do with capturing if ( shared_data->action & GET_SETTINGS ) { diff --git a/src/zmc.cpp b/src/zmc.cpp index d235767c5..b7a6d83bf 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -269,7 +269,8 @@ int main(int argc, char *argv[]) { struct timeval now; struct DeltaTimeval delta_time; while ( !zm_terminate ) { - sigprocmask(SIG_BLOCK, &block_set, 0); + Debug(2,"blocking"); + //sigprocmask(SIG_BLOCK, &block_set, 0); for ( int i = 0; i < n_monitors; i++ ) { long min_delay = MAXINT; @@ -316,14 +317,18 @@ int main(int argc, char *argv[]) { DELTA_TIMEVAL(delta_time, now, last_capture_times[i], DT_PREC_3); long sleep_time = next_delays[i]-delta_time.delta; if ( sleep_time > 0 ) { + Debug(2,"usleeping (%d)", sleep_time*(DT_MAXGRAN/DT_PREC_3) ); usleep(sleep_time*(DT_MAXGRAN/DT_PREC_3)); } + last_capture_times[i] = now; + } else { + gettimeofday(&(last_capture_times[i]), NULL); } - gettimeofday(&(last_capture_times[i]), NULL); } // end if next_delay <= min_delay || next_delays[i] <= 0 ) } // end foreach n_monitors - sigprocmask(SIG_UNBLOCK, &block_set, 0); + Debug(2,"unblocking"); + //sigprocmask(SIG_UNBLOCK, &block_set, 0); } // end while ! zm_terminate for ( int i = 0; i < n_monitors; i++ ) { if ( analysis_threads[i] ) { From eee312a2d40a44b4f67f2c0debe2936ea91d6f3e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 12 Nov 2017 17:14:21 -0500 Subject: [PATCH 0021/2339] free contexts --- src/zm_videostore.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 40606da13..1c5fab370 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -570,6 +570,16 @@ Debug(3, "dts:%d, pts:%d", pkt.dts, pkt.pts ); } #endif } +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + if ( video_in_ctx ) { + avcodec_free_context(&video_in_ctx); + video_in_ctx = NULL; + } + if ( video_out_ctx ) { + avcodec_free_context(&video_out_ctx); + video_out_ctx = NULL; + } +#endif // When will be not using a file ? // Might someday use this for streaming if ( !(out_format->flags & AVFMT_NOFILE) ) { From e325f5435cb586d6d6433a90bffe1e81fd8d60b4 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 13 Nov 2017 10:17:46 -0500 Subject: [PATCH 0022/2339] too much refactoring --- src/zm_event.cpp | 60 +++++++-------------- src/zm_event.h | 4 ++ src/zm_monitor.cpp | 120 +++++++++++------------------------------- src/zm_monitor.h | 6 +++ src/zm_videostore.cpp | 1 - src/zm_videostore.h | 1 - 6 files changed, 62 insertions(+), 130 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 4a4c841fb..40b25d19a 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -168,35 +168,19 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string snprintf( video_name, sizeof(video_name), "%d-%s", id, "video.mp4" ); snprintf( video_file, sizeof(video_file), staticConfig.video_file_format, path, video_name ); Debug(1,"Writing video file to %s", video_file ); -#if 0 - /* X264 MP4 video writer */ - if ( monitor->GetOptVideoWriter() == Monitor::X264ENCODE ) { -#if ZM_HAVE_VIDEOWRITER_X264MP4 - videowriter = new X264MP4Writer(video_file, monitor->Width(), monitor->Height(), monitor->Colours(), monitor->SubpixelOrder(), monitor->GetOptEncoderParams()); -#else - Error("ZoneMinder was not compiled with the X264 MP4 video writer, check dependencies (x264 and mp4v2)"); -#endif - } + Camera * camera = monitor->getCamera(); + videoStore = new VideoStore( + video_file, + "mp4", + camera->get_VideoStream(), + ( monitor->RecordAudio() ? camera->get_AudioStream() : NULL ), + monitor ); - if ( videowriter != NULL ) { - /* Open the video stream */ - int nRet = videowriter->Open(); - if(nRet != 0) { - Error("Failed opening video stream"); - delete videowriter; - videowriter = NULL; - } + if ( ! videoStore->open() ) { + delete videoStore; + videoStore = NULL; + } - snprintf( timecodes_name, sizeof(timecodes_name), "%d-%s", id, "video.timecodes" ); - snprintf( timecodes_file, sizeof(timecodes_file), staticConfig.video_file_format, path, timecodes_name ); - - /* Create timecodes file */ - timecodes_fd = fopen(timecodes_file, "wb"); - if ( timecodes_fd == NULL ) { - Error("Failed creating timecodes file"); - } - } -#endif } else { /* No video object */ videowriter = NULL; @@ -210,7 +194,6 @@ Event::~Event() { DELTA_TIMEVAL( delta_time, end_time, start_time, DT_PREC_2 ); if ( frames > last_db_frame ) { - Debug( 1, "Adding closing frame %d to DB", frames ); snprintf( sql, sizeof(sql), "insert into Frames ( EventId, FrameId, TimeStamp, Delta ) values ( %d, %d, from_unixtime( %ld ), %s%ld.%02ld )", id, frames, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec ); if ( mysql_query( &dbconn, sql ) ) { @@ -220,17 +203,9 @@ Event::~Event() { } /* Close the video file */ - if ( videowriter != NULL ) { - int nRet = videowriter->Close(); - if ( nRet != 0 ) { - Error("Failed closing video stream"); - } - delete videowriter; - videowriter = NULL; - - /* Close the timecodes file */ - fclose(timecodes_fd); - timecodes_fd = NULL; + if ( videoStore ) { + delete videoStore; + videoStore = NULL; } snprintf( sql, sizeof(sql), "update Events set Name='%s%d', EndTime = from_unixtime( %ld ), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, DefaultVideo = '%s' where Id = %d", monitor->EventPrefix(), id, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, frames, alarm_frames, tot_score, (int)(alarm_frames?(tot_score/alarm_frames):0), max_score, video_name, id ); @@ -273,7 +248,7 @@ Debug(3, "Writing image to %s", event_file ); } return rc; -} +} // end Event::WriteFrameImage( Image *image, struct timeval timestamp, const char *event_file, bool alarm_frame ) bool Event::WriteFrameVideo( const Image *image, const struct timeval timestamp, VideoWriter* videow ) { const Image* frameimg = image; @@ -308,6 +283,11 @@ bool Event::WriteFrameVideo( const Image *image, const struct timeval timestamp, return( true ); } +bool Event::WritePacket( ZMPacket &packet ) { + + videoStore->writePacket( &packet ); +} + void Event::updateNotes( const StringSetMap &newNoteSetMap ) { bool update = false; diff --git a/src/zm_event.h b/src/zm_event.h index 38ae4186c..8a7cfbb3c 100644 --- a/src/zm_event.h +++ b/src/zm_event.h @@ -38,7 +38,9 @@ #include "zm_image.h" #include "zm_stream.h" #include "zm_video.h" +#include "zm_packet.h" +class VideoStore; class Zone; class Monitor; class EventStream; @@ -85,6 +87,7 @@ class Event { unsigned int max_score; char path[PATH_MAX]; VideoWriter* videowriter; + VideoStore *videoStore; FILE* timecodes_fd; char video_name[PATH_MAX]; char video_file[PATH_MAX]; @@ -119,6 +122,7 @@ class Event { void AddFrames( int n_frames, Image **images, struct timeval **timestamps ); void AddFrame( Image *image, struct timeval timestamp, int score=0, Image *alarm_frame=NULL ); + bool WritePacket( ZMPacket &p ); private: void AddFramesInternal( int n_frames, int start_frame, Image **images, struct timeval **timestamps ); diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 22675f040..34affb0fd 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -2893,87 +2893,6 @@ int Monitor::Capture() { return -1; } - int video_stream_id = camera->get_VideoStreamId(); - - //Video recording - if ( video_store_data->recording.tv_sec ) { - if ( shared_data->last_event_id != this->GetVideoWriterEventId() ) { - Debug(2, "Have change of event. last_event(%d), our current (%d)", - shared_data->last_event_id, - this->GetVideoWriterEventId() - ); - if ( videoStore ) { - Debug(2, "Have videostore already?"); - // 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. - int ret = videoStore->writePacket( &packet ); - if ( ret < 0 ) { //Less than zero and we skipped a frame - Warning("Error writing last packet to videostore."); - } - - delete videoStore; - videoStore = NULL; - this->SetVideoWriterEventId( 0 ); - } // end if videoStore - } // end if end of recording - - if ( shared_data->last_event_id and ! videoStore ) { - Debug(2,"New videostore"); - videoStore = new VideoStore( - (const char *) video_store_data->event_file, - "mp4", - camera->get_VideoStream(), - ( record_audio ? camera->get_AudioStream() : NULL ), - video_store_data->recording.tv_sec, - this ); - - if ( ! videoStore->open() ) { - delete videoStore; - videoStore = NULL; - } else { - this->SetVideoWriterEventId(shared_data->last_event_id); - - Debug(2, "Clearing packets"); - // Clear all packets that predate the moment when the recording began - packetqueue.clear_unwanted_packets(&video_store_data->recording, video_stream_id); - videoStore->write_packets(packetqueue); - } // success opening - } // end if ! was recording - } else { // Not recording - if ( videoStore ) { - Info("Deleting videoStore instance"); - delete videoStore; - videoStore = NULL; - this->SetVideoWriterEventId( 0 ); - } - - // Buffer video packets, since we are not recording. - // All audio packets are keyframes, so only if it's a video keyframe - if ( ( packet.packet.stream_index == video_stream_id ) && ( packet.keyframe ) ) { - packetqueue.clearQueue( this->GetPreEventCount(), video_stream_id ); - } - // The following lines should ensure that the queue always begins with a video keyframe - if ( packet.packet.stream_index == camera->get_AudioStreamId() ) { - //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.packet.stream_index == video_stream_id ) { - if ( packet.keyframe || packetqueue.size() ) // it's a keyframe or we already have something in the queue - packetqueue.queuePacket( &packet ); - } // end if audio or video - } // end if recording or not - - if ( videoStore ) { - //Write the packet to our video store, it will be smart enough to know what to do - int ret = videoStore->writePacket( &packet ); - if ( ret < 0 ) { //Less than zero and we skipped a frame - Warning("problem writing packet"); - } - } - } // end if deinterlacing - /* Deinterlacing */ if ( deinterlacing_value ) { if ( deinterlacing_value == 1 ) { @@ -3006,11 +2925,6 @@ int Monitor::Capture() { } } - if ( capture_image->Size() > camera->ImageSize() ) { - Error( "Captured image %d does not match expected size %d check width, height and colour depth",capture_image->Size(),camera->ImageSize() ); - return( -1 ); - } - if ( (index == shared_data->last_read_index) && (function > MONITOR) ) { Warning( "Buffer overrun at index %d, image %d, slow down capture, speed up analysis or increase ring buffer size", index, image_count ); time_t now = time(0); @@ -3025,10 +2939,40 @@ int Monitor::Capture() { if ( privacy_bitmask ) capture_image->MaskPrivacy( privacy_bitmask ); - gettimeofday( image_buffer[index].timestamp, NULL ); + //gettimeofday( image_buffer[index].timestamp, NULL ); if ( config.timestamp_on_capture ) { - TimestampImage( capture_image, image_buffer[index].timestamp ); + TimestampImage( capture_image, &packet.timestamp ); } + + int video_stream_id = camera->get_VideoStreamId(); + + //packetqueue.clear_unwanted_packets(&video_store_data->recording, video_stream_id); + //videoStore->write_packets(packetqueue); + if ( ! event ) { + // Buffer video packets, since we are not recording. + // All audio packets are keyframes, so only if it's a video keyframe + if ( ( packet.packet.stream_index == video_stream_id ) && ( packet.keyframe ) ) { + packetqueue.clearQueue( this->GetPreEventCount(), video_stream_id ); + } + // The following lines should ensure that the queue always begins with a video keyframe + if ( packet.packet.stream_index == camera->get_AudioStreamId() ) { + //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.packet.stream_index == video_stream_id ) { + if ( packet.keyframe || packetqueue.size() ) // it's a keyframe or we already have something in the queue + packetqueue.queuePacket( &packet ); + } // end if audio or video + } else { + //Write the packet to our video store, it will be smart enough to know what to do + if ( ! event->WritePacket( packet ) ) { + Warning("problem writing packet"); + } + } // end if recording or not + } // end if deinterlacing + shared_data->signal = CheckSignal(capture_image); shared_data->last_write_index = index; shared_data->last_write_time = image_buffer[index].timestamp->tv_sec; diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 23d665f50..8ee2e3723 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -404,6 +404,9 @@ public: inline Function GetFunction() const { return( function ); } + inline Camera *getCamera() { + return camera; + } inline bool Enabled() { if ( function <= MONITOR ) return( false ); @@ -425,6 +428,9 @@ public: inline bool Exif() { return( embed_exif ); } + inline bool RecordAudio() { + return record_audio; + } Orientation getOrientation() const; unsigned int Width() const { return width; } diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 1c5fab370..3ed87fc3d 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -36,7 +36,6 @@ VideoStore::VideoStore( const char *format_in, AVStream *p_video_in_stream, AVStream *p_audio_in_stream, - int64_t nStartTime, Monitor *monitor ) { video_in_stream = p_video_in_stream; diff --git a/src/zm_videostore.h b/src/zm_videostore.h index c3536fb3e..ec9b44bdd 100644 --- a/src/zm_videostore.h +++ b/src/zm_videostore.h @@ -88,7 +88,6 @@ public: const char *format_in, AVStream *video_in_stream, AVStream *audio_in_stream, - int64_t starttime, Monitor * p_monitor ); ~VideoStore(); From 0e799233d2d1f923fd6ec71bcaef2f6505fae957 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 13 Nov 2017 10:57:37 -0500 Subject: [PATCH 0023/2339] move up timestamping to before videowriting --- src/zm_monitor.cpp | 104 +++++++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 55 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 22675f040..1c0f53cc4 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -2893,6 +2893,55 @@ int Monitor::Capture() { return -1; } + /* Deinterlacing */ + if ( deinterlacing_value ) { + if ( deinterlacing_value == 1 ) { + capture_image->Deinterlace_Discard(); + } else if ( deinterlacing_value == 2 ) { + capture_image->Deinterlace_Linear(); + } else if ( deinterlacing_value == 3 ) { + capture_image->Deinterlace_Blend(); + } else if ( deinterlacing_value == 4 ) { + capture_image->Deinterlace_4Field( next_buffer.image, (deinterlacing>>8)&0xff ); + } else if ( deinterlacing_value == 5 ) { + capture_image->Deinterlace_Blend_CustomRatio( (deinterlacing>>8)&0xff ); + } + } + + if ( orientation != ROTATE_0 ) { + switch ( orientation ) { + case ROTATE_0 : + // No action required + break; + case ROTATE_90 : + case ROTATE_180 : + case ROTATE_270 : + capture_image->Rotate( (orientation-1)*90 ); + break; + case FLIP_HORI : + case FLIP_VERT : + capture_image->Flip( orientation==FLIP_HORI ); + break; + } + } + + if ( (index == shared_data->last_read_index) && (function > MONITOR) ) { + Warning( "Buffer overrun at index %d, image %d, slow down capture, speed up analysis or increase ring buffer size", index, image_count ); + time_t now = time(0); + double approxFps = double(image_buffer_count)/double(now-image_buffer[index].timestamp->tv_sec); + time_t last_read_delta = now - shared_data->last_read_time; + if ( last_read_delta > (image_buffer_count/approxFps) ) { + Warning( "Last image read from shared memory %ld seconds ago, zma may have gone away", last_read_delta ) + shared_data->last_read_index = image_buffer_count; + } + } + + if ( privacy_bitmask ) + capture_image->MaskPrivacy( privacy_bitmask ); + + if ( config.timestamp_on_capture ) { + TimestampImage( capture_image, &packet.timestamp ); + } int video_stream_id = camera->get_VideoStreamId(); //Video recording @@ -2974,61 +3023,6 @@ int Monitor::Capture() { } } // end if deinterlacing - /* Deinterlacing */ - if ( deinterlacing_value ) { - if ( deinterlacing_value == 1 ) { - capture_image->Deinterlace_Discard(); - } else if ( deinterlacing_value == 2 ) { - capture_image->Deinterlace_Linear(); - } else if ( deinterlacing_value == 3 ) { - capture_image->Deinterlace_Blend(); - } else if ( deinterlacing_value == 4 ) { - capture_image->Deinterlace_4Field( next_buffer.image, (deinterlacing>>8)&0xff ); - } else if ( deinterlacing_value == 5 ) { - capture_image->Deinterlace_Blend_CustomRatio( (deinterlacing>>8)&0xff ); - } - } - - if ( orientation != ROTATE_0 ) { - switch ( orientation ) { - case ROTATE_0 : - // No action required - break; - case ROTATE_90 : - case ROTATE_180 : - case ROTATE_270 : - capture_image->Rotate( (orientation-1)*90 ); - break; - case FLIP_HORI : - case FLIP_VERT : - capture_image->Flip( orientation==FLIP_HORI ); - break; - } - } - - if ( capture_image->Size() > camera->ImageSize() ) { - Error( "Captured image %d does not match expected size %d check width, height and colour depth",capture_image->Size(),camera->ImageSize() ); - return( -1 ); - } - - if ( (index == shared_data->last_read_index) && (function > MONITOR) ) { - Warning( "Buffer overrun at index %d, image %d, slow down capture, speed up analysis or increase ring buffer size", index, image_count ); - time_t now = time(0); - double approxFps = double(image_buffer_count)/double(now-image_buffer[index].timestamp->tv_sec); - time_t last_read_delta = now - shared_data->last_read_time; - if ( last_read_delta > (image_buffer_count/approxFps) ) { - Warning( "Last image read from shared memory %ld seconds ago, zma may have gone away", last_read_delta ) - shared_data->last_read_index = image_buffer_count; - } - } - - if ( privacy_bitmask ) - capture_image->MaskPrivacy( privacy_bitmask ); - - gettimeofday( image_buffer[index].timestamp, NULL ); - if ( config.timestamp_on_capture ) { - TimestampImage( capture_image, image_buffer[index].timestamp ); - } shared_data->signal = CheckSignal(capture_image); shared_data->last_write_index = index; shared_data->last_write_time = image_buffer[index].timestamp->tv_sec; From aee2b148f024b2ae35649c2bb72efe5b07422e1f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 13 Nov 2017 12:14:57 -0500 Subject: [PATCH 0024/2339] wip --- src/zm_monitor.cpp | 177 ++++++++++++++------------------------- src/zm_monitor.h | 16 +--- src/zm_monitorstream.cpp | 22 ++--- src/zm_packet.cpp | 13 ++- src/zm_packet.h | 3 +- 5 files changed, 88 insertions(+), 143 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 1c0f53cc4..8cacd5c49 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -372,7 +372,6 @@ Monitor::Monitor( mem_size = sizeof(SharedData) + sizeof(TriggerData) + sizeof(VideoStoreData) //Information to pass back to the capture process - + (image_buffer_count*sizeof(struct timeval)) + (image_buffer_count*camera->ImageSize()) + 64; /* Padding used to permit aligning the images buffer to 64 byte boundary */ @@ -553,36 +552,32 @@ bool Monitor::connect() { shared_data = (SharedData *)mem_ptr; trigger_data = (TriggerData *)((char *)shared_data + sizeof(SharedData)); video_store_data = (VideoStoreData *)((char *)trigger_data + sizeof(TriggerData)); - struct timeval *shared_timestamps = (struct timeval *)((char *)video_store_data + sizeof(VideoStoreData)); - unsigned char *shared_images = (unsigned char *)((char *)shared_timestamps + (image_buffer_count*sizeof(struct timeval))); - + unsigned char *shared_images = (unsigned char *)((char *)video_store_data + sizeof(VideoStoreData)); if ( ((unsigned long)shared_images % 64) != 0 ) { /* Align images buffer to nearest 64 byte boundary */ Debug(3,"Aligning shared memory images to the next 64 byte boundary"); shared_images = (uint8_t*)((unsigned long)shared_images + (64 - ((unsigned long)shared_images % 64))); } - Debug(3, "Allocating %d image buffers", image_buffer_count ); - image_buffer = new Snapshot[image_buffer_count]; - for ( int i = 0; i < image_buffer_count; i++ ) { - image_buffer[i].timestamp = &(shared_timestamps[i]); - image_buffer[i].image = new Image( width, height, camera->Colours(), camera->SubpixelOrder(), &(shared_images[i*camera->ImageSize()]) ); - image_buffer[i].image->HoldBuffer(true); /* Don't release the internal buffer or replace it with another */ - } - if ( (deinterlacing & 0xff) == 4) { - /* Four field motion adaptive deinterlacing in use */ - /* Allocate a buffer for the next image */ - next_buffer.image = new Image( width, height, camera->Colours(), camera->SubpixelOrder()); - next_buffer.timestamp = new struct timeval; - } + + Debug(3, "Allocating %d image buffers", image_buffer_count ); + image_buffer = new ZMPacket[image_buffer_count]; + for ( int i = 0; i < image_buffer_count; i++ ) { + image_buffer[i].image = new Image( width, height, camera->Colours(), camera->SubpixelOrder(), &(shared_images[i*camera->ImageSize()]) ); + image_buffer[i].image->HoldBuffer(true); /* Don't release the internal buffer or replace it with another */ + } + if ( (deinterlacing & 0xff) == 4) { + /* Four field motion adaptive deinterlacing in use */ + /* Allocate a buffer for the next image */ + next_buffer.image = new Image( width, height, camera->Colours(), camera->SubpixelOrder()); + } if ( ( purpose == ANALYSIS ) && analysis_fps ) { // Size of pre event buffer must be greater than pre_event_count // if alarm_frame_count > 1, because in this case the buffer contains // alarmed images that must be discarded when event is created pre_event_buffer_count = pre_event_count + alarm_frame_count - 1; - pre_event_buffer = new Snapshot[pre_event_buffer_count]; + pre_event_buffer = new ZMPacket[pre_event_buffer_count]; for ( int i = 0; i < pre_event_buffer_count; i++ ) { - pre_event_buffer[i].timestamp = new struct timeval; pre_event_buffer[i].image = new Image( width, height, camera->Colours(), camera->SubpixelOrder()); } } @@ -611,7 +606,6 @@ Monitor::~Monitor() { if ( (deinterlacing & 0xff) == 4) { delete next_buffer.image; - delete next_buffer.timestamp; } for ( int i = 0; i < image_buffer_count; i++ ) { delete image_buffer[i].image; @@ -636,7 +630,6 @@ Monitor::~Monitor() { if ( analysis_fps ) { for ( int i = 0; i < pre_event_buffer_count; i++ ) { delete pre_event_buffer[i].image; - delete pre_event_buffer[i].timestamp; } delete[] pre_event_buffer; } @@ -718,7 +711,7 @@ int Monitor::GetImage( int index, int scale ) { Image *image; // If we are going to be modifying the snapshot before writing, then we need to copy it if ( ( scale != ZM_SCALE_BASE ) || ( !config.timestamp_on_capture ) ) { - Snapshot *snap = &image_buffer[index]; + ZMPacket *snap = &image_buffer[index]; Image *snap_image = snap->image; alarm_image.Assign( *snap_image ); @@ -731,7 +724,7 @@ int Monitor::GetImage( int index, int scale ) { } if ( !config.timestamp_on_capture ) { - TimestampImage( &alarm_image, snap->timestamp ); + TimestampImage( &alarm_image, &snap->timestamp ); } image = &alarm_image; } else { @@ -753,13 +746,13 @@ struct timeval Monitor::GetTimestamp( int index ) const { } if ( index != image_buffer_count ) { - Snapshot *snap = &image_buffer[index]; + ZMPacket *snap = &image_buffer[index]; - return( *(snap->timestamp) ); + return snap->timestamp; } else { static struct timeval null_tv = { 0, 0 }; - return( null_tv ); + return null_tv; } } @@ -778,29 +771,29 @@ unsigned int Monitor::GetLastEvent() const { double Monitor::GetFPS() const { int index1 = shared_data->last_write_index; if ( index1 == image_buffer_count ) { - return( 0.0 ); + return 0.0; } - Snapshot *snap1 = &image_buffer[index1]; - if ( !snap1->timestamp || !snap1->timestamp->tv_sec ) { - return( 0.0 ); + ZMPacket *snap1 = &image_buffer[index1]; + if ( !snap1->timestamp.tv_sec ) { + return 0.0; } - struct timeval time1 = *snap1->timestamp; + struct timeval time1 = snap1->timestamp; int image_count = image_buffer_count; int index2 = (index1+1)%image_buffer_count; if ( index2 == image_buffer_count ) { - return( 0.0 ); + return 0.0; } - Snapshot *snap2 = &image_buffer[index2]; - while ( !snap2->timestamp || !snap2->timestamp->tv_sec ) { + ZMPacket *snap2 = &image_buffer[index2]; + while ( !snap2->timestamp.tv_sec ) { if ( index1 == index2 ) { - return( 0.0 ); + return 0.0; } index2 = (index2+1)%image_buffer_count; snap2 = &image_buffer[index2]; image_count--; } - struct timeval time2 = *snap2->timestamp; + struct timeval time2 = snap2->timestamp; double time_diff = tvDiffSec( time2, time1 ); @@ -808,9 +801,9 @@ double Monitor::GetFPS() const { if ( curr_fps < 0.0 ) { //Error( "Negative FPS %f, time_diff = %lf (%d:%ld.%ld - %d:%ld.%ld), ibc: %d", curr_fps, time_diff, index2, time2.tv_sec, time2.tv_usec, index1, time1.tv_sec, time1.tv_usec, image_buffer_count ); - return( 0.0 ); + return 0.0; } - return( curr_fps ); + return curr_fps; } useconds_t Monitor::GetAnalysisRate() { @@ -1028,7 +1021,7 @@ void Monitor::DumpZoneImage( const char *zone_string ) { if ( ( (!staticConfig.SERVER_ID) || ( staticConfig.SERVER_ID == server_id ) ) && mem_ptr ) { Debug(3, "Trying to load from local zmc"); int index = shared_data->last_write_index; - Snapshot *snap = &image_buffer[index]; + ZMPacket *snap = &image_buffer[index]; zone_image = new Image( *snap->image ); } else { Debug(3, "Trying to load from event"); @@ -1216,8 +1209,9 @@ bool Monitor::Analyse() { index = shared_data->last_write_index%image_buffer_count; } - Snapshot *snap = &image_buffer[index]; - struct timeval *timestamp = snap->timestamp; + ZMPacket *snap = &image_buffer[index]; + struct timeval *timestamp = &snap->timestamp; + Debug(2,timeval_to_string( *timestamp ) ); Image *snap_image = snap->image; if ( shared_data->action ) { @@ -1267,7 +1261,6 @@ bool Monitor::Analyse() { if ( static_undef ) { // Sure would be nice to be able to assume that these were already initialized. It's just 1 compare/branch, but really not neccessary. static_undef = false; - timestamps = new struct timeval *[pre_event_count]; images = new Image *[pre_event_count]; last_signal = shared_data->signal; } @@ -1419,56 +1412,6 @@ bool Monitor::Analyse() { if ( state == IDLE ) { shared_data->state = state = TAPE; } - - //if ( config.overlap_timed_events ) - if ( false ) { - int pre_index; - int pre_event_images = pre_event_count; - - if ( analysis_fps ) { - // If analysis fps is set, - // compute the index for pre event images in the dedicated buffer - pre_index = image_count%pre_event_buffer_count; - - // Seek forward the next filled slot in to the buffer (oldest data) - // from the current position - while ( pre_event_images && !pre_event_buffer[pre_index].timestamp->tv_sec ) { - pre_index = (pre_index + 1)%pre_event_buffer_count; - // Slot is empty, removing image from counter - pre_event_images--; - } - } else { - // If analysis fps is not set (analysis performed at capturing framerate), - // compute the index for pre event images in the capturing buffer - pre_index = ((index + image_buffer_count) - pre_event_count)%image_buffer_count; - - // Seek forward the next filled slot in to the buffer (oldest data) - // from the current position - while ( pre_event_images && !image_buffer[pre_index].timestamp->tv_sec ) { - pre_index = (pre_index + 1)%image_buffer_count; - // Slot is empty, removing image from counter - pre_event_images--; - } - } - - if ( pre_event_images ) { - if ( analysis_fps ) { - for ( int i = 0; i < pre_event_images; i++ ) { - timestamps[i] = pre_event_buffer[pre_index].timestamp; - images[i] = pre_event_buffer[pre_index].image; - pre_index = (pre_index + 1)%pre_event_buffer_count; - } - } else { - for ( int i = 0; i < pre_event_images; i++ ) { - timestamps[i] = image_buffer[pre_index].timestamp; - images[i] = image_buffer[pre_index].image; - pre_index = (pre_index + 1)%image_buffer_count; - } - } - - event->AddFrames( pre_event_images, images, timestamps ); - } - } // end if false or config.overlap_timed_events } // end if ! event } if ( score ) { @@ -1487,13 +1430,13 @@ bool Monitor::Analyse() { // Seek forward the next filled slot in to the buffer (oldest data) // from the current position - while ( pre_event_images && !pre_event_buffer[pre_index].timestamp->tv_sec ) { + while ( pre_event_images && !pre_event_buffer[pre_index].timestamp.tv_sec ) { pre_index = (pre_index + 1)%pre_event_buffer_count; // Slot is empty, removing image from counter pre_event_images--; } - event = new Event( this, *(pre_event_buffer[pre_index].timestamp), cause, noteSetMap ); + event = new Event( this, pre_event_buffer[pre_index].timestamp, cause, noteSetMap ); } else { // If analysis fps is not set (analysis performed at capturing framerate), // compute the index for pre event images in the capturing buffer @@ -1504,13 +1447,13 @@ bool Monitor::Analyse() { // Seek forward the next filled slot in to the buffer (oldest data) // from the current position - while ( pre_event_images && !image_buffer[pre_index].timestamp->tv_sec ) { + while ( pre_event_images && !image_buffer[pre_index].timestamp.tv_sec ) { pre_index = (pre_index + 1)%image_buffer_count; // Slot is empty, removing image from counter pre_event_images--; } - event = new Event( this, *(image_buffer[pre_index].timestamp), cause, noteSetMap ); + event = new Event( this, image_buffer[pre_index].timestamp, cause, noteSetMap ); } shared_data->last_event_id = event->Id(); //set up video store data @@ -1522,13 +1465,13 @@ bool Monitor::Analyse() { if ( pre_event_images ) { if ( analysis_fps ) { for ( int i = 0; i < pre_event_images; i++ ) { - timestamps[i] = pre_event_buffer[pre_index].timestamp; + timestamps[i] = &pre_event_buffer[pre_index].timestamp; images[i] = pre_event_buffer[pre_index].image; pre_index = (pre_index + 1)%pre_event_buffer_count; } } else { for ( int i = 0; i < pre_event_images; i++ ) { - timestamps[i] = image_buffer[pre_index].timestamp; + timestamps[i] = &image_buffer[pre_index].timestamp; images[i] = image_buffer[pre_index].image; pre_index = (pre_index + 1)%image_buffer_count; } @@ -1667,7 +1610,7 @@ bool Monitor::Analyse() { // If analysis fps is set, add analysed image to dedicated pre event buffer int pre_index = image_count%pre_event_buffer_count; pre_event_buffer[pre_index].image->Assign(*snap->image); - memcpy( pre_event_buffer[pre_index].timestamp, snap->timestamp, sizeof(struct timeval) ); + pre_event_buffer[pre_index].timestamp = snap->timestamp; } image_count++; @@ -2862,8 +2805,7 @@ int Monitor::Capture() { unsigned int index = image_count % image_buffer_count; Image* capture_image = image_buffer[index].image; - ZMPacket packet; - packet.set_image(capture_image); + ZMPacket *packet = &image_buffer[index]; int captureResult = 0; unsigned int deinterlacing_value = deinterlacing & 0xff; @@ -2874,14 +2816,17 @@ int Monitor::Capture() { } /* Capture a new next image */ - captureResult = camera->Capture(packet); + captureResult = camera->Capture(*packet); + gettimeofday( &packet->timestamp, NULL ); if ( FirstCapture ) { FirstCapture = 0; return 0; } } else { - captureResult = camera->Capture(packet); + captureResult = camera->Capture(*packet); + gettimeofday( &packet->timestamp, NULL ); + Debug(2,timeval_to_string( packet->timestamp ) ); if ( captureResult < 0 ) { // Unable to capture image for temporary reason // Fake a signal loss image @@ -2928,7 +2873,7 @@ int Monitor::Capture() { if ( (index == shared_data->last_read_index) && (function > MONITOR) ) { Warning( "Buffer overrun at index %d, image %d, slow down capture, speed up analysis or increase ring buffer size", index, image_count ); time_t now = time(0); - double approxFps = double(image_buffer_count)/double(now-image_buffer[index].timestamp->tv_sec); + double approxFps = double(image_buffer_count)/double(now-image_buffer[index].timestamp.tv_sec); time_t last_read_delta = now - shared_data->last_read_time; if ( last_read_delta > (image_buffer_count/approxFps) ) { Warning( "Last image read from shared memory %ld seconds ago, zma may have gone away", last_read_delta ) @@ -2940,7 +2885,7 @@ int Monitor::Capture() { capture_image->MaskPrivacy( privacy_bitmask ); if ( config.timestamp_on_capture ) { - TimestampImage( capture_image, &packet.timestamp ); + TimestampImage( capture_image, &packet->timestamp ); } int video_stream_id = camera->get_VideoStreamId(); @@ -2955,7 +2900,7 @@ int Monitor::Capture() { Debug(2, "Have videostore already?"); // 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. - int ret = videoStore->writePacket( &packet ); + int ret = videoStore->writePacket( packet ); if ( ret < 0 ) { //Less than zero and we skipped a frame Warning("Error writing last packet to videostore."); } @@ -2998,25 +2943,25 @@ int Monitor::Capture() { // Buffer video packets, since we are not recording. // All audio packets are keyframes, so only if it's a video keyframe - if ( ( packet.packet.stream_index == video_stream_id ) && ( packet.keyframe ) ) { + if ( ( packet->packet.stream_index == video_stream_id ) && ( packet->keyframe ) ) { packetqueue.clearQueue( this->GetPreEventCount(), video_stream_id ); } // The following lines should ensure that the queue always begins with a video keyframe - if ( packet.packet.stream_index == camera->get_AudioStreamId() ) { + if ( packet->packet.stream_index == camera->get_AudioStreamId() ) { //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 ); + packetqueue.queuePacket( packet ); } - } else if ( packet.packet.stream_index == video_stream_id ) { - if ( packet.keyframe || packetqueue.size() ) // it's a keyframe or we already have something in the queue - packetqueue.queuePacket( &packet ); + } else if ( packet->packet.stream_index == video_stream_id ) { + if ( packet->keyframe || packetqueue.size() ) // it's a keyframe or we already have something in the queue + packetqueue.queuePacket( packet ); } // end if audio or video } // end if recording or not if ( videoStore ) { //Write the packet to our video store, it will be smart enough to know what to do - int ret = videoStore->writePacket( &packet ); + int ret = videoStore->writePacket( packet ); if ( ret < 0 ) { //Less than zero and we skipped a frame Warning("problem writing packet"); } @@ -3025,7 +2970,7 @@ int Monitor::Capture() { shared_data->signal = CheckSignal(capture_image); shared_data->last_write_index = index; - shared_data->last_write_time = image_buffer[index].timestamp->tv_sec; + shared_data->last_write_time = image_buffer[index].timestamp.tv_sec; image_count++; @@ -3034,7 +2979,7 @@ int Monitor::Capture() { if ( !captureResult ) { gettimeofday( &now, NULL ); } else { - now.tv_sec = image_buffer[index].timestamp->tv_sec; + now.tv_sec = image_buffer[index].timestamp.tv_sec; } // If we are too fast, we get div by zero. This seems to happen in the case of audio packets. @@ -3355,6 +3300,6 @@ int Monitor::PostCapture() { } Monitor::Orientation Monitor::getOrientation() const { return orientation; } -Monitor::Snapshot *Monitor::getSnapshot() { +ZMPacket *Monitor::getSnapshot() { return &image_buffer[ shared_data->last_write_index%image_buffer_count ]; } diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 23d665f50..6de449bd7 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -153,13 +153,6 @@ protected: char trigger_showtext[256]; } TriggerData; - /* sizeof(Snapshot) expected to be 16 bytes on 32bit and 32 bytes on 64bit */ - struct Snapshot { - struct timeval *timestamp; - Image *image; - void* padding; - }; - //TODO: Technically we can't exclude this struct when people don't have avformat as the Memory.pm module doesn't know about avformat //sizeOf(VideoStoreData) expected to be 4104 bytes on 32bit and 64bit typedef struct { @@ -197,7 +190,6 @@ protected: int last_state; int last_event_id; - public: MonitorLink( int p_id, const char *p_name ); ~MonitorLink(); @@ -313,9 +305,9 @@ protected: TriggerData *trigger_data; VideoStoreData *video_store_data; - Snapshot *image_buffer; - Snapshot next_buffer; /* Used by four field deinterlacing */ - Snapshot *pre_event_buffer; + ZMPacket *image_buffer; + ZMPacket next_buffer; /* Used by four field deinterlacing */ + ZMPacket *pre_event_buffer; Camera *camera; @@ -444,7 +436,7 @@ public: unsigned int GetPreEventCount() const { return pre_event_count; }; State GetState() const; int GetImage( int index=-1, int scale=100 ); - Snapshot *getSnapshot(); + ZMPacket *getSnapshot(); struct timeval GetTimestamp( int index=-1 ) const; void UpdateAdaptiveSkip(); useconds_t GetAnalysisRate(); diff --git a/src/zm_monitorstream.cpp b/src/zm_monitorstream.cpp index 010877b90..3edfc6154 100644 --- a/src/zm_monitorstream.cpp +++ b/src/zm_monitorstream.cpp @@ -665,13 +665,13 @@ Debug(2, "Have checking command Queue for connkey: %d", connkey ); if ( (frame_mod == 1) || ((frame_count%frame_mod) == 0) ) { if ( !paused && !delayed ) { // Send the next frame - Monitor::Snapshot *snap = &monitor->image_buffer[index]; + ZMPacket *snap = &monitor->image_buffer[index]; - if ( !sendFrame( snap->image, snap->timestamp ) ) { + if ( !sendFrame( snap->image, &snap->timestamp ) ) { Debug(2, "sendFrame failed, quiting."); zm_terminate = true; } - memcpy( &last_frame_timestamp, snap->timestamp, sizeof(last_frame_timestamp) ); + last_frame_timestamp = snap->timestamp; //frame_sent = true; temp_read_index = temp_write_index; @@ -679,14 +679,14 @@ Debug(2, "Have checking command Queue for connkey: %d", connkey ); } if ( buffered_playback ) { if ( monitor->shared_data->valid ) { - if ( monitor->image_buffer[index].timestamp->tv_sec ) { + if ( monitor->image_buffer[index].timestamp.tv_sec ) { int temp_index = temp_write_index%temp_image_buffer_count; Debug( 2, "Storing frame %d", temp_index ); if ( !temp_image_buffer[temp_index].valid ) { snprintf( temp_image_buffer[temp_index].file_name, sizeof(temp_image_buffer[0].file_name), "%s/zmswap-i%05d.jpg", swap_path, temp_index ); temp_image_buffer[temp_index].valid = true; } - memcpy( &(temp_image_buffer[temp_index].timestamp), monitor->image_buffer[index].timestamp, sizeof(temp_image_buffer[0].timestamp) ); + temp_image_buffer[temp_index].timestamp = monitor->image_buffer[index].timestamp; monitor->image_buffer[index].image->WriteJpeg( temp_image_buffer[temp_index].file_name, config.jpeg_file_quality ); temp_write_index = MOD_ADD( temp_write_index, 1, temp_image_buffer_count ); if ( temp_write_index == temp_read_index ) { @@ -764,7 +764,7 @@ void MonitorStream::SingleImage( int scale ) { int img_buffer_size = 0; static JOCTET img_buffer[ZM_MAX_IMAGE_SIZE]; Image scaled_image; - Monitor::Snapshot *snap = monitor->getSnapshot(); + ZMPacket *snap = monitor->getSnapshot(); Image *snap_image = snap->image; if ( scale != ZM_SCALE_BASE ) { @@ -773,7 +773,7 @@ void MonitorStream::SingleImage( int scale ) { snap_image = &scaled_image; } if ( !config.timestamp_on_capture ) { - monitor->TimestampImage( snap_image, snap->timestamp ); + monitor->TimestampImage( snap_image, &snap->timestamp ); } snap_image->EncodeJpeg( img_buffer, &img_buffer_size ); @@ -784,7 +784,7 @@ void MonitorStream::SingleImage( int scale ) { void MonitorStream::SingleImageRaw( int scale ) { Image scaled_image; - Monitor::Snapshot *snap = monitor->getSnapshot(); + ZMPacket *snap = monitor->getSnapshot(); Image *snap_image = snap->image; if ( scale != ZM_SCALE_BASE ) { @@ -793,7 +793,7 @@ void MonitorStream::SingleImageRaw( int scale ) { snap_image = &scaled_image; } if ( !config.timestamp_on_capture ) { - monitor->TimestampImage( snap_image, snap->timestamp ); + monitor->TimestampImage( snap_image, &snap->timestamp ); } fprintf( stdout, "Content-Length: %d\r\n", snap_image->Size() ); @@ -806,7 +806,7 @@ void MonitorStream::SingleImageZip( int scale ) { static Bytef img_buffer[ZM_MAX_IMAGE_SIZE]; Image scaled_image; - Monitor::Snapshot *snap = monitor->getSnapshot(); + ZMPacket *snap = monitor->getSnapshot(); Image *snap_image = snap->image; if ( scale != ZM_SCALE_BASE ) { @@ -815,7 +815,7 @@ void MonitorStream::SingleImageZip( int scale ) { snap_image = &scaled_image; } if ( !config.timestamp_on_capture ) { - monitor->TimestampImage( snap_image, snap->timestamp ); + monitor->TimestampImage( snap_image, &snap->timestamp ); } snap_image->Zip( img_buffer, &img_buffer_size ); diff --git a/src/zm_packet.cpp b/src/zm_packet.cpp index e9fcf9c58..71a154625 100644 --- a/src/zm_packet.cpp +++ b/src/zm_packet.cpp @@ -29,8 +29,8 @@ ZMPacket::ZMPacket( ) { image = NULL; frame = NULL; av_init_packet( &packet ); - packet.size = 0; - gettimeofday( ×tamp, NULL ); + packet.size = 0; // So we can detect whether it has been filled. + timestamp = (struct timeval){0}; } ZMPacket::ZMPacket( Image *i ) { @@ -38,7 +38,7 @@ ZMPacket::ZMPacket( Image *i ) { image = i; frame = NULL; av_init_packet( &packet ); - gettimeofday( ×tamp, NULL ); + timestamp = (struct timeval){0}; } ZMPacket::ZMPacket( AVPacket *p ) { @@ -71,6 +71,13 @@ ZMPacket::~ZMPacket() { //} } +void ZMPacket::reset() { + zm_av_packet_unref( &packet ); + if ( frame ) { + av_frame_free( &frame ); + } +} + int ZMPacket::decode( AVCodecContext *ctx ) { Debug(4, "about to decode video" ); diff --git a/src/zm_packet.h b/src/zm_packet.h index bf1b65d4c..e19b4de37 100644 --- a/src/zm_packet.h +++ b/src/zm_packet.h @@ -36,7 +36,7 @@ class ZMPacket { int keyframe; AVPacket packet; // Input packet, undecoded AVFrame *frame; // Input image, decoded Theoretically only filled if needed. - Image *image; // Our internal image oject representing this frame + Image *image; // Our internal image object representing this frame struct timeval timestamp; public: AVPacket *av_packet() { return &packet; } @@ -47,6 +47,7 @@ class ZMPacket { int is_keyframe() { return keyframe; }; int decode( AVCodecContext *ctx ); + void reset(); ZMPacket( AVPacket *packet, struct timeval *timestamp ); ZMPacket( AVPacket *packet ); ZMPacket( AVPacket *packet, AVFrame *frame, Image *image ); From 043e44d273a3a65722ee5324841fc012ee96b7a3 Mon Sep 17 00:00:00 2001 From: APHW2 MFGENG Date: Mon, 13 Nov 2017 14:24:28 -0800 Subject: [PATCH 0025/2339] fix, must clear the frame --- src/zm_analysis_thread.cpp | 3 --- src/zm_camera.h | 4 ++-- src/zm_image.cpp | 2 +- src/zm_image.h | 6 +++++- src/zm_monitor.cpp | 2 ++ src/zm_packet.cpp | 1 + src/zm_remote_camera_nvsocket.cpp | 24 ++++++++++++++++++++++++ src/zm_remote_camera_nvsocket.h | 1 + src/zm_videostore.cpp | 14 +++++++++----- 9 files changed, 45 insertions(+), 12 deletions(-) diff --git a/src/zm_analysis_thread.cpp b/src/zm_analysis_thread.cpp index b08632ac9..a6eec451f 100644 --- a/src/zm_analysis_thread.cpp +++ b/src/zm_analysis_thread.cpp @@ -29,13 +29,10 @@ int AnalysisThread::run() { if ( analysis_update_delay ) { cur_time = time( 0 ); if ( (unsigned int)( cur_time - last_analysis_update_time ) > analysis_update_delay ) { -Debug(4, "Updating " ); analysis_rate = monitor->GetAnalysisRate(); monitor->UpdateAdaptiveSkip(); last_analysis_update_time = cur_time; } - } else { -Debug(4, "Not Updating " ); } if ( !monitor->Analyse() ) { diff --git a/src/zm_camera.h b/src/zm_camera.h index 9d3447fe4..3cc93f5cf 100644 --- a/src/zm_camera.h +++ b/src/zm_camera.h @@ -107,8 +107,8 @@ public: virtual int PreCapture()=0; virtual int Capture(ZMPacket &p)=0; virtual int PostCapture()=0; - AVStream *get_VideoStream() { return NULL; }; - AVStream *get_AudioStream() { return NULL; }; + virtual AVStream *get_VideoStream() { return NULL; }; + virtual AVStream *get_AudioStream() { return NULL; }; int get_VideoStreamId() { return mVideoStreamId; }; int get_AudioStreamId() { return mAudioStreamId; }; }; diff --git a/src/zm_image.cpp b/src/zm_image.cpp index e8293b3fb..11cb193c0 100644 --- a/src/zm_image.cpp +++ b/src/zm_image.cpp @@ -610,7 +610,7 @@ void Image::Assign(const unsigned int p_width, const unsigned int p_height, cons size = new_size; } - if(new_buffer != buffer) + if ( new_buffer != buffer ) (*fptr_imgbufcpy)(buffer, new_buffer, size); } diff --git a/src/zm_image.h b/src/zm_image.h index e75a5e357..e837ed1b0 100644 --- a/src/zm_image.h +++ b/src/zm_image.h @@ -173,7 +173,11 @@ public: if ( colours == ZM_COLOUR_RGB32 ) { return AV_PIX_FMT_RGBA; } else if ( colours == ZM_COLOUR_RGB24 ) { - return AV_PIX_FMT_RGB24; + if ( subpixelorder == ZM_SUBPIX_ORDER_BGR){ + return AV_PIX_FMT_BGR24; + } else { + return AV_PIX_FMT_RGB24; + } } else if ( colours == ZM_COLOUR_GRAY8 ) { return AV_PIX_FMT_GRAY8; } else { diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index eba8234a4..b5be3a9e9 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -2795,6 +2795,8 @@ int Monitor::Capture() { unsigned int index = image_count % image_buffer_count; Image* capture_image = image_buffer[index].image; ZMPacket *packet = &image_buffer[index]; +// clears frame +packet->reset(); int captureResult = 0; unsigned int deinterlacing_value = deinterlacing & 0xff; diff --git a/src/zm_packet.cpp b/src/zm_packet.cpp index f60a19390..df7a776cb 100644 --- a/src/zm_packet.cpp +++ b/src/zm_packet.cpp @@ -63,6 +63,7 @@ ZMPacket::ZMPacket( AVPacket *p, AVFrame *f, Image *i ) { ZMPacket::~ZMPacket() { zm_av_packet_unref( &packet ); if ( frame ) { + //av_free(frame->data); av_frame_free( &frame ); } // We assume the image was allocated elsewhere, so we just unref it. diff --git a/src/zm_remote_camera_nvsocket.cpp b/src/zm_remote_camera_nvsocket.cpp index 88227735b..e9fe1ac60 100644 --- a/src/zm_remote_camera_nvsocket.cpp +++ b/src/zm_remote_camera_nvsocket.cpp @@ -68,6 +68,7 @@ RemoteCameraNVSocket::RemoteCameraNVSocket( timeout.tv_sec = 0; timeout.tv_usec = 0; subpixelorder = ZM_SUBPIX_ORDER_BGR; + video_stream = NULL; if ( capture ) { Initialise(); @@ -212,3 +213,26 @@ int RemoteCameraNVSocket::Capture( ZMPacket &zm_packet ) { int RemoteCameraNVSocket::PostCapture() { return( 0 ); } +AVStream *RemoteCameraNVSocket::get_VideoStream() { + if ( ! video_stream ) { + AVFormatContext *oc = avformat_alloc_context(); + video_stream = avformat_new_stream( oc, NULL ); + if ( video_stream ) { +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + video_stream->codecpar->width = width; + video_stream->codecpar->height = height; + video_stream->codecpar->format = GetFFMPEGPixelFormat(colours,subpixelorder); +#else + video_stream->codec->width = width; + video_stream->codec->height = height; + video_stream->codec->pix_fmt = GetFFMPEGPixelFormat(colours,subpixelorder); +#endif + } else { + Error("Can't create video stream"); + } +} else { +Debug(2,"Have videostream"); + } +Debug(2,"Get videoStream"); + return video_stream; +} diff --git a/src/zm_remote_camera_nvsocket.h b/src/zm_remote_camera_nvsocket.h index 990d34aec..45f1e5cf8 100644 --- a/src/zm_remote_camera_nvsocket.h +++ b/src/zm_remote_camera_nvsocket.h @@ -69,6 +69,7 @@ bool p_record_audio ); int PrimeCapture(); int Capture( ZMPacket &p ); int PostCapture(); +AVStream* get_VideoStream(); }; #endif // ZM_REMOTE_CAMERA_NVSOCKET_H diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index b47a2acac..9f1a67dd9 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -87,9 +87,12 @@ VideoStore::VideoStore( video_in_stream_index = video_in_stream->index; #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) video_in_ctx = avcodec_alloc_context3(NULL); +Debug(2,"About to copy aparames"); avcodec_parameters_to_context(video_in_ctx, video_in_stream->codecpar); zm_dump_codecpar( video_in_stream->codecpar ); +Debug(2,"About to copy aparames"); +//video_in_ctx.codec_id = video_in_stream->codecpar.codec_id; #else video_in_ctx = video_in_stream->codec; #endif @@ -100,6 +103,7 @@ VideoStore::VideoStore( } video_out_ctx = NULL; + video_out_ctx = avcodec_alloc_context3(NULL); // Copy params from instream to ctx if ( video_in_stream && ( video_in_ctx->codec_id == AV_CODEC_ID_H264 ) ) { @@ -114,13 +118,10 @@ VideoStore::VideoStore( zm_dump_codec(video_out_ctx); } #else - video_out_ctx = avcodec_alloc_context3(NULL); avcodec_copy_context( video_out_ctx, video_in_ctx ); #endif // Same codec, just copy the packets, otherwise we have to decode/encode video_out_codec = (AVCodec *)video_in_ctx->codec; - video_out_ctx->time_base = video_in_ctx->time_base; - video_out_stream->time_base = video_in_stream->time_base; } else { /** Create a new frame to store the */ @@ -168,8 +169,11 @@ VideoStore::VideoStore( Debug( 3, "Encoder Option %s=%s", e->key, e->value ); } } - if ( ! av_dict_get( opts, "preset", NULL, 0 ) ) - av_dict_set( &opts, "preset", "superfast", 0 ); + + if ( ! av_dict_get( opts, "preset", NULL, 0 ) ) { + Debug(2,"Setting preset to superfast"); + av_dict_set( &opts, "preset", "superfast", 0 ); + } if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) { Warning("Can't open video codec (%s)! %s, trying h264", From df0d37f4eb101c95f032456129f0dea2527a0a95 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 13 Nov 2017 21:29:15 -0500 Subject: [PATCH 0026/2339] add saveJPEGS to the event record --- db/zm_create.sql.in | 3 ++- src/zm_event.cpp | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index b46d5c0bd..6b4cabef9 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -195,6 +195,7 @@ CREATE TABLE `Events` ( `Frames` int(10) unsigned default NULL, `AlarmFrames` int(10) unsigned default NULL, `DefaultVideo` VARCHAR( 64 ) DEFAULT '' NOT NULL, + `SaveJPEGs` TINYINT, `TotScore` int(10) unsigned NOT NULL default '0', `AvgScore` smallint(5) unsigned default '0', `MaxScore` smallint(5) unsigned default '0', @@ -384,7 +385,7 @@ CREATE TABLE `Monitors` ( `Deinterlacing` int(10) unsigned NOT NULL default '0', `SaveJPEGs` TINYINT NOT NULL DEFAULT '3' , `VideoWriter` TINYINT NOT NULL DEFAULT '0', - `OutputCodec` enum('h264','mjpeg'), + `OutputCodec` enum('h264','mjpeg','mpeg1','mpeg2'), `OutputContainer` enum('mp4','mkv'), `EncoderParameters` TEXT, `RecordAudio` TINYINT NOT NULL DEFAULT '0', diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 3e9b46514..3640f8db5 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -71,7 +71,7 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string static char sql[ZM_SQL_MED_BUFSIZ]; struct tm *stime = localtime( &start_time.tv_sec ); - snprintf( sql, sizeof(sql), "insert into Events ( MonitorId, StorageId, Name, StartTime, Width, Height, Cause, Notes, StateId, Orientation, Videoed, DefaultVideo ) values ( %d, %d, 'New Event', from_unixtime( %ld ), %d, %d, '%s', '%s', %d, %d, %d, '' )", + snprintf( sql, sizeof(sql), "insert into Events ( MonitorId, StorageId, Name, StartTime, Width, Height, Cause, Notes, StateId, Orientation, Videoed, DefaultVideo, SaveJPEGS ) values ( %d, %d, 'New Event', from_unixtime( %ld ), %d, %d, '%s', '%s', %d, %d, %d, '', %d )", monitor->Id(), storage->Id(), start_time.tv_sec, @@ -81,7 +81,8 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string notes.c_str(), state_id, monitor->getOrientation(), - videoEvent + videoEvent, + monitor->GetOptSaveJPEGs() ); if ( mysql_query( &dbconn, sql ) ) { Error( "Can't insert event: %s. sql was (%s)", mysql_error( &dbconn ), sql ); From 39b12057f2f9f208d4c93cbf6d8479c338af2dde Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 13 Nov 2017 21:34:39 -0500 Subject: [PATCH 0027/2339] add saveJPEGs to Events --- db/zm_update-1.31.11.sql | 1 + db/zm_update-1.31.13.sql | 13 +++++++++++++ src/zm_event.cpp | 2 +- src/zm_logger.cpp | 1 + src/zm_packet.cpp | 14 ++++++++++++++ src/zm_packet.h | 1 + src/zm_swscale.cpp | 26 ++++++++++++++++++-------- src/zm_videostore.cpp | 20 +++++++++++--------- src/zmc.cpp | 8 ++++---- version | 2 +- 10 files changed, 65 insertions(+), 23 deletions(-) create mode 100644 db/zm_update-1.31.13.sql diff --git a/db/zm_update-1.31.11.sql b/db/zm_update-1.31.11.sql index de17d85d9..e0772cef4 100644 --- a/db/zm_update-1.31.11.sql +++ b/db/zm_update-1.31.11.sql @@ -67,3 +67,4 @@ SET @s = (SELECT IF( PREPARE stmt FROM @s; EXECUTE stmt; + diff --git a/db/zm_update-1.31.13.sql b/db/zm_update-1.31.13.sql new file mode 100644 index 000000000..bd102043f --- /dev/null +++ b/db/zm_update-1.31.13.sql @@ -0,0 +1,13 @@ +ALTER TABLE `Monitors` MODIFY `OutputCodec` enum('h264','mjpeg','mpeg1','mpeg2') + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Events' + AND column_name = 'SaveJPEGs' + ) > 0, +"SELECT 'Column SaveJPEGs already exists in Events'", +"ALTER TABLE `Eventss` ADD `SaveJPEGs` TINYINT AFTER `DefaultVideo`" +)); + +PREPARE stmt FROM @s; +EXECUTE stmt; diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 3640f8db5..a74d46038 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -71,7 +71,7 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string static char sql[ZM_SQL_MED_BUFSIZ]; struct tm *stime = localtime( &start_time.tv_sec ); - snprintf( sql, sizeof(sql), "insert into Events ( MonitorId, StorageId, Name, StartTime, Width, Height, Cause, Notes, StateId, Orientation, Videoed, DefaultVideo, SaveJPEGS ) values ( %d, %d, 'New Event', from_unixtime( %ld ), %d, %d, '%s', '%s', %d, %d, %d, '', %d )", + snprintf( sql, sizeof(sql), "insert into Events ( MonitorId, StorageId, Name, StartTime, Width, Height, Cause, Notes, StateId, Orientation, Videoed, DefaultVideo, SaveJPEGs ) values ( %d, %d, 'New Event', from_unixtime( %ld ), %d, %d, '%s', '%s', %d, %d, %d, '', %d )", monitor->Id(), storage->Id(), start_time.tv_sec, diff --git a/src/zm_logger.cpp b/src/zm_logger.cpp index 0196e3e6d..ffebff726 100644 --- a/src/zm_logger.cpp +++ b/src/zm_logger.cpp @@ -36,6 +36,7 @@ #ifdef __FreeBSD__ #include #endif +#include bool Logger::smInitialised = false; Logger *Logger::smInstance = 0; diff --git a/src/zm_packet.cpp b/src/zm_packet.cpp index df7a776cb..557fc1983 100644 --- a/src/zm_packet.cpp +++ b/src/zm_packet.cpp @@ -28,6 +28,7 @@ ZMPacket::ZMPacket( ) { keyframe = 0; image = NULL; frame = NULL; + buffer = NULL; av_init_packet( &packet ); packet.size = 0; // So we can detect whether it has been filled. timestamp = (struct timeval){0}; @@ -37,6 +38,7 @@ ZMPacket::ZMPacket( Image *i ) { keyframe = 1; image = i; frame = NULL; + buffer = NULL; av_init_packet( &packet ); timestamp = (struct timeval){0}; } @@ -45,6 +47,7 @@ ZMPacket::ZMPacket( AVPacket *p ) { av_init_packet( &packet ); set_packet( p ); keyframe = p->flags & AV_PKT_FLAG_KEY; + buffer = NULL; } ZMPacket::ZMPacket( AVPacket *p, struct timeval *t ) { @@ -52,12 +55,14 @@ ZMPacket::ZMPacket( AVPacket *p, struct timeval *t ) { set_packet( p ); timestamp = *t; keyframe = p->flags & AV_PKT_FLAG_KEY; + buffer = NULL; } ZMPacket::ZMPacket( AVPacket *p, AVFrame *f, Image *i ) { av_init_packet( &packet ); set_packet( p ); image = i; frame = f; + buffer = NULL; } ZMPacket::~ZMPacket() { @@ -66,15 +71,24 @@ ZMPacket::~ZMPacket() { //av_free(frame->data); av_frame_free( &frame ); } + if ( buffer ) { + av_freep( &buffer ); + } // We assume the image was allocated elsewhere, so we just unref it. image = NULL; } void ZMPacket::reset() { + Debug(2,"reset"); zm_av_packet_unref( &packet ); + packet.size = 0; if ( frame ) { av_frame_free( &frame ); } + if ( buffer ) { + Debug(2,"freeing buffer"); + av_freep( &buffer ); + } } int ZMPacket::decode( AVCodecContext *ctx ) { diff --git a/src/zm_packet.h b/src/zm_packet.h index e19b4de37..590ff5dc6 100644 --- a/src/zm_packet.h +++ b/src/zm_packet.h @@ -36,6 +36,7 @@ class ZMPacket { int keyframe; AVPacket packet; // Input packet, undecoded AVFrame *frame; // Input image, decoded Theoretically only filled if needed. + uint8_t *buffer; Image *image; // Our internal image object representing this frame struct timeval timestamp; public: diff --git a/src/zm_swscale.cpp b/src/zm_swscale.cpp index 2dc391eb0..2df94775c 100644 --- a/src/zm_swscale.cpp +++ b/src/zm_swscale.cpp @@ -78,7 +78,17 @@ int SWScale::SetDefaults(enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, return 0; } -int SWScale::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) { + +int SWScale::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 + ) { /* Parameter checking */ if(in_buffer == NULL || out_buffer == NULL) { Error("NULL Input or output buffer"); @@ -119,14 +129,14 @@ int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint size_t outsize = avpicture_get_size(out_pf, width, height); #endif - if(outsize < out_buffer_size) { + 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( swscale_ctx, width, height, in_pf, width, height, out_pf, SWS_FAST_BILINEAR, NULL, NULL, NULL ); - if(swscale_ctx == NULL) { + if ( swscale_ctx == NULL ) { Error("Failed getting swscale context"); return -6; } @@ -163,22 +173,22 @@ int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint } int SWScale::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) { - if(img->Width() != width) { + if ( img->Width() != width ) { Error("Source image width differs. Source: %d Output: %d",img->Width(), width); return -12; } - if(img->Height() != height) { + if ( img->Height() != height ) { Error("Source image height differs. Source: %d Output: %d",img->Height(), height); return -13; } - return Convert(img->Buffer(),img->Size(),out_buffer,out_buffer_size,in_pf,out_pf,width,height); + return Convert(img->Buffer(), img->Size(), out_buffer, out_buffer_size, in_pf, out_pf, width, height); } int SWScale::ConvertDefaults(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size) { - if(!gotdefaults) { + if ( !gotdefaults ) { Error("Defaults are not set"); return -24; } @@ -188,7 +198,7 @@ int SWScale::ConvertDefaults(const Image* img, uint8_t* out_buffer, const size_t int SWScale::ConvertDefaults(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size) { - if(!gotdefaults) { + if ( !gotdefaults ) { Error("Defaults are not set"); return -24; } diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 9f1a67dd9..113d3b7e9 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -472,7 +472,8 @@ Debug(2,"Different codecs between in and out"); break; } #endif -Debug(3, "dts:%d, pts:%d", pkt.dts, pkt.pts ); + int keyframe = pkt.flags & AV_PKT_FLAG_KEY; +Debug(3, "dts:%d, pts:%d, keyframe:%d", pkt.dts, pkt.pts, keyframe ); //pkt.dts = video_next_dts; pkt.pts = pkt.dts; //pkt.duration = video_last_duration; @@ -854,11 +855,11 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { video_out_ctx->pix_fmt, video_out_ctx->width, video_out_ctx->height, 1); - uint8_t *buffer = (uint8_t *)av_malloc(codec_imgsize); + zm_packet->buffer = (uint8_t *)av_malloc(codec_imgsize); av_image_fill_arrays( frame->data, frame->linesize, - buffer, + zm_packet->buffer, video_out_ctx->pix_fmt, video_out_ctx->width, video_out_ctx->height, @@ -868,10 +869,10 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { video_out_ctx->pix_fmt, video_out_ctx->width, video_out_ctx->height); - uint8_t *buffer = (uint8_t *)av_malloc(codec_imgsize); + zm_packet->buffer = (uint8_t *)av_malloc(codec_imgsize); avpicture_fill( (AVPicture *)frame, - buffer, + zm_packet->buffer, video_out_ctx->pix_fmt, video_out_ctx->width, video_out_ctx->height @@ -882,7 +883,7 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { frame->height = video_out_ctx->height; frame->format = video_out_ctx->pix_fmt; swscale.Convert(zm_packet->image, - buffer, + zm_packet->buffer, codec_imgsize, (AVPixelFormat)zm_packet->image->AVPixFormat(), video_out_ctx->pix_fmt, @@ -942,6 +943,8 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { opkt.flags = ipkt->flags; } + int keyframe = opkt.flags & AV_PKT_FLAG_KEY; +Debug(3, "dts:%d, pts:%d, keyframe:%d", opkt.dts, opkt.pts, keyframe ); write_video_packet( opkt ); zm_av_packet_unref(&opkt); @@ -950,7 +953,7 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { void VideoStore::write_video_packet( AVPacket &opkt ) { - if (opkt.dts > opkt.pts) { + if ( opkt.dts > opkt.pts ) { Debug(1, "opkt.dts(%d) must be <= opkt.pts(%d). Decompression must happen " "before presentation.", @@ -981,8 +984,7 @@ void VideoStore::write_video_packet( AVPacket &opkt ) { //dumpPacket(&opkt); } else { - ret = av_interleaved_write_frame(oc, &opkt); - if (ret < 0) { + if ( (ret = av_interleaved_write_frame(oc, &opkt)) < 0 ) { // There's nothing we can really do if the frame is rejected, just drop it // and get on with the next Warning( diff --git a/src/zmc.cpp b/src/zmc.cpp index b7a6d83bf..224583d7a 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -269,8 +269,8 @@ int main(int argc, char *argv[]) { struct timeval now; struct DeltaTimeval delta_time; while ( !zm_terminate ) { - Debug(2,"blocking"); - //sigprocmask(SIG_BLOCK, &block_set, 0); + //Debug(2,"blocking"); + sigprocmask(SIG_BLOCK, &block_set, 0); for ( int i = 0; i < n_monitors; i++ ) { long min_delay = MAXINT; @@ -327,8 +327,8 @@ int main(int argc, char *argv[]) { } // end if next_delay <= min_delay || next_delays[i] <= 0 ) } // end foreach n_monitors - Debug(2,"unblocking"); - //sigprocmask(SIG_UNBLOCK, &block_set, 0); + //Debug(2,"unblocking"); + sigprocmask(SIG_UNBLOCK, &block_set, 0); } // end while ! zm_terminate for ( int i = 0; i < n_monitors; i++ ) { if ( analysis_threads[i] ) { diff --git a/version b/version index 623203d2d..45eecfe53 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.31.12 +1.31.13 From bafdf1fdfc1b2d972bf1a2628514247c6b129af3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 13 Nov 2017 21:41:57 -0500 Subject: [PATCH 0028/2339] add codecs and containers --- web/includes/Event.php | 1 + web/includes/Monitor.php | 2 ++ web/skins/classic/views/monitor.php | 16 ++++++++++++++++ 3 files changed, 19 insertions(+) diff --git a/web/includes/Event.php b/web/includes/Event.php index 9f775f039..189f4eefe 100644 --- a/web/includes/Event.php +++ b/web/includes/Event.php @@ -9,6 +9,7 @@ class Event { 'StorageId', 'Name', 'DiskSpace', +'SaveJPEGs', ); public function __construct( $IdOrRow = null ) { $row = NULL; diff --git a/web/includes/Monitor.php b/web/includes/Monitor.php index f8c9940c2..c95a11975 100644 --- a/web/includes/Monitor.php +++ b/web/includes/Monitor.php @@ -15,6 +15,8 @@ private $defaults = array( 'Height' => null, 'Orientation' => null, 'AnalysisFPSLimit' => null, +'OutputCodec', +'OutputContainer', ); private $control_fields = array( 'Name' => '', diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index ef15bf1e8..8920a8131 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -471,6 +471,18 @@ $videowriteropts = array( 'X264 Encode' => 1, 'H264 Camera Passthrough' => 2 ); +$videowriter_codecs = array( + '' => translate('Disabled'), + 'h264' => 'h264', + 'mjpeg' => 'mjpeg', + 'mpeg1' => 'mpeg1', + 'mpeg2' => 'mpeg2', +); +$videowriter_containers = array( + '' => translate('Auto'), + 'mp4' => 'mp4', + 'mkv' => 'mkv', +); xhtmlHeaders(__FILE__, translate('Monitor')." - ".validHtmlStr($monitor->Name()) ); ?> @@ -597,6 +609,8 @@ if ( $tab != 'storage' ) { ?> + + Type() == 'Local' ) { ?> + OutputCodec() );?> + OutputContainer() );?> RecordAudio() ) { ?> checked="checked"/> Date: Tue, 14 Nov 2017 01:59:15 -0500 Subject: [PATCH 0029/2339] add mjpeg support --- db/zm_create.sql.in | 2 +- db/zm_update-1.31.13.sql | 5 +- src/zm_event.cpp | 11 +- src/zm_monitor.cpp | 36 ++++- src/zm_monitor.h | 6 + src/zm_videostore.cpp | 152 ++++++++++--------- web/skins/classic/js/skin.js | 2 +- web/skins/classic/views/_monitor_filters.php | 11 +- web/skins/classic/views/event.php | 8 +- 9 files changed, 147 insertions(+), 86 deletions(-) diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index 6b4cabef9..df7a486c0 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -386,7 +386,7 @@ CREATE TABLE `Monitors` ( `SaveJPEGs` TINYINT NOT NULL DEFAULT '3' , `VideoWriter` TINYINT NOT NULL DEFAULT '0', `OutputCodec` enum('h264','mjpeg','mpeg1','mpeg2'), - `OutputContainer` enum('mp4','mkv'), + `OutputContainer` enum('auto','mp4','mkv'), `EncoderParameters` TEXT, `RecordAudio` TINYINT NOT NULL DEFAULT '0', `RTSPDescribe` tinyint(1) unsigned, diff --git a/db/zm_update-1.31.13.sql b/db/zm_update-1.31.13.sql index bd102043f..a68936e6b 100644 --- a/db/zm_update-1.31.13.sql +++ b/db/zm_update-1.31.13.sql @@ -1,4 +1,5 @@ -ALTER TABLE `Monitors` MODIFY `OutputCodec` enum('h264','mjpeg','mpeg1','mpeg2') +ALTER TABLE `Monitors` MODIFY `OutputCodec` enum('h264','mjpeg','mpeg1','mpeg2') default 'h264'; +ALTER TABLE `Monitors` MODIFY `OutputContainer` enum('auto','mp4','mkv') default 'auto'; SET @s = (SELECT IF( (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() @@ -6,7 +7,7 @@ SET @s = (SELECT IF( AND column_name = 'SaveJPEGs' ) > 0, "SELECT 'Column SaveJPEGs already exists in Events'", -"ALTER TABLE `Eventss` ADD `SaveJPEGs` TINYINT AFTER `DefaultVideo`" +"ALTER TABLE `Events` ADD `SaveJPEGs` TINYINT AFTER `DefaultVideo`" )); PREPARE stmt FROM @s; diff --git a/src/zm_event.cpp b/src/zm_event.cpp index a74d46038..10e58ad7b 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -167,7 +167,16 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string /* Save as video */ if ( monitor->GetOptVideoWriter() != 0 ) { - snprintf( video_name, sizeof(video_name), "%d-%s", id, "video.mp4" ); + std::string container = monitor->OutputContainer(); + if ( container == "auto" || container == "" ) { + if ( monitor->OutputCodec() == "h264" ) { + container = "mp4"; + } else { + container = "mkv"; + } + } + + snprintf( video_name, sizeof(video_name), "%d-%s.%s", id, "video", container.c_str() ); snprintf( video_file, sizeof(video_file), staticConfig.video_file_format, path, video_name ); Debug(1,"Writing video file to %s", video_file ); videowriter = NULL; diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index b5be3a9e9..750ab0b26 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -243,6 +243,8 @@ Monitor::Monitor( int p_savejpegs, VideoWriter p_videowriter, std::string p_encoderparams, + std::string p_output_codec, + std::string p_output_container, bool p_record_audio, const char *p_event_prefix, const char *p_label_format, @@ -282,6 +284,8 @@ Monitor::Monitor( savejpegspref( p_savejpegs ), videowriter( p_videowriter ), encoderparams( p_encoderparams ), + output_codec( p_output_codec ), + output_container( p_output_container ), record_audio( p_record_audio ), label_coord( p_label_coord ), label_size( p_label_size ), @@ -1781,7 +1785,7 @@ void Monitor::ReloadLinkedMonitors( const char *p_linked_monitors ) { #if ZM_HAS_V4L int Monitor::LoadLocalMonitors( const char *device, Monitor **&monitors, Purpose purpose ) { - std::string sql = "select Id, Name, ServerId, StorageId, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, Method, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour, Exif from Monitors where Function != 'None' and Type = 'Local'"; + std::string sql = "select Id, Name, ServerId, StorageId, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, Method, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, OutputCodec, OutputContainer, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour, Exif from Monitors where Function != 'None' and Type = 'Local'"; ; if ( device[0] ) { sql += " AND Device='"; @@ -1846,6 +1850,8 @@ int Monitor::LoadLocalMonitors( const char *device, Monitor **&monitors, Purpose int savejpegs = atoi(dbrow[col]); col++; VideoWriter videowriter = (VideoWriter)atoi(dbrow[col]); col++; std::string encoderparams = dbrow[col] ? dbrow[col] : ""; col++; + std::string output_codec = dbrow[col] ? dbrow[col] : ""; col++; + std::string output_container = dbrow[col] ? dbrow[col] : ""; col++; bool record_audio = (*dbrow[col] != '0'); col++; int brightness = atoi(dbrow[col]); col++; @@ -1923,6 +1929,8 @@ int Monitor::LoadLocalMonitors( const char *device, Monitor **&monitors, Purpose savejpegs, videowriter, encoderparams, + output_codec, + output_container, record_audio, event_prefix, label_format, @@ -1970,7 +1978,7 @@ int Monitor::LoadLocalMonitors( const char *device, Monitor **&monitors, Purpose #endif // ZM_HAS_V4L int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const char *port, const char *path, Monitor **&monitors, Purpose purpose ) { - std::string sql = "select Id, Name, ServerId, StorageId, Function+0, Enabled, LinkedMonitors, Protocol, Method, Host, Port, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, RTSPDescribe, SaveJPEGs, VideoWriter, EncoderParameters, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'Remote'"; + std::string sql = "select Id, Name, ServerId, StorageId, Function+0, Enabled, LinkedMonitors, Protocol, Method, Host, Port, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, RTSPDescribe, SaveJPEGs, VideoWriter, EncoderParameters, OutputCodec, OutputContainer, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'Remote'"; if ( staticConfig.SERVER_ID ) { sql += stringtf( " AND ServerId=%d", staticConfig.SERVER_ID ); } @@ -2016,6 +2024,8 @@ int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const c int savejpegs = atoi(dbrow[col]); col++; VideoWriter videowriter = (VideoWriter)atoi(dbrow[col]); col++; std::string encoderparams = dbrow[col] ? dbrow[col] : ""; col++; + std::string output_codec = dbrow[col] ? dbrow[col] : ""; col++; + std::string output_container = dbrow[col] ? dbrow[col] : ""; col++; bool record_audio = (*dbrow[col] != '0'); col++; int brightness = atoi(dbrow[col]); col++; @@ -2107,6 +2117,8 @@ int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const c savejpegs, videowriter, encoderparams, + output_codec, + output_container, record_audio, event_prefix, label_format, @@ -2153,7 +2165,7 @@ int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const c } int Monitor::LoadFileMonitors( const char *file, Monitor **&monitors, Purpose purpose ) { - std::string sql = "select Id, Name, ServerId, StorageId, Function+0, Enabled, LinkedMonitors, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'File'"; + std::string sql = "select Id, Name, ServerId, StorageId, Function+0, Enabled, LinkedMonitors, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, OutputCodec, OutputContainer, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'File'"; if ( file[0] ) { sql += " AND Path='"; sql += file; @@ -2195,6 +2207,8 @@ int Monitor::LoadFileMonitors( const char *file, Monitor **&monitors, Purpose pu int savejpegs = atoi(dbrow[col]); col++; VideoWriter videowriter = (VideoWriter)atoi(dbrow[col]); col++; std::string encoderparams = dbrow[col]; col++; + std::string output_codec = dbrow[col]; col++; + std::string output_container = dbrow[col]; col++; bool record_audio = (*dbrow[col] != '0'); col++; int brightness = atoi(dbrow[col]); col++; @@ -2256,6 +2270,8 @@ int Monitor::LoadFileMonitors( const char *file, Monitor **&monitors, Purpose pu savejpegs, videowriter, encoderparams, + output_codec, + output_container, record_audio, event_prefix, label_format, @@ -2303,7 +2319,7 @@ int Monitor::LoadFileMonitors( const char *file, Monitor **&monitors, Purpose pu #if HAVE_LIBAVFORMAT int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose purpose ) { - std::string sql = "select Id, Name, ServerId, StorageId, Function+0, Enabled, LinkedMonitors, Path, Method, Options, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'Ffmpeg'"; + std::string sql = "select Id, Name, ServerId, StorageId, Function+0, Enabled, LinkedMonitors, Path, Method, Options, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, OutputCodec, OutputContainer, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'Ffmpeg'"; if ( file[0] ) { sql += " AND Path = '"; sql += file; @@ -2348,6 +2364,8 @@ int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose int savejpegs = atoi(dbrow[col]); col++; VideoWriter videowriter = (VideoWriter)atoi(dbrow[col]); col++; std::string encoderparams = dbrow[col] ? dbrow[col] : ""; col++; + std::string output_codec = dbrow[col] ? dbrow[col] : ""; col++; + std::string output_container = dbrow[col] ? dbrow[col] : ""; col++; bool record_audio = (*dbrow[col] != '0'); col++; int brightness = atoi(dbrow[col]); col++; @@ -2415,6 +2433,8 @@ int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose savejpegs, videowriter, encoderparams, + output_codec, + output_container, record_audio, event_prefix, label_format, @@ -2463,7 +2483,7 @@ int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose #endif // HAVE_LIBAVFORMAT Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) { - std::string sql = stringtf( "select Id, Name, ServerId, StorageId, Type, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, Protocol, Method, Host, Port, Path, Options, User, Pass, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, RTSPDescribe, SaveJPEGs, VideoWriter, EncoderParameters, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour, Exif from Monitors where Id = %d", p_id ); + std::string sql = stringtf( "select Id, Name, ServerId, StorageId, Type, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, Protocol, Method, Host, Port, Path, Options, User, Pass, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, RTSPDescribe, SaveJPEGs, VideoWriter, EncoderParameters, OutputCodec, OutputContainer, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour, Exif from Monitors where Id = %d", p_id ); zmDbRow dbrow; if ( ! dbrow.fetch( sql.c_str() ) ) { @@ -2523,7 +2543,9 @@ Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) { bool rtsp_describe = (dbrow[col] && *dbrow[col] != '0'); col++; int savejpegs = atoi(dbrow[col]); col++; VideoWriter videowriter = (VideoWriter)atoi(dbrow[col]); col++; - std::string encoderparams = dbrow[col] ? dbrow[col] : ""; col++; + std::string encoderparams = dbrow[col] ? dbrow[col] : ""; col++; + std::string output_codec = dbrow[col] ? dbrow[col] : ""; col++; + std::string output_container = dbrow[col] ? dbrow[col] : ""; col++; bool record_audio = (*dbrow[col] != '0'); col++; int brightness = atoi(dbrow[col]); col++; @@ -2742,6 +2764,8 @@ Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) { savejpegs, videowriter, encoderparams, + output_codec, + output_container, record_audio, event_prefix, label_format, diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 9cf303976..b59ad2a7f 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -166,6 +166,8 @@ protected: VideoStore *videoStore; zm_packetqueue packetqueue; Mutex mutex; + std::string output_codec; + std::string output_container; class MonitorLink { protected: @@ -346,6 +348,8 @@ public: int p_savejpegs, VideoWriter p_videowriter, std::string p_encoderparams, + std::string p_output_codec, + std::string p_output_container, bool p_record_audio, const char *p_event_prefix, const char *p_label_format, @@ -431,6 +435,8 @@ public: VideoWriter GetOptVideoWriter() const { return( videowriter ); } const std::vector* GetOptEncoderParams() const { return( &encoderparamsvec ); } const std::string &GetEncoderOptions() const { return( encoderparams ); } + const std::string &OutputCodec() const { return output_codec; } + const std::string &OutputContainer() const { return output_container; } uint32_t GetLastEventId() const { return shared_data->last_event_id; } uint32_t GetVideoWriterEventId() const { return video_store_data->current_event; } diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 113d3b7e9..f86f0f190 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -129,78 +129,95 @@ Debug(2,"About to copy aparames"); Error("Could not allocate in frame"); return; } - video_out_codec = avcodec_find_encoder_by_name("h264_omx"); - if ( ! video_out_codec ) { - Debug(1, "Didn't find omx"); - video_out_codec = avcodec_find_encoder(AV_CODEC_ID_H264); - } - if ( !video_out_codec ) { - Fatal("Could not find codec for H264"); - } - Debug(2, "Have video out codec"); + video_out_ctx = avcodec_alloc_context3( video_out_codec ); + // Don't have an input stream, so need to tell it what we are sending it, or are transcoding + video_out_ctx->width = monitor->Width(); + video_out_ctx->height = monitor->Height(); + video_out_ctx->codec_type = AVMEDIA_TYPE_VIDEO; - video_out_ctx = avcodec_alloc_context3( video_out_codec ); - // Don't have an input stream, so need to tell it what we are sending it, or are transcoding - video_out_ctx->width = monitor->Width(); - video_out_ctx->height = monitor->Height(); - video_out_ctx->codec_id = AV_CODEC_ID_H264; - video_out_ctx->codec_type = AVMEDIA_TYPE_VIDEO; -//video_in_ctx->sample_aspect_ratio; - /* take first format from list of supported formats */ - //video_out_ctx->pix_fmt = video_out_codec->pix_fmts[0]; - video_out_ctx->pix_fmt = AV_PIX_FMT_YUV420P; - /* video time_base can be set to whatever is handy and supported by encoder */ - video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate - video_out_ctx->framerate = (AVRational){0,1}; // Unknown framerate - video_out_ctx->gop_size = 12; - video_out_ctx->bit_rate = 4000000; - video_out_ctx->qmin = 10; - video_out_ctx->qmax = 51; - video_out_ctx->qcompress = 0.6; - - AVDictionary *opts = 0; - std::string Options = monitor->GetEncoderOptions(); - ret = av_dict_parse_string(&opts, Options.c_str(), "=", ",#\n", 0); - if ( ret < 0 ) { - Warning("Could not parse ffmpeg encoder options list '%s'\n", Options.c_str()); - } else { - AVDictionaryEntry *e = NULL; - while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { - Debug( 3, "Encoder Option %s=%s", e->key, e->value ); - } - } - - if ( ! av_dict_get( opts, "preset", NULL, 0 ) ) { - Debug(2,"Setting preset to superfast"); - av_dict_set( &opts, "preset", "superfast", 0 ); - } - - if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) { - Warning("Can't open video codec (%s)! %s, trying h264", - video_out_codec->name, - av_make_error_string(ret).c_str() - ); - video_out_codec = avcodec_find_encoder_by_name("h264"); + if ( monitor->OutputCodec() == "mjpeg" ) { + video_out_codec = avcodec_find_encoder_by_name("mjpeg"); if ( ! video_out_codec ) { - Error("Can't find h264 encoder"); - video_out_codec = avcodec_find_encoder_by_name("libx264"); + Debug(1, "Didn't find omx"); + video_out_codec = avcodec_find_encoder(AV_CODEC_ID_MJPEG); + } + video_out_ctx->codec_id = video_out_codec->id; + video_out_ctx->pix_fmt = AV_PIX_FMT_YUVJ422P; + + } else if ( monitor->OutputCodec() == "h264" ) { + video_out_codec = avcodec_find_encoder_by_name("h264_omx"); + if ( ! video_out_codec ) { + Debug(1, "Didn't find omx"); + video_out_codec = avcodec_find_encoder(AV_CODEC_ID_H264); + } + if ( !video_out_codec ) { + Fatal("Could not find codec for H264"); + } + Debug(2, "Have video out codec"); + + video_out_ctx->codec_id = AV_CODEC_ID_H264; + //video_in_ctx->sample_aspect_ratio; + /* take first format from list of supported formats */ + //video_out_ctx->pix_fmt = video_out_codec->pix_fmts[0]; + video_out_ctx->pix_fmt = AV_PIX_FMT_YUV420P; + /* video time_base can be set to whatever is handy and supported by encoder */ + video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate + video_out_ctx->framerate = (AVRational){0,1}; // Unknown framerate + video_out_ctx->gop_size = 12; + video_out_ctx->bit_rate = 4000000; + video_out_ctx->qmin = 10; + video_out_ctx->qmax = 51; + video_out_ctx->qcompress = 0.6; + + AVDictionary *opts = 0; + std::string Options = monitor->GetEncoderOptions(); + ret = av_dict_parse_string(&opts, Options.c_str(), "=", ",#\n", 0); + if ( ret < 0 ) { + Warning("Could not parse ffmpeg encoder options list '%s'\n", Options.c_str()); + } else { + AVDictionaryEntry *e = NULL; + while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { + Debug( 3, "Encoder Option %s=%s", e->key, e->value ); + } + } + + if ( ! av_dict_get( opts, "preset", NULL, 0 ) ) { + Debug(2,"Setting preset to ultrafast"); + av_dict_set( &opts, "preset", "ultrafast", 0 ); + } + + if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) { + Warning("Can't open video codec (%s)! %s, trying h264", + video_out_codec->name, + av_make_error_string(ret).c_str() + ); + video_out_codec = avcodec_find_encoder_by_name("h264"); if ( ! video_out_codec ) { - Error("Can't find libx264 encoder"); + Error("Can't find h264 encoder"); + video_out_codec = avcodec_find_encoder_by_name("libx264"); + if ( ! video_out_codec ) { + Error("Can't find libx264 encoder"); + return; + } + } + if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) { + Error("Can't open video codec (%s)! %s", + video_out_codec->name, + av_make_error_string(ret).c_str() ); return; } } - if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) { - Error("Can't open video codec (%s)! %s", - video_out_codec->name, - av_make_error_string(ret).c_str() ); - return; + AVDictionaryEntry *e = NULL; + while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { + Warning( "Encoder Option %s not recognized by ffmpeg codec", e->key); } - } - AVDictionaryEntry *e = NULL; - while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { - Warning( "Encoder Option %s not recognized by ffmpeg codec", e->key); - } - av_dict_free(&opts); + av_dict_free(&opts); + if ( !video_out_ctx->codec_tag ) { + video_out_ctx->codec_tag = + av_codec_get_tag(oc->oformat->codec_tag, AV_CODEC_ID_H264 ); + Debug(2, "No codec_tag, setting to %d", video_out_ctx->codec_tag); + } + }// end if codec == h264 swscale.SetDefaults( video_in_ctx->pix_fmt, @@ -210,11 +227,6 @@ Debug(2,"About to copy aparames"); ); } // end if copying or trasncoding - if ( !video_out_ctx->codec_tag ) { - video_out_ctx->codec_tag = - av_codec_get_tag(oc->oformat->codec_tag, AV_CODEC_ID_H264 ); - Debug(2, "No codec_tag, setting to %d", video_out_ctx->codec_tag); - } video_out_stream = avformat_new_stream(oc, video_out_codec); if ( !video_out_stream ) { diff --git a/web/skins/classic/js/skin.js b/web/skins/classic/js/skin.js index 7f770b1cb..c3d225aa8 100644 --- a/web/skins/classic/js/skin.js +++ b/web/skins/classic/js/skin.js @@ -326,7 +326,7 @@ function changeGroup( e, depth ) { } function changeMonitor( e ) { var monitor_id = e.value; - Cookie.write( 'zmMonitorId', monitor_id, { duration: 10*365 } ); + Cookie.write( 'MonitorId', monitor_id, { duration: 10*365 } ); window.location = window.location; } function changeFilter( e ) { diff --git a/web/skins/classic/views/_monitor_filters.php b/web/skins/classic/views/_monitor_filters.php index c8607f845..1409d629e 100644 --- a/web/skins/classic/views/_monitor_filters.php +++ b/web/skins/classic/views/_monitor_filters.php @@ -97,12 +97,17 @@ $groupSql = Group::get_group_sql( $group_id ); $monitors_dropdown[$monitors[$i]['Id']] = $monitors[$i]['Name']; if ( $monitors[$i]['Id'] == $monitor_id ) { $found_selected_monitor = true; + } else { + Warning("didn't find monitor $monitor_id " . $monitors[$i]['Id'] ); } - } + } // end foreach monitor if ( ! $found_selected_monitor ) { $monitor_id = ''; } - } + } else { + Warning("Monitor id not specified"); + } // end if a monitor was specified + for ( $i = 0; $i < count($monitors); $i++ ) { if ( !visibleMonitor( $monitors[$i]['Id'] ) ) { continue; @@ -114,7 +119,7 @@ $groupSql = Group::get_group_sql( $group_id ); } $displayMonitors[] = $monitors[$i]; } - echo htmlSelect( 'MonitorId', $monitors_dropdown, $monitor_id, array('onchange'=>'changeMonitor(this);') ); + echo htmlSelect( 'MonitorId', $monitors_dropdown, $monitor_id, array('onchange'=>'changeFilter(this);') ); ?> DefaultVideo() and ( 'mp4' == pathinfo($Event->DefaultVideo(), PATHINFO_EXTENSION) ) ) { + $video_tag = true; +} // videojs zoomrotate only when direct recording $Zoom = 1; $Rotation = 0; @@ -150,7 +154,7 @@ if ( $Event->SaveJPEGs() & 3 ) { // Analysis or Jpegs
DefaultVideo() ) { +if ( $video_tag ) { ?>
@@ -170,7 +174,7 @@ if ( $Event->DefaultVideo() ) { -DefaultVideo()) { ?> +
Date: Tue, 14 Nov 2017 08:41:45 -0500 Subject: [PATCH 0030/2339] fixes, set tune to lowlatency --- src/zm_ffmpeg.cpp | 2 +- src/zm_videostore.cpp | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index 51f8ad866..ccc876802 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -271,7 +271,6 @@ void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output) 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 */ @@ -281,6 +280,7 @@ void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output) if (lang) Debug(1, "(%s)", lang->value); Debug(1, ", frames:%d, timebase: %d/%d", st->codec_info_nb_frames, st->time_base.num, st->time_base.den); + avcodec_string(buf, sizeof(buf), st->codec, is_output); Debug(1, ": %s", buf); if (st->sample_aspect_ratio.num && // default diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 03fc0f24c..04b9202a2 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -128,7 +128,6 @@ Debug(2,"About to copy aparames"); Error("Could not allocate in frame"); return; } - video_out_ctx = avcodec_alloc_context3( video_out_codec ); // Don't have an input stream, so need to tell it what we are sending it, or are transcoding video_out_ctx->width = monitor->Width(); video_out_ctx->height = monitor->Height(); @@ -184,6 +183,10 @@ Debug(2,"About to copy aparames"); Debug(2,"Setting preset to ultrafast"); av_dict_set( &opts, "preset", "ultrafast", 0 ); } + if ( ! av_dict_get( opts, "tune", NULL, 0 ) ) { + Debug(2,"Setting tune to lowlatency"); + av_dict_set( &opts, "tune", "lowlatency", 0 ); + } if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) { Warning("Can't open video codec (%s)! %s, trying h264", From 13ca8435ef6076f6ad90d301d5dfd1542c1c093c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 14 Nov 2017 08:13:54 -0800 Subject: [PATCH 0031/2339] Don't go looking for Events to update Diskspace for --- web/includes/Storage.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web/includes/Storage.php b/web/includes/Storage.php index cc52b5c65..e3fedad84 100644 --- a/web/includes/Storage.php +++ b/web/includes/Storage.php @@ -114,11 +114,12 @@ class Storage { $used = 0; if ( $this->{'Type'} == 's3fs' ) { $used = dbFetchOne('SELECT SUM(DiskSpace) AS DiskSpace FROM Events WHERE StorageId=? AND DiskSpace IS NOT NULL', 'DiskSpace', array($this->Id()) ); - +if ( 0 ) { foreach ( Event::find_all( array( 'StorageId'=>$this->Id(), 'DiskSpace'=>null ) ) as $Event ) { $Event->Storage( $this ); // Prevent further db hit $used += $Event->DiskSpace(); } +} } else { $path = $this->Path(); $used = disk_total_space( $path ) - disk_free_space( $path );; From 1809921b46141e8ab7ac1bdeec191a308eba003c Mon Sep 17 00:00:00 2001 From: APHW2 MFGENG Date: Tue, 14 Nov 2017 08:53:08 -0800 Subject: [PATCH 0032/2339] turnoff debug --- src/zm_analysis_thread.cpp | 4 ++-- src/zm_remote_camera_nvsocket.cpp | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/zm_analysis_thread.cpp b/src/zm_analysis_thread.cpp index a6eec451f..8d2c14551 100644 --- a/src/zm_analysis_thread.cpp +++ b/src/zm_analysis_thread.cpp @@ -36,10 +36,10 @@ int AnalysisThread::run() { } if ( !monitor->Analyse() ) { -Debug(4, "Sleeping for %d", monitor->Active()?ZM_SAMPLE_RATE:ZM_SUSPENDED_RATE); +//Debug(4, "Sleeping for %d", monitor->Active()?ZM_SAMPLE_RATE:ZM_SUSPENDED_RATE); usleep(monitor->Active()?ZM_SAMPLE_RATE:ZM_SUSPENDED_RATE); } else if ( analysis_rate ) { -Debug(4, "Sleeping for %d", analysis_rate); +//Debug(4, "Sleeping for %d", analysis_rate); usleep(analysis_rate); } diff --git a/src/zm_remote_camera_nvsocket.cpp b/src/zm_remote_camera_nvsocket.cpp index e9fe1ac60..ae5eb3faa 100644 --- a/src/zm_remote_camera_nvsocket.cpp +++ b/src/zm_remote_camera_nvsocket.cpp @@ -142,13 +142,13 @@ int RemoteCameraNVSocket::Disconnect() { } int RemoteCameraNVSocket::SendRequest( std::string request ) { - Debug( 4, "Sending request: %s", request.c_str() ); + //Debug( 4, "Sending request: %s", request.c_str() ); if ( write( sd, request.data(), request.length() ) < 0 ) { Error( "Can't write: %s", strerror(errno) ); Disconnect(); return( -1 ); } - Debug( 4, "Request sent" ); + //Debug( 4, "Request sent" ); return( 0 ); } @@ -222,10 +222,12 @@ AVStream *RemoteCameraNVSocket::get_VideoStream() { video_stream->codecpar->width = width; video_stream->codecpar->height = height; video_stream->codecpar->format = GetFFMPEGPixelFormat(colours,subpixelorder); + video_stream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; #else video_stream->codec->width = width; video_stream->codec->height = height; video_stream->codec->pix_fmt = GetFFMPEGPixelFormat(colours,subpixelorder); + video_stream->codec->codec_type = AVMEDIA_TYPE_VIDEO; #endif } else { Error("Can't create video stream"); From b839151cbcdd7ad02c34153dc8c852c6fba70554 Mon Sep 17 00:00:00 2001 From: APHW2 MFGENG Date: Tue, 14 Nov 2017 08:53:29 -0800 Subject: [PATCH 0033/2339] only set orientation if doing pssthrough --- src/zm_videostore.cpp | 61 +++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 04b9202a2..e42705dda 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -86,11 +86,9 @@ VideoStore::VideoStore( video_in_stream_index = video_in_stream->index; #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) video_in_ctx = avcodec_alloc_context3(NULL); -Debug(2,"About to copy aparames"); avcodec_parameters_to_context(video_in_ctx, video_in_stream->codecpar); zm_dump_codecpar( video_in_stream->codecpar ); -Debug(2,"About to copy aparames"); //video_in_ctx.codec_id = video_in_stream->codecpar.codec_id; #else video_in_ctx = video_in_stream->codec; @@ -101,7 +99,6 @@ Debug(2,"About to copy aparames"); video_in_stream_index = 0; } - video_out_ctx = NULL; video_out_ctx = avcodec_alloc_context3(NULL); // Copy params from instream to ctx @@ -121,6 +118,24 @@ Debug(2,"About to copy aparames"); #endif // Same codec, just copy the packets, otherwise we have to decode/encode video_out_codec = (AVCodec *)video_in_ctx->codec; + // Only set orientation if doing passthrough, otherwise the frame image will be rotated + Monitor::Orientation orientation = monitor->getOrientation(); + Debug(3, "Have orientation"); + if ( orientation ) { + if ( orientation == Monitor::ROTATE_0 ) { + } else if ( orientation == Monitor::ROTATE_90 ) { + dsr = av_dict_set(&video_out_stream->metadata, "rotate", "90", 0); + if ( dsr < 0 ) Warning("%s:%d: title set failed", __FILE__, __LINE__); + } else if ( orientation == Monitor::ROTATE_180 ) { + dsr = av_dict_set(&video_out_stream->metadata, "rotate", "180", 0); + if ( dsr < 0 ) Warning("%s:%d: title set failed", __FILE__, __LINE__); + } else if ( orientation == Monitor::ROTATE_270 ) { + dsr = av_dict_set(&video_out_stream->metadata, "rotate", "270", 0); + if ( dsr < 0 ) Warning("%s:%d: title set failed", __FILE__, __LINE__); + } else { + Warning("Unsupported Orientation(%d)", orientation); + } + } } else { /** Create a new frame to store the */ @@ -128,10 +143,10 @@ Debug(2,"About to copy aparames"); Error("Could not allocate in frame"); return; } - // Don't have an input stream, so need to tell it what we are sending it, or are transcoding - video_out_ctx->width = monitor->Width(); - video_out_ctx->height = monitor->Height(); - video_out_ctx->codec_type = AVMEDIA_TYPE_VIDEO; + // Don't have an input stream, so need to tell it what we are sending it, or are transcoding + video_out_ctx->width = monitor->Width(); + video_out_ctx->height = monitor->Height(); + video_out_ctx->codec_type = AVMEDIA_TYPE_VIDEO; if ( monitor->OutputCodec() == "mjpeg" ) { video_out_codec = avcodec_find_encoder_by_name("mjpeg"); @@ -209,16 +224,20 @@ Debug(2,"About to copy aparames"); return; } } +Debug(2,"Sucess opening codec"); AVDictionaryEntry *e = NULL; while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { Warning( "Encoder Option %s not recognized by ffmpeg codec", e->key); } av_dict_free(&opts); - if ( !video_out_ctx->codec_tag ) { - video_out_ctx->codec_tag = - av_codec_get_tag(oc->oformat->codec_tag, AV_CODEC_ID_H264 ); - Debug(2, "No codec_tag, setting to %d", video_out_ctx->codec_tag); - } + + if ( !video_out_ctx->codec_tag ) { + video_out_ctx->codec_tag = + av_codec_get_tag(oc->oformat->codec_tag, AV_CODEC_ID_H264 ); + Debug(2, "No codec_tag, setting to h264"); + } + } else { +Error("Codec not set"); }// end if codec == h264 swscale.SetDefaults( @@ -261,23 +280,7 @@ video_out_stream->time_base.den = video_out_ctx->time_base.den; video_out_ctx->time_base.num, video_out_ctx->time_base.den); - Monitor::Orientation orientation = monitor->getOrientation(); - Debug(3, "Have orientation"); - if ( orientation ) { - if ( orientation == Monitor::ROTATE_0 ) { - } else if ( orientation == Monitor::ROTATE_90 ) { - dsr = av_dict_set(&video_out_stream->metadata, "rotate", "90", 0); - if ( dsr < 0 ) Warning("%s:%d: title set failed", __FILE__, __LINE__); - } else if ( orientation == Monitor::ROTATE_180 ) { - dsr = av_dict_set(&video_out_stream->metadata, "rotate", "180", 0); - if ( dsr < 0 ) Warning("%s:%d: title set failed", __FILE__, __LINE__); - } else if ( orientation == Monitor::ROTATE_270 ) { - dsr = av_dict_set(&video_out_stream->metadata, "rotate", "270", 0); - if ( dsr < 0 ) Warning("%s:%d: title set failed", __FILE__, __LINE__); - } else { - Warning("Unsupported Orientation(%d)", orientation); - } - } + converted_in_samples = NULL; audio_out_codec = NULL; From bac3fbfce96e9345a357f8ffb144ccd0ce4c7b6e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 14 Nov 2017 08:55:00 -0800 Subject: [PATCH 0034/2339] fix compile on old ffmpeg --- db/zm_create.sql.in | 3 ++- db/zm_update-1.31.13.sql | 12 ++++++++++++ scripts/zmwatch.pl.in | 11 ++++++++++- src/zm_videostore.cpp | 2 ++ web/includes/database.php | 2 +- 5 files changed, 27 insertions(+), 3 deletions(-) diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index df7a486c0..f4a41d93a 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -609,13 +609,14 @@ CREATE TABLE `Storage` ( `Path` varchar(64) NOT NULL default '', `Name` varchar(64) NOT NULL default '', `Type` enum('local','s3fs') NOT NULL default 'local', + `DiskSpace` bigint unsigned default NULL, PRIMARY KEY (`Id`) ) ENGINE=@ZM_MYSQL_ENGINE@; -- -- Create a default storage location -- -insert into Storage VALUES (NULL, '/var/cache/zoneminder/events', 'Default', 'local' ); +insert into Storage VALUES (NULL, '/var/cache/zoneminder/events', 'Default', 'local', NULL ); /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; diff --git a/db/zm_update-1.31.13.sql b/db/zm_update-1.31.13.sql index a68936e6b..dd63b347a 100644 --- a/db/zm_update-1.31.13.sql +++ b/db/zm_update-1.31.13.sql @@ -12,3 +12,15 @@ SET @s = (SELECT IF( PREPARE stmt FROM @s; EXECUTE stmt; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Storage' + AND column_name = 'DiskSpace' + ) > 0, +"SELECT 'Column DiskSpace already exists in Events'", +"ALTER TABLE `Storage` ADD `DiskSpace` bigint unsigned default NULL AFTER `Type`" +)); + +PREPARE stmt FROM @s; +EXECUTE stmt; diff --git a/scripts/zmwatch.pl.in b/scripts/zmwatch.pl.in index 393d8fe90..3b6bbaf93 100644 --- a/scripts/zmwatch.pl.in +++ b/scripts/zmwatch.pl.in @@ -55,6 +55,7 @@ use constant START_DELAY => 30; # To give everything else time to start @EXTRA_PERL_LIB@ use ZoneMinder; +use ZoneMinder::Storage; use POSIX; use DBI; use autouse 'Data::Dumper'=>qw(Dumper); @@ -168,13 +169,21 @@ while( 1 ) { if ( $restart ) { Info( "Restarting analysis daemon for $$monitor{Id} $$monitor{Name}\n"); - my $command = "zmdc.pl restart zma -m ".$monitor->{Id}; + my $command = "zmdc.pl restart zmc -m ".$monitor->{Id}; runCommand( $command ); } # end if restart } # end if check analysis daemon # Prevent open handles building up if we have connect to shared memory zmMemInvalidate( $monitor ); # Close our file handle to the zmc process we are about to end } # end foreach monitor + my $diskspace_sql = 'UPDATE Storage SET DiskSpace =(SELECT SUM(DiskSpace) FROM Events WHERE StorageId=? AND DiskSpace IS NOT NULL)'; + my $diskspace_sth = $dbh->prepare_cached( $sql ) + or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); + foreach my $Storage ( ZoneMinder::Storage->find() ) { +Error("Updating displace for $$Storage{Name}"); + $diskspace_sth->execute( $$Storage{Id} ) or Error( "Can't execute: ".$diskspace_sth->errstr() ); + } + $diskspace_sth->finish(); sleep( $Config{ZM_WATCH_CHECK_INTERVAL} ); } # end while (1) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index e42705dda..fa71b2e63 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -938,6 +938,7 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { return -1; } #else + int data_present; if ( (ret = avcodec_encode_video2( video_out_ctx, &opkt, zm_packet->frame, &data_present)) < 0) { Error("Could not encode frame (error '%s')", @@ -1059,6 +1060,7 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { * If we are at the end of the file, pass an empty packet to the decoder * to flush it. */ + int data_present; if ( (ret = avcodec_decode_audio4(audio_in_ctx, in_frame, &data_present, ipkt)) < 0 ) { Error("Could not decode frame (error '%s')\n", diff --git a/web/includes/database.php b/web/includes/database.php index 227de8132..a1bcf66c3 100644 --- a/web/includes/database.php +++ b/web/includes/database.php @@ -134,7 +134,7 @@ function dbQuery( $sql, $params=NULL ) { } else { $result = $dbConn->query( $sql ); } -if ( 0 ) { +if ( 1 ) { if ( $params ) Warning("SQL: $sql" . implode(',',$params) . ' rows: '.$result->rowCount() ); else From 9563c534a9055a5eec3fc201f7da93342bb11ab1 Mon Sep 17 00:00:00 2001 From: APHW2 MFGENG Date: Tue, 14 Nov 2017 12:41:25 -0800 Subject: [PATCH 0035/2339] play around with presets --- src/zm_videostore.cpp | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index e42705dda..6fb35768a 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -176,11 +176,13 @@ VideoStore::VideoStore( /* video time_base can be set to whatever is handy and supported by encoder */ video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate video_out_ctx->framerate = (AVRational){0,1}; // Unknown framerate +#if 1 video_out_ctx->gop_size = 12; - video_out_ctx->bit_rate = 4000000; video_out_ctx->qmin = 10; video_out_ctx->qmax = 51; video_out_ctx->qcompress = 0.6; + video_out_ctx->bit_rate = 4000000; +#endif AVDictionary *opts = 0; std::string Options = monitor->GetEncoderOptions(); @@ -194,14 +196,22 @@ VideoStore::VideoStore( } } +#if 0 if ( ! av_dict_get( opts, "preset", NULL, 0 ) ) { - Debug(2,"Setting preset to ultrafast"); - av_dict_set( &opts, "preset", "ultrafast", 0 ); + Debug(2,"Setting preset to superfast"); + av_dict_set( &opts, "preset", "superfast", 0 ); } + if ( ! av_dict_get( opts, "crf", NULL, 0 ) ) { + Debug(2,"Setting crf to superfast"); + av_dict_set( &opts, "crf", "0", 0 ); + } +#endif +#if 1 if ( ! av_dict_get( opts, "tune", NULL, 0 ) ) { - Debug(2,"Setting tune to lowlatency"); - av_dict_set( &opts, "tune", "lowlatency", 0 ); + Debug(2,"Setting tune to zerolatency"); + av_dict_set( &opts, "tune", "zerolatency", 0 ); } +#endif if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) { Warning("Can't open video codec (%s)! %s, trying h264", @@ -217,6 +227,21 @@ VideoStore::VideoStore( return; } } +#if 0 + if ( ! av_dict_get( opts, "preset", NULL, 0 ) ) { + Debug(2,"Setting preset to superfast"); + av_dict_set( &opts, "preset", "ultrafast", 0 ); + } + if ( ! av_dict_get( opts, "crf", NULL, 0 ) ) { + Debug(2,"Setting crf to 0"); + av_dict_set( &opts, "crf", "0", 0 ); + } +#else + if ( ! av_dict_get( opts, "tune", NULL, 0 ) ) { + Debug(2,"Setting tune to zerolatency"); + av_dict_set( &opts, "tune", "zerolatency", 0 ); + } +#endif if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) { Error("Can't open video codec (%s)! %s", video_out_codec->name, @@ -270,8 +295,10 @@ Debug(2, "%dx%d", video_out_stream->codec->width, video_out_stream->codec->heigh zm_dump_codec(video_out_ctx); zm_dump_codec(video_out_stream->codec); #endif +#if 0 video_out_stream->time_base.num = video_out_ctx->time_base.num; video_out_stream->time_base.den = video_out_ctx->time_base.den; +#endif Debug(3, "Time bases: VIDEO out stream: (%d/%d) out codec (%d/%d)", @@ -987,6 +1014,7 @@ void VideoStore::write_video_packet( AVPacket &opkt ) { //AVPacket safepkt; //memcpy(&safepkt, &opkt, sizeof(AVPacket)); + av_packet_rescale_ts( &opkt, video_out_ctx->time_base, video_out_stream->time_base ); Debug(1, "writing video packet pts(%d) dts(%d) duration(%d) packet_count(%d)", From 3129afa5d69249f86a30d318f7cc45e72453306e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 14 Nov 2017 13:16:07 -0800 Subject: [PATCH 0036/2339] fixup decoding when recording from a non-ffmpeg suorce --- src/zm_camera.h | 2 + src/zm_ffmpeg_camera.cpp | 15 +----- src/zm_ffmpeg_camera.h | 2 + src/zm_image.cpp | 10 ++-- src/zm_monitor.cpp | 113 ++++++++++++++++++++++----------------- src/zm_monitor.h | 4 +- src/zm_packet.cpp | 45 +++++++++++----- src/zm_packet.h | 3 +- src/zm_swscale.cpp | 21 ++++++++ src/zm_swscale.h | 1 + src/zm_videostore.cpp | 71 +++++++++++------------- version | 2 +- 12 files changed, 163 insertions(+), 126 deletions(-) diff --git a/src/zm_camera.h b/src/zm_camera.h index 3cc93f5cf..204aa526d 100644 --- a/src/zm_camera.h +++ b/src/zm_camera.h @@ -109,6 +109,8 @@ public: virtual int PostCapture()=0; virtual AVStream *get_VideoStream() { return NULL; }; virtual AVStream *get_AudioStream() { return NULL; }; + virtual AVCodecContext *get_VideoCodecContext() { return NULL; }; + virtual AVCodecContext *get_AudioCodecContext() { return NULL; }; int get_VideoStreamId() { return mVideoStreamId; }; int get_AudioStreamId() { return mAudioStreamId; }; }; diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index af635e840..72aa9d3ce 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -195,8 +195,7 @@ int FfmpegCamera::Capture( ZMPacket &zm_packet ) { mReopenThread = 0; } - ret = av_read_frame( mFormatContext, &packet ); - if ( ret < 0 ) { + if ( (ret = av_read_frame( mFormatContext, &packet )) < 0 ) { if ( // Check if EOF. (ret == AVERROR_EOF || (mFormatContext->pb && mFormatContext->pb->eof_reached)) || @@ -433,18 +432,6 @@ int FfmpegCamera::OpenFfmpeg() { } } - if ( mVideoCodecContext->codec_id != AV_CODEC_ID_H264 ) { -#ifdef AV_CODEC_ID_H265 - if ( mVideoCodecContext->codec_id == AV_CODEC_ID_H265 ) { - Debug( 1, "Input stream appears to be h265. The stored event file may not be viewable in browser." ); - } else { -#endif - Warning( "Input stream is not h264. The stored event file may not be viewable in browser." ); -#ifdef AV_CODEC_ID_H265 - } -#endif - } - if (mVideoCodecContext->hwaccel != NULL) { Debug(1, "HWACCEL in use"); } else { diff --git a/src/zm_ffmpeg_camera.h b/src/zm_ffmpeg_camera.h index ef3b259ae..45bede6b9 100644 --- a/src/zm_ffmpeg_camera.h +++ b/src/zm_ffmpeg_camera.h @@ -127,6 +127,8 @@ class FfmpegCamera : public Camera { return mFormatContext->streams[mAudioStreamId]; return NULL; } + AVCodecContext *get_VideoCodecContext() { return mVideoCodecContext; }; + AVCodecContext *get_AudioCodecContext() { return mAudioCodecContext; }; }; #endif // ZM_FFMPEG_CAMERA_H diff --git a/src/zm_image.cpp b/src/zm_image.cpp index 11cb193c0..da7475dbb 100644 --- a/src/zm_image.cpp +++ b/src/zm_image.cpp @@ -146,13 +146,15 @@ Image::Image( const AVFrame *frame ) { void Image::Assign( const AVFrame *frame ) { /* Assume the dimensions etc are correct. FIXME */ +AVPixelFormat format = (AVPixelFormat)AVPixFormat(); + AVFrame *dest_frame = zm_av_frame_alloc(); #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) av_image_fill_arrays(dest_frame->data, dest_frame->linesize, - buffer, AV_PIX_FMT_RGBA, width, height, 1); + buffer, format, width, height, 1); #else avpicture_fill( (AVPicture *)dest_frame, buffer, - AV_PIX_FMT_RGBA, width, height); + format, width, height); #endif #if HAVE_LIBSWSCALE @@ -161,13 +163,13 @@ void Image::Assign( const AVFrame *frame ) { height, (AVPixelFormat)frame->format, width, height, - AV_PIX_FMT_RGBA, SWS_BICUBIC, NULL, + format, SWS_BICUBIC, NULL, NULL, NULL); if ( mConvertContext == NULL ) Fatal( "Unable to create conversion context" ); if ( sws_scale(mConvertContext, frame->data, frame->linesize, 0, frame->height, dest_frame->data, dest_frame->linesize) < 0 ) - Fatal("Unable to convert raw format %u to target format %u", frame->format, AV_PIX_FMT_RGBA); + Fatal("Unable to convert raw format %u to target format %u", frame->format, format); #else // HAVE_LIBSWSCALE Fatal("You must compile ffmpeg with the --enable-swscale option to use ffmpeg cameras"); #endif // HAVE_LIBSWSCALE diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 693047fe0..3e41b2194 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -2822,6 +2822,18 @@ int Monitor::Capture() { static int FirstCapture = 1; // Used in de-interlacing to indicate whether this is the even or odd image unsigned int index = image_count % image_buffer_count; + + if ( (index == shared_data->last_read_index) && (function > MONITOR) ) { + Warning( "Buffer overrun at index %d, image %d, slow down capture, speed up analysis or increase ring buffer size", index, image_count ); + time_t now = time(0); + double approxFps = double(image_buffer_count)/double(now-image_buffer[index].timestamp.tv_sec); + time_t last_read_delta = now - shared_data->last_read_time; + if ( last_read_delta > (image_buffer_count/approxFps) ) { + Warning( "Last image read from shared memory %ld seconds ago, zma may have gone away", last_read_delta ) + shared_data->last_read_index = image_buffer_count; + } + } + Image* capture_image = image_buffer[index].image; ZMPacket *packet = &image_buffer[index]; // clears frame @@ -2854,60 +2866,54 @@ packet->reset(); capture_image->Fill(signalcolor); shared_data->signal = false; return -1; + } else if ( captureResult > 0 ) { + + if ( packet->packet.size && ! packet->frame ) { + packet->decode( camera->get_VideoCodecContext() ); + packet->get_image(); } - /* Deinterlacing */ - if ( deinterlacing_value ) { - if ( deinterlacing_value == 1 ) { - capture_image->Deinterlace_Discard(); - } else if ( deinterlacing_value == 2 ) { - capture_image->Deinterlace_Linear(); - } else if ( deinterlacing_value == 3 ) { - capture_image->Deinterlace_Blend(); - } else if ( deinterlacing_value == 4 ) { - capture_image->Deinterlace_4Field( next_buffer.image, (deinterlacing>>8)&0xff ); - } else if ( deinterlacing_value == 5 ) { - capture_image->Deinterlace_Blend_CustomRatio( (deinterlacing>>8)&0xff ); + /* Deinterlacing */ + if ( deinterlacing_value ) { + if ( deinterlacing_value == 1 ) { + capture_image->Deinterlace_Discard(); + } else if ( deinterlacing_value == 2 ) { + capture_image->Deinterlace_Linear(); + } else if ( deinterlacing_value == 3 ) { + capture_image->Deinterlace_Blend(); + } else if ( deinterlacing_value == 4 ) { + capture_image->Deinterlace_4Field( next_buffer.image, (deinterlacing>>8)&0xff ); + } else if ( deinterlacing_value == 5 ) { + capture_image->Deinterlace_Blend_CustomRatio( (deinterlacing>>8)&0xff ); + } } - } - if ( orientation != ROTATE_0 ) { - switch ( orientation ) { - case ROTATE_0 : - // No action required - break; - case ROTATE_90 : - case ROTATE_180 : - case ROTATE_270 : - capture_image->Rotate( (orientation-1)*90 ); - break; - case FLIP_HORI : - case FLIP_VERT : - capture_image->Flip( orientation==FLIP_HORI ); - break; + if ( orientation != ROTATE_0 ) { + switch ( orientation ) { + case ROTATE_0 : + // No action required + break; + case ROTATE_90 : + case ROTATE_180 : + case ROTATE_270 : + capture_image->Rotate( (orientation-1)*90 ); + break; + case FLIP_HORI : + case FLIP_VERT : + capture_image->Flip( orientation==FLIP_HORI ); + break; + } } - } - if ( (index == shared_data->last_read_index) && (function > MONITOR) ) { - Warning( "Buffer overrun at index %d, image %d, slow down capture, speed up analysis or increase ring buffer size", index, image_count ); - time_t now = time(0); - double approxFps = double(image_buffer_count)/double(now-image_buffer[index].timestamp.tv_sec); - time_t last_read_delta = now - shared_data->last_read_time; - if ( last_read_delta > (image_buffer_count/approxFps) ) { - Warning( "Last image read from shared memory %ld seconds ago, zma may have gone away", last_read_delta ) - shared_data->last_read_index = image_buffer_count; + if ( privacy_bitmask ) + capture_image->MaskPrivacy( privacy_bitmask ); + + if ( config.timestamp_on_capture ) { + TimestampImage( capture_image, &packet->timestamp ); } - } - - if ( privacy_bitmask ) - capture_image->MaskPrivacy( privacy_bitmask ); - - if ( config.timestamp_on_capture ) { - TimestampImage( capture_image, &packet->timestamp ); - } - int video_stream_id = camera->get_VideoStreamId(); #if 0 + int video_stream_id = camera->get_VideoStreamId(); //Video recording if ( video_store_data->recording.tv_sec ) { if ( shared_data->last_event_id != this->GetVideoWriterEventId() ) { @@ -2986,13 +2992,17 @@ packet->reset(); } } #endif + + shared_data->signal = CheckSignal(capture_image); + shared_data->last_write_index = index; + shared_data->last_write_time = image_buffer[index].timestamp.tv_sec; + image_count++; + } else { // result == 0 + + } // end if result } // end if deinterlacing - shared_data->signal = CheckSignal(capture_image); - shared_data->last_write_index = index; - shared_data->last_write_time = image_buffer[index].timestamp.tv_sec; mutex.unlock(); - image_count++; if ( image_count && fps_report_interval && !(image_count%fps_report_interval) ) { struct timeval now; @@ -3013,8 +3023,11 @@ packet->reset(); snprintf( sql, sizeof(sql), "UPDATE Monitors SET CaptureFPS='%.2lf' WHERE Id=%d", fps, id ); if ( mysql_query( &dbconn, sql ) ) { Error( "Can't run query: %s", mysql_error( &dbconn ) ); - } + } else { +Debug(2,"toofast");} } // end if too fast +}else { +Debug(2,"Nor reopting fps"); } // end if should report fps // Icon: I'm not sure these should be here. They have nothing to do with capturing diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 229597585..2ea984b92 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -166,8 +166,6 @@ protected: VideoStore *videoStore; zm_packetqueue packetqueue; Mutex mutex; - std::string output_codec; - std::string output_container; class MonitorLink { protected: @@ -238,6 +236,8 @@ protected: int savejpegspref; VideoWriter videowriter; std::string encoderparams; + std::string output_codec; + std::string output_container; std::vector encoderparamsvec; bool record_audio; // Whether to store the audio that we receive diff --git a/src/zm_packet.cpp b/src/zm_packet.cpp index 557fc1983..8341e9a6d 100644 --- a/src/zm_packet.cpp +++ b/src/zm_packet.cpp @@ -27,6 +27,7 @@ using namespace std; ZMPacket::ZMPacket( ) { keyframe = 0; image = NULL; + in_frame = NULL; frame = NULL; buffer = NULL; av_init_packet( &packet ); @@ -37,6 +38,7 @@ ZMPacket::ZMPacket( ) { ZMPacket::ZMPacket( Image *i ) { keyframe = 1; image = i; + in_frame = NULL; frame = NULL; buffer = NULL; av_init_packet( &packet ); @@ -48,6 +50,8 @@ ZMPacket::ZMPacket( AVPacket *p ) { set_packet( p ); keyframe = p->flags & AV_PKT_FLAG_KEY; buffer = NULL; + in_frame = NULL; + frame = NULL; } ZMPacket::ZMPacket( AVPacket *p, struct timeval *t ) { @@ -56,6 +60,8 @@ ZMPacket::ZMPacket( AVPacket *p, struct timeval *t ) { timestamp = *t; keyframe = p->flags & AV_PKT_FLAG_KEY; buffer = NULL; + in_frame = NULL; + frame = NULL; } ZMPacket::ZMPacket( AVPacket *p, AVFrame *f, Image *i ) { av_init_packet( &packet ); @@ -63,10 +69,16 @@ ZMPacket::ZMPacket( AVPacket *p, AVFrame *f, Image *i ) { image = i; frame = f; buffer = NULL; + in_frame = NULL; + frame = NULL; } ZMPacket::~ZMPacket() { zm_av_packet_unref( &packet ); + if ( in_frame ) { + //av_free(frame->data); + av_frame_free( &in_frame ); + } if ( frame ) { //av_free(frame->data); av_frame_free( &frame ); @@ -82,11 +94,16 @@ void ZMPacket::reset() { Debug(2,"reset"); zm_av_packet_unref( &packet ); packet.size = 0; + if ( in_frame ) { + Debug(4,"reset frame"); + av_frame_free( &in_frame ); + } if ( frame ) { + Debug(4,"reset frame"); av_frame_free( &frame ); } if ( buffer ) { - Debug(2,"freeing buffer"); + Debug(4,"freeing buffer"); av_freep( &buffer ); } } @@ -94,17 +111,17 @@ void ZMPacket::reset() { int ZMPacket::decode( AVCodecContext *ctx ) { Debug(4, "about to decode video" ); - if ( frame ) { + if ( in_frame ) { Error("Already have a frame?"); } else { - frame = zm_av_frame_alloc(); + in_frame = zm_av_frame_alloc(); } #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) int ret = avcodec_send_packet( ctx, &packet ); if ( ret < 0 ) { Error( "Unable to send packet: %s", av_make_error_string(ret).c_str() ); - av_frame_free( &frame ); + av_frame_free( &in_frame ); return 0; } @@ -113,21 +130,21 @@ int ZMPacket::decode( AVCodecContext *ctx ) { ret = avcodec_receive_frame( ctx, hwFrame ); if ( ret < 0 ) { Error( "Unable to receive frame: %s", av_make_error_string(ret).c_str() ); - av_frame_free( &frame ); + av_frame_free( &in_frame ); return 0; } ret = av_hwframe_transfer_data(frame, hwFrame, 0); if ( ret < 0 ) { Error( "Unable to transfer frame: %s", av_make_error_string(ret).c_str() ); - av_frame_free( &frame ); + av_frame_free( &in_frame ); return 0; } } else { #endif - ret = avcodec_receive_frame( ctx, frame ); + ret = avcodec_receive_frame( ctx, in_frame ); if ( ret < 0 ) { Error( "Unable to receive frame: %s", av_make_error_string(ret).c_str() ); - av_frame_free( &frame ); + av_frame_free( &in_frame ); return 0; } @@ -137,23 +154,23 @@ int ZMPacket::decode( AVCodecContext *ctx ) { # else int frameComplete = 0; - int ret = zm_avcodec_decode_video( ctx, frame, &frameComplete, &packet ); + int ret = zm_avcodec_decode_video( ctx, in_frame, &frameComplete, &packet ); if ( ret < 0 ) { Error( "Unable to decode frame at frame %s", av_make_error_string(ret).c_str() ); - av_frame_free( &frame ); + av_frame_free( &in_frame ); return 0; } if ( ! frameComplete ) { Debug(1, "incomplete frame?"); - av_frame_free( &frame ); + av_frame_free( &in_frame ); return 0; } #endif return 1; } // end ZMPacket::decode -Image * ZMPacket::get_image( Image *i = NULL ) { - if ( ! frame ) { +Image * ZMPacket::get_image( Image *i ) { + if ( ! in_frame ) { Error("Can't get image without frame.. maybe need to decode first"); return NULL; } @@ -164,7 +181,7 @@ Image * ZMPacket::get_image( Image *i = NULL ) { } image = i; } - image->Assign( frame ); + image->Assign( in_frame ); return image; } diff --git a/src/zm_packet.h b/src/zm_packet.h index 590ff5dc6..84c74a0c9 100644 --- a/src/zm_packet.h +++ b/src/zm_packet.h @@ -35,6 +35,7 @@ class ZMPacket { int keyframe; AVPacket packet; // Input packet, undecoded + AVFrame *in_frame; // Input image, decoded Theoretically only filled if needed. AVFrame *frame; // Input image, decoded Theoretically only filled if needed. uint8_t *buffer; Image *image; // Our internal image object representing this frame @@ -43,7 +44,7 @@ class ZMPacket { AVPacket *av_packet() { return &packet; } AVPacket *set_packet( AVPacket *p ) ; AVFrame *av_frame() { return frame; } - Image *get_image( Image * ); + Image *get_image( Image *i=NULL ); Image *set_image( Image * ); int is_keyframe() { return keyframe; }; diff --git a/src/zm_swscale.cpp b/src/zm_swscale.cpp index 2df94775c..5874b1e49 100644 --- a/src/zm_swscale.cpp +++ b/src/zm_swscale.cpp @@ -78,6 +78,27 @@ int SWScale::SetDefaults(enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, return 0; } +int SWScale::Convert( + AVFrame *in_frame, + AVFrame *out_frame +) { + /* Get the context */ + swscale_ctx = sws_getCachedContext( swscale_ctx, + in_frame->width, in_frame->height, (AVPixelFormat)in_frame->format, + out_frame->width, out_frame->height, (AVPixelFormat)out_frame->format, + SWS_FAST_BILINEAR, NULL, NULL, NULL ); + if ( swscale_ctx == NULL ) { + Error("Failed getting swscale context"); + return -6; + } + /* Do the conversion */ + if(!sws_scale(swscale_ctx, in_frame->data, in_frame->linesize, 0, in_frame->height, out_frame->data, out_frame->linesize ) ) { + Error("swscale conversion failed"); + return -10; + } + + return 0; +} int SWScale::Convert( const uint8_t* in_buffer, diff --git a/src/zm_swscale.h b/src/zm_swscale.h index 66a3d470a..f8749b463 100644 --- a/src/zm_swscale.h +++ b/src/zm_swscale.h @@ -13,6 +13,7 @@ class 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( AVFrame *in_frame, AVFrame *out_frame ); 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); diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index fa71b2e63..c8029ac80 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -92,6 +92,8 @@ VideoStore::VideoStore( //video_in_ctx.codec_id = video_in_stream->codecpar.codec_id; #else video_in_ctx = video_in_stream->codec; +Debug(2,"Copied video context from input stream"); + zm_dump_codec(video_in_ctx); #endif } else { Debug(2, "No input ctx"); @@ -147,6 +149,13 @@ VideoStore::VideoStore( video_out_ctx->width = monitor->Width(); video_out_ctx->height = monitor->Height(); video_out_ctx->codec_type = AVMEDIA_TYPE_VIDEO; + if (oc->oformat->flags & AVFMT_GLOBALHEADER) { +#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) + video_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; +#else + video_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; +#endif + } if ( monitor->OutputCodec() == "mjpeg" ) { video_out_codec = avcodec_find_encoder_by_name("mjpeg"); @@ -199,8 +208,8 @@ VideoStore::VideoStore( av_dict_set( &opts, "preset", "ultrafast", 0 ); } if ( ! av_dict_get( opts, "tune", NULL, 0 ) ) { - Debug(2,"Setting tune to lowlatency"); - av_dict_set( &opts, "tune", "lowlatency", 0 ); + Debug(2,"Setting tune to zerolatency"); + av_dict_set( &opts, "tune", "zerolatency", 0 ); } if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) { @@ -832,38 +841,8 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { Debug(3, "Have encoding video frame count (%d)", frame_count); if ( ! zm_packet->frame ) { - if ( zm_packet->packet.size ) { - AVPacket *ipkt = &zm_packet->packet; - -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - if ( ( ret = avcodec_send_packet(video_in_ctx, ipkt) ) < 0 ) { - Error("avcodec_send_packet fail %s", av_make_error_string(ret).c_str()); - return 0; - } - if ( ( ret = avcodec_receive_frame(video_in_ctx, in_frame) ) < 0 ) { - Error("avcodec_receive_frame fail %s", av_make_error_string(ret).c_str()); - return 0; - } -#else - int data_present; - if ((ret = avcodec_decode_video2(video_in_ctx, in_frame, - &data_present, ipkt )) < 0) { - Error("Could not decode frame (error '%s')\n", - av_make_error_string(ret).c_str()); - av_frame_free(&in_frame); - return 0; - } else { - Debug(3, "Decoded frame data_present(%d)", data_present); - } - if ( !data_present ) { - Debug(2, "Not ready to transcode a frame yet."); - return 0; - } -#endif - zm_packet->frame = in_frame; - } else if ( zm_packet->image ) { - AVFrame *frame = zm_packet->frame = zm_av_frame_alloc(); - if ( ! frame ) { + AVFrame *out_frame = zm_packet->frame = zm_av_frame_alloc(); + if ( ! out_frame ) { Error("Unable to allocate a frame"); return 0; } @@ -874,8 +853,8 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { video_out_ctx->height, 1); zm_packet->buffer = (uint8_t *)av_malloc(codec_imgsize); av_image_fill_arrays( - frame->data, - frame->linesize, + out_frame->data, + out_frame->linesize, zm_packet->buffer, video_out_ctx->pix_fmt, video_out_ctx->width, @@ -888,7 +867,7 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { video_out_ctx->height); zm_packet->buffer = (uint8_t *)av_malloc(codec_imgsize); avpicture_fill( - (AVPicture *)frame, + (AVPicture *)out_frame, zm_packet->buffer, video_out_ctx->pix_fmt, video_out_ctx->width, @@ -896,9 +875,21 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { ); #endif - frame->width = video_out_ctx->width; - frame->height = video_out_ctx->height; - frame->format = video_out_ctx->pix_fmt; + out_frame->width = video_out_ctx->width; + out_frame->height = video_out_ctx->height; + out_frame->format = video_out_ctx->pix_fmt; + + if ( ! zm_packet->in_frame ) { + if ( zm_packet->packet.size ) { + if ( ! zm_packet->decode( video_in_ctx ) ) { + Debug(2, "unable to decode yet."); + return 0; + } + } + //Go straight to out frame + swscale.Convert( zm_packet->in_frame, out_frame ); + } else if ( zm_packet->image ) { + //Go straight to out frame swscale.Convert(zm_packet->image, zm_packet->buffer, codec_imgsize, diff --git a/version b/version index 45eecfe53..623203d2d 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.31.13 +1.31.12 From 93c79efc729bfed6d533fa08f2acaa46d689ebf7 Mon Sep 17 00:00:00 2001 From: APHW2 MFGENG Date: Tue, 14 Nov 2017 13:16:56 -0800 Subject: [PATCH 0037/2339] test out more options --- src/zm_videostore.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 6fb35768a..20ecd830d 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -175,7 +175,7 @@ VideoStore::VideoStore( video_out_ctx->pix_fmt = AV_PIX_FMT_YUV420P; /* video time_base can be set to whatever is handy and supported by encoder */ video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate - video_out_ctx->framerate = (AVRational){0,1}; // Unknown framerate + video_out_ctx->framerate = (AVRational){0,24}; // Unknown framerate #if 1 video_out_ctx->gop_size = 12; video_out_ctx->qmin = 10; @@ -206,7 +206,7 @@ VideoStore::VideoStore( av_dict_set( &opts, "crf", "0", 0 ); } #endif -#if 1 +#if 0 if ( ! av_dict_get( opts, "tune", NULL, 0 ) ) { Debug(2,"Setting tune to zerolatency"); av_dict_set( &opts, "tune", "zerolatency", 0 ); @@ -236,7 +236,6 @@ VideoStore::VideoStore( Debug(2,"Setting crf to 0"); av_dict_set( &opts, "crf", "0", 0 ); } -#else if ( ! av_dict_get( opts, "tune", NULL, 0 ) ) { Debug(2,"Setting tune to zerolatency"); av_dict_set( &opts, "tune", "zerolatency", 0 ); @@ -433,7 +432,7 @@ bool VideoStore::open() { AVDictionary *opts = NULL; // av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0); - // av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0); + av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0); // av_dict_set(&opts, "movflags", // "frag_keyframe+empty_moov+default_base_moof", 0); if ( (ret = avformat_write_header(oc, &opts)) < 0 ) { @@ -945,6 +944,8 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { zm_packet->frame->pts = ( zm_packet->timestamp.tv_sec*1000000 + zm_packet->timestamp.tv_usec ) - video_last_pts; } + // Do this to allow the encoder to choose whether to use I/P/B frame + zm_packet->frame->pict_type = AV_PICTURE_TYPE_NONE; #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) if ( (ret = avcodec_send_frame(video_out_ctx, zm_packet->frame)) < 0 ) { Error("Could not send frame (error '%s')", av_make_error_string(ret).c_str()); From bb6e6c18eb04e4035d0b33a6a5a7ac16095d86ce Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 14 Nov 2017 13:17:50 -0800 Subject: [PATCH 0038/2339] add defaults for CaptureFPS and AnalysisFPS --- web/includes/Monitor.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/web/includes/Monitor.php b/web/includes/Monitor.php index c95a11975..40990a17e 100644 --- a/web/includes/Monitor.php +++ b/web/includes/Monitor.php @@ -15,8 +15,10 @@ private $defaults = array( 'Height' => null, 'Orientation' => null, 'AnalysisFPSLimit' => null, -'OutputCodec', -'OutputContainer', +'OutputCodec' => 'h264', +'OutputContainer' => 'auto', +'AnalysisFPS' => null, +'CaptureFPS' => null, ); private $control_fields = array( 'Name' => '', From 028aa9f161e194de8682f0df723066c3ac1f7770 Mon Sep 17 00:00:00 2001 From: APHW2 MFGENG Date: Tue, 14 Nov 2017 15:32:37 -0800 Subject: [PATCH 0039/2339] fix segfault --- src/zm_videostore.cpp | 103 ++++++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 48 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 1ff5fb936..14a57e606 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -859,7 +859,6 @@ int VideoStore::writePacket( ZMPacket *ipkt ) { } int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { - av_init_packet(&opkt); frame_count += 1; // if we have to transcode @@ -867,65 +866,72 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { Debug(3, "Have encoding video frame count (%d)", frame_count); if ( ! zm_packet->frame ) { + Debug(3, "Have no out frame"); AVFrame *out_frame = zm_packet->frame = zm_av_frame_alloc(); - if ( ! out_frame ) { - Error("Unable to allocate a frame"); - return 0; - } + if ( ! out_frame ) { + Error("Unable to allocate a frame"); + return 0; + } #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) - int codec_imgsize = av_image_get_buffer_size( - video_out_ctx->pix_fmt, - video_out_ctx->width, - video_out_ctx->height, 1); - zm_packet->buffer = (uint8_t *)av_malloc(codec_imgsize); - av_image_fill_arrays( - out_frame->data, - out_frame->linesize, - zm_packet->buffer, - video_out_ctx->pix_fmt, - video_out_ctx->width, - video_out_ctx->height, - 1); + int codec_imgsize = av_image_get_buffer_size( + video_out_ctx->pix_fmt, + video_out_ctx->width, + video_out_ctx->height, 1); + zm_packet->buffer = (uint8_t *)av_malloc(codec_imgsize); + av_image_fill_arrays( + out_frame->data, + out_frame->linesize, + zm_packet->buffer, + video_out_ctx->pix_fmt, + video_out_ctx->width, + video_out_ctx->height, + 1); #else - int codec_imgsize = avpicture_get_size( - video_out_ctx->pix_fmt, - video_out_ctx->width, - video_out_ctx->height); - zm_packet->buffer = (uint8_t *)av_malloc(codec_imgsize); - avpicture_fill( - (AVPicture *)out_frame, - zm_packet->buffer, - video_out_ctx->pix_fmt, - video_out_ctx->width, - video_out_ctx->height - ); + int codec_imgsize = avpicture_get_size( + video_out_ctx->pix_fmt, + video_out_ctx->width, + video_out_ctx->height); + zm_packet->buffer = (uint8_t *)av_malloc(codec_imgsize); + avpicture_fill( + (AVPicture *)out_frame, + zm_packet->buffer, + video_out_ctx->pix_fmt, + video_out_ctx->width, + video_out_ctx->height + ); #endif - out_frame->width = video_out_ctx->width; - out_frame->height = video_out_ctx->height; - out_frame->format = video_out_ctx->pix_fmt; + out_frame->width = video_out_ctx->width; + out_frame->height = video_out_ctx->height; + out_frame->format = video_out_ctx->pix_fmt; if ( ! zm_packet->in_frame ) { + Debug(2,"Have no in_frame"); if ( zm_packet->packet.size ) { + Debug(2,"Decoding"); if ( ! zm_packet->decode( video_in_ctx ) ) { Debug(2, "unable to decode yet."); return 0; } - } - //Go straight to out frame - swscale.Convert( zm_packet->in_frame, out_frame ); - } else if ( zm_packet->image ) { - //Go straight to out frame - swscale.Convert(zm_packet->image, - zm_packet->buffer, - codec_imgsize, - (AVPixelFormat)zm_packet->image->AVPixFormat(), - video_out_ctx->pix_fmt, - video_out_ctx->width, - video_out_ctx->height - ); + //Go straight to out frame + swscale.Convert( zm_packet->in_frame, out_frame ); + } else if ( zm_packet->image ) { + Debug(2,"Have an image, convert it"); + //Go straight to out frame + swscale.Convert(zm_packet->image, + zm_packet->buffer, + codec_imgsize, + (AVPixelFormat)zm_packet->image->AVPixFormat(), + video_out_ctx->pix_fmt, + video_out_ctx->width, + video_out_ctx->height + ); - } // end if has packet or image + } else { + Error("Have neither in_frame or image!"); + return 0; + } // end if has packet or image + } // end if no in_Frmae } // end if no frame if ( ! video_last_pts ) { @@ -940,9 +946,10 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) if ( (ret = avcodec_send_frame(video_out_ctx, zm_packet->frame)) < 0 ) { Error("Could not send frame (error '%s')", av_make_error_string(ret).c_str()); - zm_av_packet_unref(&opkt); // NOT SURE THIS IS NECCESSARY return -1; } + + av_init_packet(&opkt); if ( (ret = avcodec_receive_packet(video_out_ctx, &opkt)) < 0 ) { zm_av_packet_unref(&opkt); if ( AVERROR(EAGAIN) == ret ) { From cca9fb13cc064f38027f431471f12a5449a90061 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 14 Nov 2017 15:33:31 -0800 Subject: [PATCH 0040/2339] add FPS to console --- web/includes/Event.php | 2 +- web/skins/classic/views/console.php | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/web/includes/Event.php b/web/includes/Event.php index 189f4eefe..b56c9962a 100644 --- a/web/includes/Event.php +++ b/web/includes/Event.php @@ -215,7 +215,7 @@ class Event { $eventPath = $this->Path(); if ( file_exists( $eventPath.'/snapshot.jpg' ) ) { $frame = 'snapshot'; - $humbData = array('Path'=>$eventPath.'/snapshot.jpg'); + $thumbData = array('Path'=>$eventPath.'/snapshot.jpg'); } else { # Load the frame with the highest score to use as a thumbnail if ( !($frame = dbFetchOne( 'SELECT * FROM Frames WHERE EventId=? AND Score=? ORDER BY FrameId LIMIT 1', NULL, array( $this->{'Id'}, $this->{'MaxScore'} ) )) ) { diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index 4433b0afc..92c1a82c7 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -212,7 +212,10 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { } ?> - '.translate('Fn'.$monitor['Function']).( empty($monitor['Enabled']) ? ', disabled' : '' ) .'', canEdit( 'Monitors' ) ) ?> + + '.translate('Fn'.$monitor['Function']).( empty($monitor['Enabled']) ? ', disabled' : '' ) .'', canEdit( 'Monitors' ) ) ?>
+ + Name(); ?> From 7bff9a80832a69ea22657199892255adde396b8d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 16 Nov 2017 20:37:40 -0500 Subject: [PATCH 0041/2339] fix to compile --- src/zm_config.cpp | 1 + src/zm_videostore.cpp | 4 ++-- version | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/zm_config.cpp b/src/zm_config.cpp index 65a3f6591..1bd5b7f9d 100644 --- a/src/zm_config.cpp +++ b/src/zm_config.cpp @@ -28,6 +28,7 @@ #include #include "zm_utils.h" +#include "zm_config.h" void zmLoadConfig() { diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 14a57e606..53b227d5a 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -184,7 +184,7 @@ Debug(2,"Copied video context from input stream"); video_out_ctx->pix_fmt = AV_PIX_FMT_YUV420P; /* video time_base can be set to whatever is handy and supported by encoder */ video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate - video_out_ctx->framerate = (AVRational){0,24}; // Unknown framerate + //video_out_ctx->framerate = (AVRational){0,24}; // Unknown framerate #if 1 video_out_ctx->gop_size = 12; video_out_ctx->qmin = 10; @@ -942,8 +942,8 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { } // Do this to allow the encoder to choose whether to use I/P/B frame - zm_packet->frame->pict_type = AV_PICTURE_TYPE_NONE; #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + zm_packet->frame->pict_type = AV_PICTURE_TYPE_NONE; if ( (ret = avcodec_send_frame(video_out_ctx, zm_packet->frame)) < 0 ) { Error("Could not send frame (error '%s')", av_make_error_string(ret).c_str()); return -1; diff --git a/version b/version index 623203d2d..45eecfe53 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.31.12 +1.31.13 From 778942b9289ee8f22810a2f4fc7f955321ccf036 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 16 Nov 2017 17:39:48 -0800 Subject: [PATCH 0042/2339] improve add_monitors --- web/ajax/add_monitors.php | 12 ++++++++++-- web/skins/classic/js/classic.js | 2 +- web/skins/classic/views/add_monitors.php | 2 +- web/skins/classic/views/console.php | 2 +- web/skins/classic/views/js/add_monitors.js | 4 ++-- web/skins/classic/views/js/console.js | 8 ++++++-- 6 files changed, 21 insertions(+), 9 deletions(-) diff --git a/web/ajax/add_monitors.php b/web/ajax/add_monitors.php index b95f0e8f4..89a0d5daa 100644 --- a/web/ajax/add_monitors.php +++ b/web/ajax/add_monitors.php @@ -1,4 +1,5 @@ set(array( 'StorageId' => 1, 'ServerId' => 'auto', - 'Function' => 'Record', + 'Function' => 'Mocord', 'Type' => 'Ffmpeg', 'Enabled' => '1', 'Colour' => '4', // 32bit - 'PreEventCount' => 0, + 'ImageBufferCount' => '20', + 'WarmupCount' => '0', + 'PreEventCount' => '0', + 'StreamReplayBuffer' => '0', + 'SaveJPEGs' => '4', + 'VideoWriter' => '1', + 'MaxFPS' => '20', + 'AlarmMaxFPS' => '20', ) ); function probe( &$url_bits ) { diff --git a/web/skins/classic/js/classic.js b/web/skins/classic/js/classic.js index 084997e3a..715afa5b0 100644 --- a/web/skins/classic/js/classic.js +++ b/web/skins/classic/js/classic.js @@ -47,7 +47,7 @@ var popupSizes = { 'log': { 'width': 1080, 'height': 720 }, 'login': { 'width': 720, 'height': 480 }, 'logout': { 'width': 260, 'height': 150 }, - 'monitor': { 'width': 700, 'height': 640 }, + 'monitor': { 'width': 700, 'height': 720 }, 'monitorpreset':{ 'width': 440, 'height': 200 }, 'monitorprobe': { 'width': 500, 'height': 240 }, 'monitorselect':{ 'width': 160, 'height': 200 }, diff --git a/web/skins/classic/views/add_monitors.php b/web/skins/classic/views/add_monitors.php index 61f26c4d5..b77c048d5 100644 --- a/web/skins/classic/views/add_monitors.php +++ b/web/skins/classic/views/add_monitors.php @@ -45,7 +45,7 @@ xhtmlHeaders(__FILE__, translate('AddMonitors'));
Enter by IP or URL - +
Import CSV Spreadsheet Spreadsheet should have the following format:
diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index 92c1a82c7..8aaef178a 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -270,7 +270,7 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { - + diff --git a/web/skins/classic/views/js/add_monitors.js b/web/skins/classic/views/js/add_monitors.js index a94fd2200..ca52eca5b 100644 --- a/web/skins/classic/views/js/add_monitors.js +++ b/web/skins/classic/views/js/add_monitors.js @@ -8,9 +8,9 @@ function probe( url_e ) { var ProbeResults; function getProbeResponse( respObj, respText ) { - if ( checkStreamForErrors( "getProbeResponse", respObj ) ) + if ( checkStreamForErrors( "getProbeResponse", respObj ) ) { return; -//alert(respText); + } if ( respObj.Streams ) { parseStreams( respObj.Streams ); diff --git a/web/skins/classic/views/js/console.js b/web/skins/classic/views/js/console.js index 3ba206f81..a9659b280 100644 --- a/web/skins/classic/views/js/console.js +++ b/web/skins/classic/views/js/console.js @@ -34,8 +34,12 @@ function addMonitor(element) { } } } - dupParam = (monitorId == -1 ) ? '': '&dupId='+monitorId; - createPopup( '?view=monitor'+dupParam, 'zmMonitor0', 'monitor' ); + if ( monitorId == -1 ) { + window.location = '?view=add_monitors'; + //createPopup( '?view=add_monitors', 'zmMonitor0', 'monitor' ); + } else { + createPopup( '?view=monitor&dupId='+monitorId, 'zmMonitor0', 'monitor' ); + } } function editMonitor( element ) { From 6702b10dee2c562ea7210ee432a8a1f4ba01218c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 17 Nov 2017 15:37:26 -0500 Subject: [PATCH 0043/2339] remove redundant code and memory leaks --- src/zm_ffmpeg.cpp | 58 +++++++++++++++----------------------- src/zm_ffmpeg_camera.cpp | 6 ++-- src/zm_monitor.cpp | 16 +++++++---- src/zm_videostore.cpp | 61 ++++++++++++++++++++++++++++++++-------- 4 files changed, 83 insertions(+), 58 deletions(-) diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index 9221e2f78..ca07a0f81 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -184,46 +184,32 @@ int hacked_up_context2_for_older_ffmpeg(AVFormatContext **avctx, AVOutputFormat } } - 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; } + + s->oformat = oformat; +#if 0 + if (s->oformat->priv_data_size > 0) { + if (s->oformat->priv_class) { + // This looks wrong, we just allocated priv_data and now we are losing the pointer to it.FIXME + *(const AVClass**)s->priv_data = s->oformat->priv_class; + av_opt_set_defaults(s->priv_data); + } else { + s->priv_data = av_mallocz(s->oformat->priv_data_size); + if ( ! s->priv_data) { + av_log(s, AV_LOG_ERROR, "Out of memory\n"); + ret = AVERROR(ENOMEM); + return ret; + } + s->priv_data = NULL; + } +#endif + + if (filename) strncpy(s->filename, filename, sizeof(s->filename)); + *avctx = s; + return 0; } static void zm_log_fps(double d, const char *postfix) { diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 79ed3d579..72e2270eb 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -285,10 +285,8 @@ int FfmpegCamera::OpenFfmpeg() { Info( "Stream open %s", mPath.c_str() ); #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" ); 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) ); @@ -559,12 +557,12 @@ int FfmpegCamera::CloseFfmpeg() { if ( mVideoCodecContext ) { avcodec_close(mVideoCodecContext); - //av_free(mVideoCodecContext); + avcodec_free_context(&mVideoCodecContext); mVideoCodecContext = NULL; // Freed by av_close_input_file } if ( mAudioCodecContext ) { avcodec_close(mAudioCodecContext); - //av_free(mAudioCodecContext); + avcodec_free_context(&mAudioCodecContext); mAudioCodecContext = NULL; // Freed by av_close_input_file } diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 1003691a0..80684ad53 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -554,12 +554,16 @@ bool Monitor::connect() { // alarmed images that must be discarded when event is created // Couldn't we just make sure there is always enough frames in the ring buffer? - pre_event_buffer_count = pre_event_count + alarm_frame_count - 1; - pre_event_buffer = new ZMPacket[pre_event_buffer_count]; - for ( int i = 0; i < pre_event_buffer_count; i++ ) { - pre_event_buffer[i].image = new Image( width, height, camera->Colours(), camera->SubpixelOrder()); + if ( purpose == ANALYSIS ) { + if ( analysis_fps ) { + pre_event_buffer_count = pre_event_count + alarm_frame_count - 1; + pre_event_buffer = new ZMPacket[pre_event_buffer_count]; + for ( int i = 0; i < pre_event_buffer_count; i++ ) { + pre_event_buffer[i].image = new Image( width, height, camera->Colours(), camera->SubpixelOrder()); + } } -Debug(3, "Success connecting"); + } + Debug(3, "Success connecting"); return true; } // Monitor::connect @@ -1614,7 +1618,7 @@ Debug(3,"Not ready?"); shared_data->last_read_time = now.tv_sec; mutex.unlock(); - if ( analysis_fps ) { + if ( (purpose == ANALYSIS) && analysis_fps ) { // If analysis fps is set, add analysed image to dedicated pre event buffer Debug(3,"analysis fps image_count(%d) pre_event_buffer_count(%d)", image_count, pre_event_buffer_count ); int pre_index = pre_event_buffer_count ? image_count%pre_event_buffer_count : 0; diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index fff0dd170..453e6a8e0 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -95,6 +95,23 @@ VideoStore::VideoStore( Debug(2,"Copied video context from input stream"); zm_dump_codec(video_in_ctx); #endif + // Fix deprecated formats + switch ( video_in_ctx->pix_fmt ) { + case AV_PIX_FMT_YUVJ420P : + video_in_ctx->pix_fmt = AV_PIX_FMT_YUV420P; + break; + case AV_PIX_FMT_YUVJ422P : + video_in_ctx->pix_fmt = AV_PIX_FMT_YUV422P; + break; + case AV_PIX_FMT_YUVJ444P : + video_in_ctx->pix_fmt = AV_PIX_FMT_YUV444P; + break; + case AV_PIX_FMT_YUVJ440P : + video_in_ctx->pix_fmt = AV_PIX_FMT_YUV440P; + break; + default: + break; + } } else { Debug(2, "No input ctx"); video_in_ctx = avcodec_alloc_context3(NULL); @@ -139,6 +156,24 @@ Debug(2,"Copied video context from input stream"); Warning("Unsupported Orientation(%d)", orientation); } } + // Fix deprecated formats + switch ( video_out_ctx->pix_fmt ) { + case AV_PIX_FMT_YUVJ420P : + video_out_ctx->pix_fmt = AV_PIX_FMT_YUV420P; + break; + case AV_PIX_FMT_YUVJ422P : + video_out_ctx->pix_fmt = AV_PIX_FMT_YUV422P; + break; + case AV_PIX_FMT_YUVJ444P : + video_out_ctx->pix_fmt = AV_PIX_FMT_YUV444P; + break; + case AV_PIX_FMT_YUVJ440P : + video_out_ctx->pix_fmt = AV_PIX_FMT_YUV440P; + break; + default: + break; + } + } else { /** Create a new frame to store the */ @@ -462,8 +497,8 @@ bool VideoStore::open() { } // end bool VideoStore::open() void VideoStore::write_audio_packet( AVPacket &pkt ) { - Debug(2, "writing flushed packet pts(%d) dts(%d) duration(%d)", pkt.pts, - pkt.dts, pkt.duration); +//Debug(2, "writing audio packet pts(%d) dts(%d) duration(%d)", pkt.pts, + //pkt.dts, pkt.duration); pkt.pts = audio_next_pts; pkt.dts = audio_next_dts; @@ -474,7 +509,7 @@ void VideoStore::write_audio_packet( AVPacket &pkt ) { audio_next_pts += pkt.duration; audio_next_dts += pkt.duration; - Debug(2, "writing flushed packet pts(%d) dts(%d) duration(%d)", pkt.pts, + Debug(2, "writing audio packet pts(%d) dts(%d) duration(%d)", pkt.pts, pkt.dts, pkt.duration); pkt.stream_index = audio_out_stream->index; av_interleaved_write_frame(oc, &pkt); @@ -591,18 +626,18 @@ Debug(3, "dts:%d, pts:%d, keyframe:%d", pkt.dts, pkt.pts, keyframe ); // allocation/de-allocation constantly, or whether we can just re-use it. // Just do a file open/close/writeheader/etc. // What if we were only doing audio recording? - if ( video_out_stream ) { - avcodec_close(video_out_ctx); - video_out_ctx = NULL; - Debug(4, "Success freeing video_out_ctx"); - } // Used by both audio and video conversions if ( in_frame ) { av_frame_free(&in_frame); in_frame = NULL; } + if ( audio_in_ctx ) { + avcodec_free_context(&audio_in_ctx); + audio_in_ctx = NULL; + } if ( audio_out_stream ) { avcodec_close(audio_out_ctx); + avcodec_free_context(&audio_out_ctx); audio_out_ctx = NULL; #ifdef HAVE_LIBAVRESAMPLE if ( resample_ctx ) { @@ -621,12 +656,13 @@ Debug(3, "dts:%d, pts:%d, keyframe:%d", pkt.dts, pkt.pts, keyframe ); } #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) if ( video_in_ctx ) { - avcodec_free_context(&video_in_ctx); - video_in_ctx = NULL; + avcodec_free_context(&video_in_ctx); + video_in_ctx = NULL; } if ( video_out_ctx ) { - avcodec_free_context(&video_out_ctx); - video_out_ctx = NULL; + avcodec_close(video_out_ctx); + avcodec_free_context(&video_out_ctx); + video_out_ctx = NULL; } #endif @@ -995,6 +1031,7 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { opkt.dts = opkt.pts = ( zm_packet->timestamp.tv_sec*1000000 + zm_packet->timestamp.tv_usec ) - video_last_pts; } } + opkt.duration = 0; int keyframe = opkt.flags & AV_PKT_FLAG_KEY; Debug(3, "dts:%d, pts:%d, keyframe:%d", opkt.dts, opkt.pts, keyframe ); From cd596d49e39daa10f85b9720221a8988b263430c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 17 Nov 2017 16:49:01 -0500 Subject: [PATCH 0044/2339] fix local camera inputstream --- src/zm_local_camera.cpp | 30 ++++++++++++++++++++++++++++++ src/zm_local_camera.h | 1 + src/zm_logger.cpp | 2 +- src/zm_monitor.cpp | 12 ++++++++---- src/zm_videostore.cpp | 2 ++ src/zmc.cpp | 2 +- 6 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/zm_local_camera.cpp b/src/zm_local_camera.cpp index a97a6470e..47ab5f065 100644 --- a/src/zm_local_camera.cpp +++ b/src/zm_local_camera.cpp @@ -650,6 +650,9 @@ LocalCamera::LocalCamera( } } // end if capture and conversion_tye == swscale #endif + mVideoStreamId = 0; + mAudioStreamId = -1; + video_stream = NULL; } // end LocalCamera::LocalCamera LocalCamera::~LocalCamera() { @@ -2105,5 +2108,32 @@ int LocalCamera::PostCapture() { } return( 0 ); } +AVStream *LocalCamera::get_VideoStream() { + if ( ! video_stream ) { + AVFormatContext *oc = avformat_alloc_context(); + video_stream = avformat_new_stream( oc, NULL ); + if ( video_stream ) { +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + video_stream->codecpar->width = width; + video_stream->codecpar->height = height; + video_stream->codecpar->format = GetFFMPEGPixelFormat(colours,subpixelorder); + video_stream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; +#else + video_stream->codec->width = width; + video_stream->codec->height = height; + video_stream->codec->pix_fmt = GetFFMPEGPixelFormat(colours,subpixelorder); + video_stream->codec->codec_type = AVMEDIA_TYPE_VIDEO; +#endif + } else { + Error("Can't create video stream"); + } + } else { + Debug(2,"Have videostream"); + } + Debug(2,"Get videoStream"); + return video_stream; +} + #endif // ZM_HAS_V4L + diff --git a/src/zm_local_camera.h b/src/zm_local_camera.h index de1d7f9c5..57f8aaa40 100644 --- a/src/zm_local_camera.h +++ b/src/zm_local_camera.h @@ -159,6 +159,7 @@ public: int Capture(ZMPacket &p); int PostCapture(); static bool GetCurrentSettings( const char *device, char *output, int version, bool verbose ); +AVStream* get_VideoStream(); }; #endif // ZM_HAS_V4L diff --git a/src/zm_logger.cpp b/src/zm_logger.cpp index ffebff726..f2797f8e7 100644 --- a/src/zm_logger.cpp +++ b/src/zm_logger.cpp @@ -498,7 +498,7 @@ void Logger::logPrint( bool hex, const char * const filepath, const int line, co va_start( argPtr, fstring ); if ( hex ) { unsigned char *data = va_arg( argPtr, unsigned char * ); - int len = va_arg( argPtr, int ); + int len = va_arg( argPtr, int32_t ); int i; logPtr += snprintf( logPtr, sizeof(logString)-(logPtr-logString), "%d:", len ); for ( i = 0; i < len; i++ ) { diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 80684ad53..9ab4e9a37 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -600,6 +600,7 @@ Monitor::~Monitor() { if ( purpose == ANALYSIS ) { shared_data->state = state = IDLE; + // I think we set it to the count so that it is technically 1 behind capture, which starts at 0 shared_data->last_read_index = image_buffer_count; shared_data->last_read_time = 0; @@ -1202,10 +1203,13 @@ bool Monitor::Analyse() { ZMPacket *snap = &image_buffer[index]; if ( snap->packet.stream_index != camera->get_VideoStreamId() ) { + Debug(2, "Non video packet in analysis (%d) != (%d)", snap->packet.stream_index, camera->get_VideoStreamId() ); if ( event ) { //event->AddFrame( snap_image, *timestamp, score ); event->AddPacket( snap, 0 ); } + shared_data->last_read_index = index % image_buffer_count; + shared_data->last_read_time = now.tv_sec; mutex.unlock(); return false; } @@ -3022,10 +3026,10 @@ packet->reset(); } #endif - shared_data->signal = CheckSignal(capture_image); - shared_data->last_write_index = index; - shared_data->last_write_time = image_buffer[index].timestamp.tv_sec; - image_count++; + shared_data->signal = CheckSignal(capture_image); + shared_data->last_write_index = index; + shared_data->last_write_time = image_buffer[index].timestamp.tv_sec; + image_count++; } else { // result == 0 } // end if result diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 453e6a8e0..a72627bbb 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -86,8 +86,10 @@ VideoStore::VideoStore( video_in_stream_index = video_in_stream->index; #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) video_in_ctx = avcodec_alloc_context3(NULL); + Debug(2, "copy to context"); avcodec_parameters_to_context(video_in_ctx, video_in_stream->codecpar); + Debug(2, "dump to context"); zm_dump_codecpar( video_in_stream->codecpar ); //video_in_ctx.codec_id = video_in_stream->codecpar.codec_id; #else diff --git a/src/zmc.cpp b/src/zmc.cpp index 6dd833e5d..7d391d22a 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -317,7 +317,7 @@ int main(int argc, char *argv[]) { DELTA_TIMEVAL(delta_time, now, last_capture_times[i], DT_PREC_3); long sleep_time = next_delays[i]-delta_time.delta; if ( sleep_time > 0 ) { - Debug(2,"usleeping (%d)", sleep_time*(DT_MAXGRAN/DT_PREC_3) ); + //Debug(2,"usleeping (%d)", sleep_time*(DT_MAXGRAN/DT_PREC_3) ); usleep(sleep_time*(DT_MAXGRAN/DT_PREC_3)); } last_capture_times[i] = now; From 28286c7967e3cbb8d846e6721814df233add496a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 17 Nov 2017 16:49:28 -0500 Subject: [PATCH 0045/2339] fix spacing --- src/zm_local_camera.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/zm_local_camera.cpp b/src/zm_local_camera.cpp index a97a6470e..59abedd25 100644 --- a/src/zm_local_camera.cpp +++ b/src/zm_local_camera.cpp @@ -358,7 +358,7 @@ LocalCamera::LocalCamera( } #endif - if( capture ) { + if ( capture ) { if ( last_camera ) { if ( (p_method == "v4l2" && v4l_version != 2) || (p_method == "v4l1" && v4l_version != 1) ) Fatal( "Different Video For Linux version used for monitors sharing same device" ); @@ -1932,12 +1932,14 @@ int LocalCamera::Capture( ZMPacket &zm_packet ) { Debug( 3, "Capturing %d frames", captures_per_frame ); while ( captures_per_frame ) { + Debug( 3, "Capturing %d frames", captures_per_frame ); if ( vidioctl( vid_fd, VIDIOC_DQBUF, &vid_buf ) < 0 ) { - if ( errno == EIO ) - Warning( "Capture failure, possible signal loss?: %s", strerror(errno) ) - else - Error( "Unable to capture frame %d: %s", vid_buf.index, strerror(errno) ) - return -1; + if ( errno == EIO ) { + Warning( "Capture failure, possible signal loss?: %s", strerror(errno) ); + } else { + Error( "Unable to capture frame %d: %s", vid_buf.index, strerror(errno) ); + } + return -1; } v4l2_data.bufptr = &vid_buf; From f5f45b3397e51d77e4bc12f70afffc5cb1113fa9 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 17 Nov 2017 16:50:44 -0500 Subject: [PATCH 0046/2339] add Copy --- src/zm_config.h.in | 1 + 1 file changed, 1 insertion(+) diff --git a/src/zm_config.h.in b/src/zm_config.h.in index d018fa7f5..f90f9d440 100644 --- a/src/zm_config.h.in +++ b/src/zm_config.h.in @@ -110,6 +110,7 @@ public: ConfigItem(const char *p_name, const char *p_value, const char *const p_type); ConfigItem(const ConfigItem &); ~ConfigItem(); + void Copy( const ConfigItem &item ); void ConvertValue() const; bool BooleanValue() const; int IntegerValue() const; From 882563c06ed145c8078de57c05ea87fc5be0c27b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 17 Nov 2017 18:19:37 -0500 Subject: [PATCH 0047/2339] rename frame to out_frame. Fix problem where we weren't copying from in_frame to out_frame --- src/zm_monitor.cpp | 2 +- src/zm_packet.cpp | 24 +++++++++++------------- src/zm_packet.h | 4 ++-- src/zm_videostore.cpp | 23 +++++++++++++---------- 4 files changed, 27 insertions(+), 26 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 9ab4e9a37..c9e28a9e0 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -2891,7 +2891,7 @@ packet->reset(); return -1; } else if ( captureResult > 0 ) { - if ( packet->packet.size && ! packet->frame ) { + if ( packet->packet.size && ! packet->in_frame ) { if ( packet->packet.stream_index == camera->get_VideoStreamId() ) { packet->decode( camera->get_VideoCodecContext() ); packet->get_image(); diff --git a/src/zm_packet.cpp b/src/zm_packet.cpp index 4ce0a17ef..3ddfcc8c7 100644 --- a/src/zm_packet.cpp +++ b/src/zm_packet.cpp @@ -26,9 +26,10 @@ using namespace std; ZMPacket::ZMPacket( ) { keyframe = 0; - image = NULL; + // frame from decoded packet, to be used in generating image in_frame = NULL; - frame = NULL; + out_frame = NULL; + image = NULL; buffer = NULL; av_init_packet( &packet ); packet.size = 0; // So we can detect whether it has been filled. @@ -39,25 +40,23 @@ ZMPacket::ZMPacket( Image *i ) { keyframe = 1; image = i; in_frame = NULL; - frame = NULL; + out_frame = NULL; buffer = NULL; av_init_packet( &packet ); timestamp = (struct timeval){0}; } ZMPacket::ZMPacket( AVPacket *p ) { - frame = NULL; image = NULL; av_init_packet( &packet ); set_packet( p ); keyframe = p->flags & AV_PKT_FLAG_KEY; buffer = NULL; in_frame = NULL; - frame = NULL; + out_frame = NULL; } ZMPacket::ZMPacket( AVPacket *p, struct timeval *t ) { - frame = NULL; image = NULL; av_init_packet( &packet ); set_packet( p ); @@ -65,16 +64,15 @@ ZMPacket::ZMPacket( AVPacket *p, struct timeval *t ) { keyframe = p->flags & AV_PKT_FLAG_KEY; buffer = NULL; in_frame = NULL; - frame = NULL; + out_frame = NULL; } ZMPacket::ZMPacket( AVPacket *p, AVFrame *f, Image *i ) { av_init_packet( &packet ); set_packet( p ); image = i; - frame = f; buffer = NULL; in_frame = NULL; - frame = NULL; + out_frame = f; } ZMPacket::~ZMPacket() { @@ -83,9 +81,9 @@ ZMPacket::~ZMPacket() { //av_free(frame->data); av_frame_free( &in_frame ); } - if ( frame ) { + if ( out_frame ) { //av_free(frame->data); - av_frame_free( &frame ); + av_frame_free( &out_frame ); } if ( buffer ) { av_freep( &buffer ); @@ -102,9 +100,9 @@ void ZMPacket::reset() { //Debug(4,"reset frame"); av_frame_free( &in_frame ); } - if ( frame ) { + if ( out_frame ) { //Debug(4,"reset frame"); - av_frame_free( &frame ); + av_frame_free( &out_frame ); } if ( buffer ) { //Debug(4,"freeing buffer"); diff --git a/src/zm_packet.h b/src/zm_packet.h index 098ff5b99..45083510b 100644 --- a/src/zm_packet.h +++ b/src/zm_packet.h @@ -36,14 +36,14 @@ class ZMPacket { int keyframe; AVPacket packet; // Input packet, undecoded AVFrame *in_frame; // Input image, decoded Theoretically only filled if needed. - AVFrame *frame; // Input image, decoded Theoretically only filled if needed. + AVFrame *out_frame; // Input image, decoded Theoretically only filled if needed. uint8_t *buffer; Image *image; // Our internal image object representing this frame struct timeval timestamp; public: AVPacket *av_packet() { return &packet; } AVPacket *set_packet( AVPacket *p ) ; - AVFrame *av_frame() { return frame; } + AVFrame *av_frame() { return out_frame; } Image *get_image( Image *i=NULL ); Image *set_image( Image * ); diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index a72627bbb..e10179342 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -305,7 +305,7 @@ Debug(2,"Sucess opening codec"); if ( !video_out_ctx->codec_tag ) { video_out_ctx->codec_tag = av_codec_get_tag(oc->oformat->codec_tag, AV_CODEC_ID_H264 ); - Debug(2, "No codec_tag, setting to h264"); + Debug(2, "No codec_tag, setting to h264 ? "); } } else { Error("Codec not set"); @@ -903,9 +903,9 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { if ( video_out_ctx->codec_id != video_in_ctx->codec_id ) { Debug(3, "Have encoding video frame count (%d)", frame_count); - if ( ! zm_packet->frame ) { + if ( ! zm_packet->out_frame ) { Debug(3, "Have no out frame"); - AVFrame *out_frame = zm_packet->frame = zm_av_frame_alloc(); + AVFrame *out_frame = zm_packet->out_frame = zm_av_frame_alloc(); if ( ! out_frame ) { Error("Unable to allocate a frame"); return 0; @@ -969,20 +969,23 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { Error("Have neither in_frame or image!"); return 0; } // end if has packet or image - } // end if no in_Frmae - } // end if no frame + } else { + // Have in_frame.... may need to convert it to out_frame + swscale.Convert(zm_packet->in_frame, zm_packet->out_frame); + } // end if no in_frame + } // end if no out_frame if ( ! video_last_pts ) { video_last_pts = zm_packet->timestamp.tv_sec*1000000 + zm_packet->timestamp.tv_usec; - zm_packet->frame->pts = 0; + zm_packet->out_frame->pts = 0; } else { - zm_packet->frame->pts = ( zm_packet->timestamp.tv_sec*1000000 + zm_packet->timestamp.tv_usec ) - video_last_pts; + zm_packet->out_frame->pts = ( zm_packet->timestamp.tv_sec*1000000 + zm_packet->timestamp.tv_usec ) - video_last_pts; } // Do this to allow the encoder to choose whether to use I/P/B frame #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - zm_packet->frame->pict_type = AV_PICTURE_TYPE_NONE; - if ( (ret = avcodec_send_frame(video_out_ctx, zm_packet->frame)) < 0 ) { + zm_packet->out_frame->pict_type = AV_PICTURE_TYPE_NONE; + if ( (ret = avcodec_send_frame(video_out_ctx, zm_packet->out_frame)) < 0 ) { Error("Could not send frame (error '%s')", av_make_error_string(ret).c_str()); return -1; } @@ -1005,7 +1008,7 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { av_init_packet(&opkt); int data_present; if ( (ret = avcodec_encode_video2( - video_out_ctx, &opkt, zm_packet->frame, &data_present)) < 0) { + video_out_ctx, &opkt, zm_packet->out_frame, &data_present)) < 0) { Error("Could not encode frame (error '%s')", av_make_error_string(ret).c_str()); zm_av_packet_unref(&opkt); From 43b71fc49bb232b939887e3dcc8dcca3b1817b6b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 20 Nov 2017 15:32:40 -0500 Subject: [PATCH 0048/2339] rework --- scripts/zmaudit.pl.in | 2 +- src/zm_eventstream.cpp | 3 +- src/zm_ffmpeg.cpp | 45 +++++++++++++++ src/zm_ffmpeg.h | 6 +- src/zm_ffmpeg_input.cpp | 115 ++++++++++++++++--------------------- src/zm_ffmpeg_input.h | 2 +- src/zm_monitor.cpp | 41 ++++++------- src/zm_monitor.h | 3 +- src/zm_user.cpp | 35 +++++------ web/includes/functions.php | 25 ++++---- 10 files changed, 148 insertions(+), 129 deletions(-) diff --git a/scripts/zmaudit.pl.in b/scripts/zmaudit.pl.in index e0ba169ee..8d18eabc5 100644 --- a/scripts/zmaudit.pl.in +++ b/scripts/zmaudit.pl.in @@ -81,7 +81,7 @@ use constant EVENT_PATH => ($Config{ZM_DIR_EVENTS}=~m|/|) ? $Config{ZM_DIR_EVENTS} : ($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS}) ; -use constant ZM_AUDIT_PID => $Config{ZM_RUNDIR}.'/zm.pid' +use constant ZM_AUDIT_PID => '@ZM_RUNDIR@/zmaudit.pid'; $| = 1; diff --git a/src/zm_eventstream.cpp b/src/zm_eventstream.cpp index 817c8753a..4344e7f75 100644 --- a/src/zm_eventstream.cpp +++ b/src/zm_eventstream.cpp @@ -579,7 +579,6 @@ Image * EventStream::getImage( ) { Debug( 2, "EventStream::getImage path(%s) frame(%d)", event_data->path, curr_frame_id ); snprintf( filepath, sizeof(filepath), staticConfig.capture_file_format, event_data->path, curr_frame_id ); - Debug( 2, "EventStream::getImage path(%s) ", filepath, curr_frame_id ); Image *image = new Image( filepath ); return image; } @@ -657,7 +656,7 @@ bool EventStream::sendFrame( int delta_us ) { } else if ( ffmpeg_input ) { // Get the frame from the mp4 input Debug(1,"Getting frame from ffmpeg"); - AVFrame *frame = ffmpeg_input->get_frame( ffmpeg_input->get_video_stream_id() ); + AVFrame *frame = ffmpeg_input->get_frame( ffmpeg_input->get_video_stream_id(), curr_frame_id ); if ( frame ) { image = new Image( frame ); av_frame_free(&frame); diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index ca07a0f81..fe710ab87 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -373,3 +373,48 @@ bool is_audio_stream( AVStream * stream ) { } return false; } + +int zm_receive_frame( AVCodecContext *context, AVFrame *frame, AVPacket &packet ) { + int ret; +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + if ( (ret = avcodec_send_packet(context, &packet)) < 0 ) { + Error( "Unable to send packet %s, continuing", + av_make_error_string(ret).c_str() ); + return 0; + } + +#if HAVE_AVUTIL_HWCONTEXT_H + if ( hwaccel ) { + if ( (ret = avcodec_receive_frame(context, hwFrame)) < 0 ) { + Error( "Unable to receive frame %d: %s, continuing", streams[packet.stream_index].frame_count, + av_make_error_string(ret).c_str() ); + return 0; + } + if ( (ret = av_hwframe_transfer_data(frame, hwFrame, 0)) < 0 ) { + Error( "Unable to transfer frame at frame %d: %s, continuing", streams[packet.stream_index].frame_count, + av_make_error_string(ret).c_str() ); + return 0; + } + } else { +#endif + if ( (ret = avcodec_receive_frame(context, frame)) < 0 ) { + Error( "Unable to send packet %s, continuing", av_make_error_string(ret).c_str() ); + return 0; + } +#if HAVE_AVUTIL_HWCONTEXT_H + } +#endif + +# else + int frameComplete; + while ( !frameComplete ) { + if ( (ret = zm_avcodec_decode_video( context, frame, &frameComplete, &packet )) < 0 ) { + Error( "Unable to decode frame at frame %d: %s, continuing", + streams[packet.stream_index].frame_count, + av_make_error_string(ret).c_str() ); + return 0; + } + } +#endif + return 1; +} // end int zm_receive_frame( AVCodecContext *context, AVFrame *frame, AVPacket &packet ) diff --git a/src/zm_ffmpeg.h b/src/zm_ffmpeg.h index 10ad5260c..ff896e0ae 100644 --- a/src/zm_ffmpeg.h +++ b/src/zm_ffmpeg.h @@ -237,9 +237,8 @@ enum _AVPIXELFORMAT GetFFMPEGPixelFormat(unsigned int p_colours, unsigned p_subp */ #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) { + static 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); #else @@ -327,4 +326,5 @@ int check_sample_fmt(AVCodec *codec, enum AVSampleFormat sample_fmt); bool is_video_stream( AVStream * stream ); bool is_audio_stream( AVStream * stream ); +int zm_receive_frame( AVCodecContext *context, AVFrame *frame, AVPacket &packet ); #endif // ZM_FFMPEG_H diff --git a/src/zm_ffmpeg_input.cpp b/src/zm_ffmpeg_input.cpp index 8697d55b8..240dfff24 100644 --- a/src/zm_ffmpeg_input.cpp +++ b/src/zm_ffmpeg_input.cpp @@ -13,6 +13,9 @@ FFmpeg_Input::FFmpeg_Input() { } FFmpeg_Input::~FFmpeg_Input() { + if ( input_format_context ) { + Close(); + } if ( streams ) { delete streams; streams = NULL; @@ -25,7 +28,6 @@ int FFmpeg_Input::Open( const char *filepath ) { /** Open the input file to read from it. */ if ( (error = avformat_open_input( &input_format_context, filepath, NULL, NULL)) < 0 ) { - Error("Could not open input file '%s' (error '%s')\n", filepath, av_make_error_string(error).c_str() ); input_format_context = NULL; @@ -94,94 +96,73 @@ int FFmpeg_Input::Open( const char *filepath ) { return 0; } // end int FFmpeg_Input::Open( const char * filepath ) -AVFrame *FFmpeg_Input::get_frame( int stream_id ) { - Debug(1, "Getting frame from stream %d", stream_id ); +int FFmpeg_Input::Close( ) { + for ( unsigned int i = 0; i < input_format_context->nb_streams; i += 1 ) { + if ( streams[i].context ) { + avcodec_close( streams[i].context ); +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + avcodec_free_context(& streams[i].context ); +#endif + streams[i].context = NULL; + } + } + + if ( input_format_context ) { +#if !LIBAVFORMAT_VERSION_CHECK(53, 17, 0, 25, 0) + av_close_input_file( input_format_context ); +#else + avformat_close_input( &input_format_context ); +#endif + input_format_context = NULL; + } + return 1; +} // end int FFmpeg_Input::Close() + +AVFrame *FFmpeg_Input::get_frame( int stream_id, int frame_number ) { + Debug(1, "Getting frame from stream %d, frame_number(%d)", stream_id, frame_number ); - int frameComplete = false; AVPacket packet; av_init_packet( &packet ); AVFrame *frame = zm_av_frame_alloc(); - char errbuf[AV_ERROR_MAX_STRING_SIZE]; - while ( !frameComplete ) { - int ret = av_read_frame( input_format_context, &packet ); + while ( frame_number >= streams[stream_id].frame_count ) { + + int ret = av_read_frame(input_format_context, &packet); if ( ret < 0 ) { - av_strerror(ret, errbuf, AV_ERROR_MAX_STRING_SIZE); if ( // Check if EOF. (ret == AVERROR_EOF || (input_format_context->pb && input_format_context->pb->eof_reached)) || // Check for Connection failure. (ret == -110) ) { - Info( "av_read_frame returned %s.", errbuf ); - return NULL; + Info( "av_read_frame returned %s.", av_make_error_string(ret).c_str() ); + } else { + Error( "Unable to read packet from stream %d: error %d \"%s\".", packet.stream_index, ret, + av_make_error_string(ret).c_str() ); } - Error( "Unable to read packet from stream %d: error %d \"%s\".", packet.stream_index, ret, errbuf ); return NULL; } - if ( (stream_id < 0 ) || ( packet.stream_index == stream_id ) ) { - Debug(1,"Packet is for our stream (%d)", packet.stream_index ); + if ( ( stream_id < 0 ) || ( packet.stream_index != stream_id ) ) { + Warning("Packet is not for our stream (%d)", packet.stream_index); + return NULL; + } -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - AVCodecContext *context = streams[packet.stream_index].context; - - ret = avcodec_send_packet( context, &packet ); - if ( ret < 0 ) { - av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); - Error( "Unable to send packet at frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf ); + if ( ! zm_receive_frame( streams[packet.stream_index].context, frame, packet ) ) { + Error("Unable to get frame %d, continuing", streams[packet.stream_index].frame_count); zm_av_packet_unref( &packet ); continue; } else { - Debug(1, "Success getting a packet"); + Debug(1, "Success getting a packet at frame (%d)", streams[packet.stream_index].frame_count); + streams[packet.stream_index].frame_count += 1; } -#if HAVE_AVUTIL_HWCONTEXT_H - if ( hwaccel ) { - ret = avcodec_receive_frame( context, hwFrame ); - if ( ret < 0 ) { - av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); - Error( "Unable to receive frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf ); - zm_av_packet_unref( &packet ); - continue; - } - ret = av_hwframe_transfer_data(frame, hwFrame, 0); - if (ret < 0) { - av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); - Error( "Unable to transfer frame at frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf ); - zm_av_packet_unref( &packet ); - continue; - } - } else { -#endif - Debug(1,"Getting a frame?"); - ret = avcodec_receive_frame( context, frame ); - if ( ret < 0 ) { - av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); - Error( "Unable to send packet at frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf ); - zm_av_packet_unref( &packet ); - continue; - } + zm_av_packet_unref( &packet ); -#if HAVE_AVUTIL_HWCONTEXT_H - } -#endif - - frameComplete = 1; -# else - ret = zm_avcodec_decode_video( context, frame, &frameComplete, &packet ); - if ( ret < 0 ) { - av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); - Error( "Unable to decode frame at frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf ); - zm_av_packet_unref( &packet ); - continue; - } -#endif - } // end if it's the right stream - - zm_av_packet_unref( &packet ); - - } // end while ! frameComplete + if ( frame_number == -1 ) + break; + } // end while frame_number > streams.frame_count return frame; - } // end AVFrame *FFmpeg_Input::get_frame + + diff --git a/src/zm_ffmpeg_input.h b/src/zm_ffmpeg_input.h index 727fc110a..0fd9801f3 100644 --- a/src/zm_ffmpeg_input.h +++ b/src/zm_ffmpeg_input.h @@ -21,7 +21,7 @@ class FFmpeg_Input { int Open( const char *filename ); int Close(); - AVFrame *get_frame( int stream_id=-1 ); + AVFrame *get_frame( int stream_id=-1, int frame_number=-1 ); int get_video_stream_id() { return video_stream_id; } diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 4187cf9e3..6e1b55126 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1216,7 +1216,7 @@ bool Monitor::Analyse() { // if have event, sent frames until we find a video packet, at which point do analysis. Adaptive skip should only affect which frames we do analysis on. - int skip_index = 0; + unsigned int skip_index = 0; if ( adaptive_skip ) { int read_margin = shared_data->last_read_index - shared_data->last_write_index; @@ -1295,6 +1295,7 @@ bool Monitor::Analyse() { Debug(3, "Motion detection is enabled signal(%d) signal_change(%d)", signal, signal_change); + // if we have been told to be OFF, then we are off and don't do any processing. if ( trigger_data->trigger_state != TRIGGER_OFF ) { Debug(4, "Trigger not oFF state is (%d)", trigger_data->trigger_state ); unsigned int score = 0; @@ -1304,8 +1305,8 @@ Debug(4, "Ready"); std::string cause; Event::StringSetMap noteSetMap; + // Specifically told to be on. Setting the score here will trigger the alarm. if ( trigger_data->trigger_state == TRIGGER_ON ) { - score += trigger_data->trigger_score; if ( !event ) { if ( cause.length() ) @@ -1372,7 +1373,6 @@ Debug(3,"before DetectMotion"); // If we aren't recording, check linked monitors to see if we should be. if ( (!(signal_change && signal)) && (n_linked_monitors > 0) ) { - bool first_link = true; Event::StringSet noteSet; for ( int i=0; i < n_linked_monitors; i++ ) { if ( ! linked_monitors[i]->isConnected() ) @@ -1434,6 +1434,7 @@ Debug(3,"before DetectMotion"); } } // end if ! event } + if ( score ) { Debug(9, "Score: (%d)", score ); if ( (state == IDLE || state == TAPE || state == PREALARM ) ) { @@ -1488,7 +1489,7 @@ Debug(3, "creating new event"); if ( pre_event_images ) { Debug(2,"Have pre_event_image"); if ( analysis_fps ) { - Debug(2,"Have analysis_fps"); + Debug(2,"Have analysis_fps"); for ( int i = 0; i < pre_event_images; i++ ) { timestamps[i] = &pre_event_buffer[pre_index].timestamp; images[i] = pre_event_buffer[pre_index].image; @@ -1520,7 +1521,7 @@ Debug(3, "creating new event"); shared_data->state = state = ALARM; } last_alarm_count = image_count; - } else { + } else { // no score? if ( state == ALARM ) { Info( "%s: %03d - Gone into alert state", name, image_count ); shared_data->state = state = ALERT; @@ -1536,17 +1537,14 @@ Debug(3, "creating new event"); shared_data->state = state = TAPE; } } - } - if ( state == PREALARM ) { - if ( function != MOCORD ) { - shared_data->state = state = IDLE; - } else { - shared_data->state = state = TAPE; - } + } else if ( state == PREALARM ) { + // Back to IDLE + shared_data->state = state = function != MOCORD ? IDLE : TAPE; } if ( Event::PreAlarmCount() ) Event::EmptyPreAlarmFrames(); - } + } // end if score or not + if ( state != IDLE ) { if ( state == PREALARM || state == ALARM ) { if ( config.create_analysis_images ) { @@ -1565,6 +1563,7 @@ Debug(3, "creating new event"); } if ( got_anal_image ) { if ( state == PREALARM ) + // AddPreAlarmFrame just copies/buffers these frames in the event. If we go back to idle, we will drop them. Event::AddPreAlarmFrame( snap_image, *timestamp, score, &alarm_image ); else //event->AddFrame( snap_image, *timestamp, score, &alarm_image ); @@ -1593,23 +1592,17 @@ Debug(3, "creating new event"); if ( event && noteSetMap.size() > 0 ) event->updateNotes( noteSetMap ); } else if ( state == ALERT ) { - event->AddFrame( snap_image, *timestamp ); + // Alert means this frame has no motion, but we were alarmed and are still recording. + event->AddPacket( snap ); if ( noteSetMap.size() > 0 ) event->updateNotes( noteSetMap ); } else if ( state == TAPE ) { - //Video Storage: activate only for supported cameras. Event::AddFrame knows whether or not we are recording video and saves frames accordingly - //if((GetOptVideoWriter() == 2) && camera->SupportsNativeVideo()) { - // I don't think this is required, and causes problems, as the event file hasn't been setup yet. - //Warning("In state TAPE, - //video_store_data->recording = event->StartTime(); - //} + if ( !(image_count%(frame_skip+1)) ) { if ( config.bulk_frame_interval > 1 ) { - event->AddPacket( snap, (event->Frames()AddFrame( snap_image, *timestamp, (event->Frames()AddPacket( snap, (event->Frames()AddFrame( snap_image, *timestamp ); - event->AddPacket( snap ); + event->AddPacket( snap ); } } } diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 699ecdb4c..8ad87229b 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -285,7 +285,7 @@ protected: int ready_count; int first_alarm_count; int last_alarm_count; - static bool last_signal; + bool last_signal; int buffer_count; int prealarm_count; State state; @@ -294,7 +294,6 @@ protected: time_t last_analysis_fps_time; time_t auto_resume_time; unsigned int last_motion_score; - bool last_signal; EventCloseMode event_close_mode; diff --git a/src/zm_user.cpp b/src/zm_user.cpp index b6c9f9553..418a6fd8b 100644 --- a/src/zm_user.cpp +++ b/src/zm_user.cpp @@ -148,7 +148,7 @@ User *zmLoadAuthUser( const char *auth, bool use_remote_addr ) { } } - Debug( 1, "Attempting to authenticate user from auth string '%s'", auth ); + Debug( 1, "Attempting to authenticate user from auth string '%s', remote addr(%s)", auth, remote_addr ); char sql[ZM_SQL_SML_BUFSIZ] = ""; snprintf( sql, sizeof(sql), "SELECT Username, Password, Enabled, Stream+0, Events+0, Control+0, Monitors+0, System+0, MonitorIds FROM Users WHERE Enabled = 1" ); @@ -170,6 +170,17 @@ User *zmLoadAuthUser( const char *auth, bool use_remote_addr ) { return( 0 ); } + // getting the time is expensive, so only do it once. + time_t now = time( 0 ); + unsigned int hours = config.auth_hash_ttl; + + if ( ! hours ) { + Warning("No value set for ZM_AUTH_HASH_TTL. Defaulting to 2."); + hours = 2; + } else { + Debug( 1, "AUTH_HASH_TTL is %d, time is %d", hours, now ); + } + while( MYSQL_ROW dbrow = mysql_fetch_row( result ) ) { const char *user = dbrow[0]; const char *pass = dbrow[1]; @@ -179,18 +190,9 @@ User *zmLoadAuthUser( const char *auth, bool use_remote_addr ) { size_t md5len = 16; unsigned char md5sum[md5len]; - time_t now = time( 0 ); - unsigned int hours = config.auth_hash_ttl; - - if ( ! hours ) { - Warning("No value set for ZM_AUTH_HASH_TTL. Defaulting to 2."); - hours = 2; - } else { - Debug( 1, "AUTH_HASH_TTL is %d", hours ); - } - - for ( unsigned int i = 0; i < hours; i++, now -= 3600 ) { - struct tm *now_tm = localtime( &now ); + time_t now_copy = now; + for ( unsigned int i = 0; i < hours; i++, now_copy -= 3600 ) { + struct tm *now_tm = localtime(&now_copy); snprintf( auth_key, sizeof(auth_key), "%s%s%s%s%d%d%d%d", config.auth_hash_secret, @@ -221,11 +223,10 @@ User *zmLoadAuthUser( const char *auth, bool use_remote_addr ) { Debug(1, "Authenticated user '%s'", user->getUsername() ); mysql_free_result( result ); return( user ); - } else { - Debug(1, "No match for %s", auth ); } - } - } + } // end foreach hours + } // end foreach user + Debug(1, "No match for %s", auth ); mysql_free_result( result ); #else // HAVE_DECL_MD5 Error( "You need to build with gnutls or openssl installed to use hash based authentication" ); diff --git a/web/includes/functions.php b/web/includes/functions.php index 2d0b9c681..128b565d6 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -28,13 +28,13 @@ if ( version_compare( phpversion(), '4.3.0', '<') ) { } # We are requiring these because this file is getting included from the api, which hasn't already included them. -require_once( 'logger.php' ); -require_once( 'database.php' ); +require_once('logger.php'); +require_once('database.php'); function userLogin( $username, $password='', $passwordHashed=false ) { global $user, $cookies; - $sql = 'SELECT * FROM Users WHERE Enabled = 1'; + $sql = 'SELECT * FROM Users WHERE Enabled=1'; $sql_values = NULL; if ( ZM_AUTH_TYPE == 'builtin' ) { if ( $passwordHashed ) { @@ -44,7 +44,7 @@ function userLogin( $username, $password='', $passwordHashed=false ) { } $sql_values = array( $username, $password ); } else { - $sql .= ' AND Username = ?'; + $sql .= ' AND Username=?'; $sql_values = array( $username ); } $_SESSION['username'] = $username; @@ -138,26 +138,27 @@ function getAuthUser( $auth ) { $authHash = md5( $authKey ); if ( $auth == $authHash ) { - return( $user ); + return $user; } } // end foreach hour } // end foreach user } // end if using auth hash Error( "Unable to authenticate user from auth hash '$auth'" ); return( false ); -} +} // end getAuthUser($auth) function generateAuthHash( $useRemoteAddr ) { if ( ZM_OPT_USE_AUTH and ZM_AUTH_RELAY == 'hashed' and isset($_SESSION['username']) and $_SESSION['passwordHash'] ) { # regenerate a hash at half the liftetime of a hash, an hour is 3600 so half is 1800 - if ( ( ! isset($_SESSION['AuthHash']) ) or ( $_SESSION['AuthHashGeneratedAt'] < time() - ( ZM_AUTH_HASH_TTL * 1800 ) ) ) { + $time = time(); + if ( ( ! isset($_SESSION['AuthHash']) ) or ( $_SESSION['AuthHashGeneratedAt'] < ( $time - ( ZM_AUTH_HASH_TTL * 1800 ) ) ) ) { # Don't both regenerating Auth Hash if an hour hasn't gone by yet - $time = localtime(); + $local_time = localtime(); $authKey = ''; if ( $useRemoteAddr ) { - $authKey = ZM_AUTH_HASH_SECRET.$_SESSION['username'].$_SESSION['passwordHash'].$_SESSION['remoteAddr'].$time[2].$time[3].$time[4].$time[5]; + $authKey = ZM_AUTH_HASH_SECRET.$_SESSION['username'].$_SESSION['passwordHash'].$_SESSION['remoteAddr'].$local_time[2].$local_time[3].$local_time[4].$local_time[5]; } else { - $authKey = ZM_AUTH_HASH_SECRET.$_SESSION['username'].$_SESSION['passwordHash'].$time[2].$time[3].$time[4].$time[5]; + $authKey = ZM_AUTH_HASH_SECRET.$_SESSION['username'].$_SESSION['passwordHash'].$local_time[2].$local_time[3].$local_time[4].$local_time[5]; } $auth = md5( $authKey ); if ( session_status() == PHP_SESSION_NONE ) { @@ -167,10 +168,10 @@ function generateAuthHash( $useRemoteAddr ) { Warning("Session is not active. AuthHash will not be cached. called from $file:$line"); } $_SESSION['AuthHash'] = $auth; - $_SESSION['AuthHashGeneratedAt'] = time(); + $_SESSION['AuthHashGeneratedAt'] = $time; Logger::Debug("Generated new auth $auth at " . $_SESSION['AuthHashGeneratedAt']. " using $authKey" ); } else { - Logger::Debug( "Using cached auth " . $_SESSION['AuthHash'] ); + Logger::Debug( "Using cached auth " . $_SESSION['AuthHash'] ." beacuse " . $_SESSION['AuthHashGeneratedAt'] . ' < '. $time . ' - ' . ZM_AUTH_HASH_TTL . ' * 1800 = '.( $time - (ZM_AUTH_HASH_TTL * 1800) )); } # end if AuthHash is not cached return $_SESSION['AuthHash']; } else { From 24a0d717c552ff853a93676895b8ac51a60cb570 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 21 Nov 2017 19:55:40 -0500 Subject: [PATCH 0049/2339] wip --- src/zm_event.cpp | 2 +- src/zm_event.h | 2 +- src/zm_ffmpeg.cpp | 11 +- src/zm_ffmpeg_camera.cpp | 2 +- src/zm_monitor.cpp | 861 ++++++++++++++++----------------------- src/zm_monitor.h | 29 +- src/zm_monitorstream.cpp | 19 +- src/zm_packet.cpp | 60 +-- src/zm_packet.h | 10 +- src/zm_packetqueue.cpp | 11 +- src/zm_packetqueue.h | 3 +- src/zm_remote_camera.h | 3 +- src/zm_videostore.cpp | 8 +- 13 files changed, 422 insertions(+), 599 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 8de834ccf..ee5f82d76 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -435,7 +435,7 @@ void Event::AddPacket( ZMPacket *packet, int score, Image *alarm_image ) { //FIXME if it fails, we should write a jpeg } if ( packet->codec_type == AVMEDIA_TYPE_VIDEO ) { - AddFrame( packet->image, packet->timestamp, score, alarm_image ); + AddFrame( packet->image, *packet->timestamp, score, alarm_image ); } // end if is video return; } diff --git a/src/zm_event.h b/src/zm_event.h index 04d758e55..3782172a7 100644 --- a/src/zm_event.h +++ b/src/zm_event.h @@ -86,7 +86,7 @@ class Event { unsigned int max_score; char path[PATH_MAX]; VideoStore *videoStore; - char video_name[PATH_MAX]; + char video_name[64]; char video_file[PATH_MAX]; int last_db_frame; bool have_video_keyframe; // a flag to tell us if we have had a video keyframe when writing an mp4. The first frame SHOULD be a video keyframe. diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index fe710ab87..3c9d969b5 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -266,13 +266,18 @@ void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output) Debug(1, ", frames:%d, timebase: %d/%d", st->codec_info_nb_frames, st->time_base.num, st->time_base.den); avcodec_string(buf, sizeof(buf), st->codec, is_output); Debug(1, ": %s", buf); +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + AVCodecParameters *codec = st->codecpar; +#else + AVCodecContext *codec = st->codec; +#endif if (st->sample_aspect_ratio.num && // default - av_cmp_q(st->sample_aspect_ratio, st->codec->sample_aspect_ratio)) { + av_cmp_q(st->sample_aspect_ratio, 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, + codec->width * (int64_t)st->sample_aspect_ratio.num, + 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, diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 7a90fbf63..f8b6d6241 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -438,7 +438,7 @@ int FfmpegCamera::OpenFfmpeg() { mCanCapture = true; - return 0; + return 1; } // int FfmpegCamera::OpenFfmpeg() int FfmpegCamera::ReopenFfmpeg() { diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index c3aefdba0..b9710ed3b 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -260,7 +260,7 @@ Monitor::Monitor( int p_section_length, int p_frame_skip, int p_motion_frame_skip, - double p_analysis_fps, + double p_analysis_fps_limit, unsigned int p_analysis_update_delay, int p_capture_delay, int p_alarm_capture_delay, @@ -299,7 +299,7 @@ Monitor::Monitor( section_length( p_section_length ), frame_skip( p_frame_skip ), motion_frame_skip( p_motion_frame_skip ), - analysis_fps( p_analysis_fps ), + analysis_fps_limit( p_analysis_fps_limit ), analysis_update_delay( p_analysis_update_delay ), capture_delay( p_capture_delay ), alarm_capture_delay( p_alarm_capture_delay ), @@ -342,51 +342,9 @@ Monitor::Monitor( /* Parse encoder parameters */ ParseEncoderParameters(encoderparams.c_str(), &encoderparamsvec); -#if HAVE_LIBSWSCALE - mConvertContext = NULL; -#endif - /* Has to be located inside the constructor so other components such as zma will receive correct colours and subpixel order */ - if ( colours == ZM_COLOUR_RGB32 ) { - subpixelorder = ZM_SUBPIX_ORDER_RGBA; - imagePixFormat = AV_PIX_FMT_RGBA; - } else if ( colours == ZM_COLOUR_RGB24 ) { - subpixelorder = ZM_SUBPIX_ORDER_RGB; - imagePixFormat = AV_PIX_FMT_RGB24; - } else if ( colours == ZM_COLOUR_GRAY8 ) { - subpixelorder = ZM_SUBPIX_ORDER_NONE; - imagePixFormat = AV_PIX_FMT_GRAY8; - } else { - Panic("Unexpected colours: %d",colours); - } -#if HAVE_LIBSWSCALE -//FIXME, need to be able to query the camera input for what it is going to be getting, which needs to be called after the camera is open. - //Debug ( 1, "Calling sws_isSupportedInput" ); - //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)); - } - - // We don't know this yet, need to open the camera first. - //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 ); - //} - - fps = 0.0; + capture_fps = 0.0; + analysis_fps = 0.0; event_count = 0; image_count = 0; analysis_image_count = 0; @@ -414,6 +372,7 @@ Monitor::Monitor( mem_size = sizeof(SharedData) + sizeof(TriggerData) + sizeof(VideoStoreData) //Information to pass back to the capture process + + (image_buffer_count*sizeof(struct timeval)) + (image_buffer_count*camera->ImageSize()) + 64; /* Padding used to permit aligning the images buffer to 64 byte boundary */ @@ -573,7 +532,10 @@ bool Monitor::connect() { shared_data = (SharedData *)mem_ptr; trigger_data = (TriggerData *)((char *)shared_data + sizeof(SharedData)); video_store_data = (VideoStoreData *)((char *)trigger_data + sizeof(TriggerData)); - unsigned char *shared_images = (unsigned char *)((char *)video_store_data + sizeof(VideoStoreData)); + shared_timestamps = (struct timeval *)((char *)video_store_data + sizeof(VideoStoreData)); + shared_images = (unsigned char *)((char *)shared_timestamps + (image_buffer_count*sizeof(struct timeval))); + + analysis_it = packetqueue.pktQueue.begin(); if ( ((unsigned long)shared_images % 64) != 0 ) { /* Align images buffer to nearest 64 byte boundary */ @@ -584,6 +546,8 @@ bool Monitor::connect() { Debug(3, "Allocating %d image buffers", image_buffer_count ); image_buffer = new ZMPacket[image_buffer_count]; for ( int i = 0; i < image_buffer_count; i++ ) { + image_buffer[i].image_index = i; + image_buffer[i].timestamp = &(shared_timestamps[i]); image_buffer[i].image = new Image( width, height, camera->Colours(), camera->SubpixelOrder(), &(shared_images[i*camera->ImageSize()]) ); image_buffer[i].image->HoldBuffer(true); /* Don't release the internal buffer or replace it with another */ } @@ -593,21 +557,7 @@ bool Monitor::connect() { next_buffer.image = new Image( width, height, camera->Colours(), camera->SubpixelOrder()); } pre_event_buffer_count = pre_event_count + alarm_frame_count - 1; - //if ( ( purpose == ANALYSIS ) && analysis_fps ) { - // Size of pre event buffer must be greater than pre_event_count - // if alarm_frame_count > 1, because in this case the buffer contains - // alarmed images that must be discarded when event is created - // Couldn't we just make sure there is always enough frames in the ring buffer? - if ( purpose == ANALYSIS ) { - if ( analysis_fps ) { - pre_event_buffer_count = pre_event_count + alarm_frame_count - 1; - pre_event_buffer = new ZMPacket[pre_event_buffer_count]; - for ( int i = 0; i < pre_event_buffer_count; i++ ) { - pre_event_buffer[i].image = new Image( width, height, camera->Colours(), camera->SubpixelOrder()); - } - } - } Debug(3, "Success connecting"); return true; } // Monitor::connect @@ -644,9 +594,11 @@ Monitor::~Monitor() { if ( (deinterlacing & 0xff) == 4) { delete next_buffer.image; } +#if 0 for ( int i = 0; i < image_buffer_count; i++ ) { - delete image_buffer[i].image; + delete image_buffer[i]; } +#endif delete[] image_buffer; if ( purpose == ANALYSIS ) { @@ -654,13 +606,6 @@ Monitor::~Monitor() { // I think we set it to the count so that it is technically 1 behind capture, which starts at 0 shared_data->last_read_index = image_buffer_count; shared_data->last_read_time = 0; - - if ( analysis_fps ) { - for ( int i = 0; i < pre_event_buffer_count; i++ ) { - delete pre_event_buffer[i].image; - } - delete[] pre_event_buffer; - } } else if ( purpose == CAPTURE ) { shared_data->valid = false; memset( mem_ptr, 0, mem_size ); @@ -759,7 +704,7 @@ Debug(3, "GetImage"); } if ( !config.timestamp_on_capture ) { - TimestampImage( &alarm_image, &snap->timestamp ); + TimestampImage( &alarm_image, snap->timestamp ); } image = &alarm_image; } else { @@ -775,20 +720,28 @@ Debug(3, "GetImage"); return( 0 ); } -struct timeval Monitor::GetTimestamp( int index ) const { +ZMPacket *Monitor::getSnapshot( int index ) { + if ( index < 0 || index > image_buffer_count ) { index = shared_data->last_write_index; } + return &image_buffer[index]; - if ( index != image_buffer_count ) { - ZMPacket *snap = &image_buffer[index]; - - return snap->timestamp; - } else { - static struct timeval null_tv = { 0, 0 }; - - return null_tv; + for ( std::list::iterator it = packetqueue.pktQueue.begin(); it != packetqueue.pktQueue.end(); ++it ) { + ZMPacket *zm_packet = *it; + if ( zm_packet->image_index == index ) + return zm_packet; } + return NULL; +} + +struct timeval Monitor::GetTimestamp( int index ) { + ZMPacket *packet = getSnapshot( index ); + if ( packet ) + return *packet->timestamp; + + static struct timeval null_tv = { 0, 0 }; + return null_tv; } unsigned int Monitor::GetLastReadIndex() const { @@ -809,10 +762,10 @@ double Monitor::GetFPS() const { return 0.0; } ZMPacket *snap1 = &image_buffer[index1]; - if ( !snap1->timestamp.tv_sec ) { + if ( !snap1->timestamp->tv_sec ) { return 0.0; } - struct timeval time1 = snap1->timestamp; + struct timeval time1 = *snap1->timestamp; int image_count = image_buffer_count; @@ -820,16 +773,16 @@ double Monitor::GetFPS() const { if ( index2 == image_buffer_count ) { return 0.0; } - ZMPacket *snap2 = &image_buffer[index2]; - while ( !snap2->timestamp.tv_sec ) { + ZMPacket *snap2 = &image_buffer[ index2 ]; + while ( !snap2->timestamp->tv_sec ) { if ( index1 == index2 ) { return 0.0; } index2 = (index2+1)%image_buffer_count; - snap2 = &image_buffer[index2]; + snap2 = &image_buffer[ index2 ]; image_count--; } - struct timeval time2 = snap2->timestamp; + struct timeval time2 = *snap2->timestamp; double time_diff = tvDiffSec( time2, time1 ); if ( ! time_diff ) { @@ -845,14 +798,14 @@ double Monitor::GetFPS() const { } useconds_t Monitor::GetAnalysisRate() { - double capturing_fps = GetFPS(); - if ( !analysis_fps ) { + capture_fps = GetFPS(); + if ( !analysis_fps_limit ) { return( 0 ); - } else if ( analysis_fps > capturing_fps ) { - Warning( "Analysis fps (%.2f) is greater than capturing fps (%.2f)", analysis_fps, capturing_fps ); + } else if ( analysis_fps_limit > capture_fps ) { + Warning( "Analysis fps (%.2f) is greater than capturing fps (%.2f)", analysis_fps_limit, capture_fps ); return( 0 ); } else { - return( ( 1000000 / analysis_fps ) - ( 1000000 / capturing_fps ) ); + return( ( 1000000 / analysis_fps_limit ) - ( 1000000 / capture_fps ) ); } } @@ -894,7 +847,7 @@ void Monitor::actionEnable() { shared_data->action |= RELOAD; static char sql[ZM_SQL_SML_BUFSIZ]; - snprintf( sql, sizeof(sql), "update Monitors set Enabled = 1 where Id = '%d'", id ); + snprintf( sql, sizeof(sql), "update Monitors set Enabled = 1 where Id='%d'", id ); if ( mysql_query( &dbconn, sql ) ) { Error( "Can't run query: %s", mysql_error( &dbconn ) ); exit( mysql_errno( &dbconn ) ); @@ -905,7 +858,7 @@ void Monitor::actionDisable() { shared_data->action |= RELOAD; static char sql[ZM_SQL_SML_BUFSIZ]; - snprintf( sql, sizeof(sql), "update Monitors set Enabled = 0 where Id = '%d'", id ); + snprintf( sql, sizeof(sql), "update Monitors set Enabled = 0 where Id='%d'", id ); if ( mysql_query( &dbconn, sql ) ) { Error( "Can't run query: %s", mysql_error( &dbconn ) ); exit( mysql_errno( &dbconn ) ); @@ -1059,7 +1012,7 @@ void Monitor::DumpZoneImage( const char *zone_string ) { if ( ( (!staticConfig.SERVER_ID) || ( staticConfig.SERVER_ID == server_id ) ) && mem_ptr ) { Debug(3, "Trying to load from local zmc"); int index = shared_data->last_write_index; - ZMPacket *snap = &image_buffer[index]; + ZMPacket *snap = getSnapshot(index); zone_image = new Image( *snap->image ); } else { Debug(3, "Trying to load from event"); @@ -1200,6 +1153,9 @@ bool Monitor::CheckSignal( const Image *image ) { } void Monitor::CheckAction() { + struct timeval now; + gettimeofday( &now, NULL ); + if ( shared_data->action ) { // Can there be more than 1 bit set in the action? Shouldn't these be elseifs? if ( shared_data->action & RELOAD ) { @@ -1216,8 +1172,6 @@ void Monitor::CheckAction() { Info( "Received suspend indication at count %d, but wasn't active", image_count ); } if ( config.max_suspend_time ) { - struct timeval now; - gettimeofday( &now, NULL ); auto_resume_time = now.tv_sec + config.max_suspend_time; } shared_data->action &= ~SUSPEND; @@ -1232,448 +1186,315 @@ void Monitor::CheckAction() { shared_data->action &= ~RESUME; } } // end if shared_data->action + + if ( auto_resume_time && (now.tv_sec >= auto_resume_time) ) { + Info( "Auto resuming at count %d", image_count ); + shared_data->active = true; + ref_image = *(image_buffer[shared_data->last_write_index].image); + ready_count = image_count+(warmup_count/2); + auto_resume_time = 0; + } +} + +void Monitor::UpdateAnalysisFPS() { + struct timeval now; + gettimeofday( &now, NULL ); + if ( analysis_image_count && fps_report_interval && !(analysis_image_count%fps_report_interval) ) { + analysis_fps = double(fps_report_interval)/(now.tv_sec - last_analysis_fps_time); + Info( "%s: %d - Analysing at %.2f fps", name, image_count, analysis_fps ); + static char sql[ZM_SQL_SML_BUFSIZ]; + snprintf( sql, sizeof(sql), "UPDATE Monitors SET AnalysisFPS = '%.2lf' WHERE Id = '%d'", analysis_fps, id ); + if ( mysql_query( &dbconn, sql ) ) { + Error( "Can't run query: %s", mysql_error( &dbconn ) ); + } + last_analysis_fps_time = now.tv_sec; + } } // Would be nice if this JUST did analysis +// This idea is that we should be analysing as close to the capture frame as possible. +// This function should process as much as possible before returning +// +// If there is an event, the we should do our best to empty the queue. +// If there isn't then we keep pre-event + alarm frames. = pre_event_count bool Monitor::Analyse() { // last_write_index is the last capture // last_read_index is the last analysis - if ( ! packetqueue.size() ) { - Debug(2, "Nothing in packetqueue"); - return false; - } if ( ! Enabled() ) { Warning("SHouldn't be doing Analyze when not Enabled"); return false; } - mutex.lock(); - struct timeval now; gettimeofday( &now, NULL ); - - if ( analysis_image_count && fps_report_interval && !(analysis_image_count%fps_report_interval) ) { - fps = double(fps_report_interval)/(now.tv_sec - last_analysis_fps_time); - Info( "%s: %d - Analysing at %.2f fps", name, image_count, fps ); - static char sql[ZM_SQL_SML_BUFSIZ]; - snprintf( sql, sizeof(sql), "UPDATE Monitors SET AnalysisFPS = '%.2lf' WHERE Id = '%d'", fps, id ); - if ( mysql_query( &dbconn, sql ) ) { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); - } - last_analysis_fps_time = now.tv_sec; - } + mutex.lock(); // if have event, sent frames until we find a video packet, at which point do analysis. Adaptive skip should only affect which frames we do analysis on. - unsigned int skip_index = 0; - - if ( adaptive_skip ) { - int read_margin = shared_data->last_read_index - shared_data->last_write_index; - if ( read_margin < 0 ) read_margin += image_buffer_count; - - int step = 1; - // Isn't read_margin always > 0 here? Yes because it can only happen when last_read_index == last_write_index - // Which happens when we are analysing faster than capture. We test for this above - // - if ( read_margin > 0 ) { - // TODO explain this so... 90% of image buffer / 50% of read margin? - step = (9*image_buffer_count)/(5*read_margin); - } - - int pending_frames = shared_data->last_write_index - shared_data->last_read_index; - if ( pending_frames < 0 ) pending_frames += image_buffer_count; - - Debug( 4, "ReadIndex:%d, WriteIndex: %d, PendingFrames = %d, ReadMargin = %d, Step = %d", - shared_data->last_read_index, shared_data->last_write_index, pending_frames, read_margin, step ); - if ( step <= pending_frames ) { - skip_index = (shared_data->last_read_index+step)%image_buffer_count; - } else { - if ( pending_frames ) { - Warning( "Approaching buffer overrun, consider slowing capture, simplifying analysis or increasing ring buffer size" ); - } - skip_index = shared_data->last_write_index%image_buffer_count; - } - } else { - // last-write_index is the last frame captured - skip_index = shared_data->last_write_index%image_buffer_count; + // Keeps minimum video frames. This should be ok, because we SHOULD be staying close to the head of the queue in analysis + if ( ! event ) { + if ( packetqueue.video_packet_count > pre_event_count ) + packetqueue.clearQueue( pre_event_count, video_stream_id ); } - // process audio packets, writing them if there is an event. - ZMPacket *queued_packet; - while ( packetqueue.size() ) { - if ( ( queued_packet = packetqueue.popPacket() ) ) { - if ( queued_packet->packet.stream_index == video_stream_id ) { - break; - } - if ( event ) { - event->AddPacket( queued_packet ); - } - delete queued_packet; - queued_packet = NULL; - } - } - - if ( ! queued_packet ) { - shared_data->last_read_time = now.tv_sec; - mutex.unlock(); - return false; - } - - //Debug(2, "timestamp for index (%d) %s", index, timeval_to_string( *timestamp ) ); - ZMPacket *snap = queued_packet; - struct timeval *timestamp = &snap->timestamp; - Image *snap_image = snap->image; - - if ( auto_resume_time && (now.tv_sec >= auto_resume_time) ) { - Info( "Auto resuming at count %d", image_count ); - shared_data->active = true; - ref_image = *snap_image; - ready_count = image_count+(warmup_count/2); - auto_resume_time = 0; - } - - int last_section_mod = 0; - - bool signal = shared_data->signal; - bool signal_change = (signal != last_signal); - - Debug(3, "Motion detection is enabled signal(%d) signal_change(%d)", signal, signal_change); + // If do have an event, then analysis_it should point to the head of the queue, because we would have emptied it on event creation. - // if we have been told to be OFF, then we are off and don't do any processing. - if ( trigger_data->trigger_state != TRIGGER_OFF ) { -Debug(4, "Trigger not oFF state is (%d)", trigger_data->trigger_state ); - unsigned int score = 0; - // Ready means that we have captured the warmpup # of frames - if ( Ready() ) { -Debug(4, "Ready"); - std::string cause; - Event::StringSetMap noteSetMap; + // Move to next packet. + while ( analysis_it != packetqueue.pktQueue.end() ) { + ++analysis_it; - // Specifically told to be on. Setting the score here will trigger the alarm. - if ( trigger_data->trigger_state == TRIGGER_ON ) { - score += trigger_data->trigger_score; - if ( !event ) { - if ( cause.length() ) - cause += ", "; - cause += trigger_data->trigger_cause; - } - Event::StringSet noteSet; - noteSet.insert( trigger_data->trigger_text ); - noteSetMap[trigger_data->trigger_cause] = noteSet; - } - if ( signal_change ) { - const char *signalText; - if ( !signal ) { - signalText = "Lost"; - } else { - signalText = "Reacquired"; - score += 100; - } - Warning( "%s: %s", SIGNAL_CAUSE, signalText ); - if ( event && !signal ) { - Info( "%s: %03d - Closing event %d, signal loss", name, image_count, event->Id() ); - closeEvent(); - last_section_mod = 0; - } - if ( !event ) { - if ( cause.length() ) - cause += ", "; - cause += SIGNAL_CAUSE; - } - Event::StringSet noteSet; - noteSet.insert( signalText ); - noteSetMap[SIGNAL_CAUSE] = noteSet; - shared_data->state = state = IDLE; - shared_data->active = signal; - ref_image = *snap_image; + ZMPacket *snap = *analysis_it; + struct timeval *timestamp = snap->timestamp; + Image *snap_image = snap->image; - } else if ( signal && Active() && (function == MODECT || function == MOCORD) ) { -Debug(3, "signal and active and modtect"); - Event::StringSet zoneSet; - int motion_score = last_motion_score; - if ( !(image_count % (motion_frame_skip+1) ) ) { - // Get new score. -Debug(3,"before DetectMotion"); - motion_score = DetectMotion( *snap_image, zoneSet ); + int last_section_mod = 0; - Debug( 3, "After motion detection, last_motion_score(%d), new motion score(%d)", last_motion_score, motion_score ); - // Why are we updating the last_motion_score too? - last_motion_score = motion_score; - } - //int motion_score = DetectBlack( *snap_image, zoneSet ); - if ( motion_score ) { + // signal is set by capture + bool signal = shared_data->signal; + bool signal_change = (signal != last_signal); + Debug(3, "Motion detection is enabled signal(%d) signal_change(%d)", signal, signal_change); + + // if we have been told to be OFF, then we are off and don't do any processing. + if ( trigger_data->trigger_state != TRIGGER_OFF ) { + Debug(4, "Trigger not oFF state is (%d)", trigger_data->trigger_state ); + unsigned int score = 0; + // Ready means that we have captured the warmpup # of frames + if ( Ready() ) { + Debug(4, "Ready"); + std::string cause; + Event::StringSetMap noteSetMap; + + // Specifically told to be on. Setting the score here will trigger the alarm. + if ( trigger_data->trigger_state == TRIGGER_ON ) { + score += trigger_data->trigger_score; if ( !event ) { - score += motion_score; if ( cause.length() ) cause += ", "; - cause += MOTION_CAUSE; - } else { - score += motion_score; + cause += trigger_data->trigger_cause; } - noteSetMap[MOTION_CAUSE] = zoneSet; - } // end if motion_score - shared_data->active = signal; - } // end if signal change + Event::StringSet noteSet; + noteSet.insert( trigger_data->trigger_text ); + noteSetMap[trigger_data->trigger_cause] = noteSet; + } // end if trigger_on - // If we aren't recording, check linked monitors to see if we should be. - if ( (!(signal_change && signal)) && (n_linked_monitors > 0) ) { - Event::StringSet noteSet; - for ( int i=0; i < n_linked_monitors; i++ ) { - if ( ! linked_monitors[i]->isConnected() ) - linked_monitors[i]->connect(); + if ( signal_change ) { + const char *signalText; + if ( !signal ) { + signalText = "Lost"; + if ( event ) { + Info( "%s: %03d - Closing event %d, signal loss", name, image_count, event->Id() ); + closeEvent(); + last_section_mod = 0; + } + } else { + signalText = "Reacquired"; + score += 100; + } + Warning( "%s: %s", SIGNAL_CAUSE, signalText ); + if ( !event ) { + if ( cause.length() ) + cause += ", "; + cause += SIGNAL_CAUSE; + } + Event::StringSet noteSet; + noteSet.insert( signalText ); + noteSetMap[SIGNAL_CAUSE] = noteSet; + shared_data->state = state = IDLE; + shared_data->active = signal; + ref_image = *snap_image; - if ( linked_monitors[i]->isConnected() && linked_monitors[i]->hasAlarmed() ) { - if ( !event ) { + } else if ( signal ) { + if ( Active() && (function == MODECT || function == MOCORD) ) { + Debug(3, "signal and active and modect"); + Event::StringSet zoneSet; + int motion_score = last_motion_score; + if ( !(analysis_image_count % (motion_frame_skip+1) ) ) { + // Get new score. + Debug(3,"before DetectMotion"); + motion_score = DetectMotion( *snap_image, zoneSet ); + + Debug( 3, "After motion detection, last_motion_score(%d), new motion score(%d)", last_motion_score, motion_score ); + // Why are we updating the last_motion_score too? + last_motion_score = motion_score; + } + if ( motion_score ) { + score += motion_score; + if ( !event ) { if ( cause.length() ) cause += ", "; - cause += LINKED_CAUSE; - } - noteSet.insert( linked_monitors[i]->Name() ); - score += 50; + cause += MOTION_CAUSE; + } + noteSetMap[MOTION_CAUSE] = zoneSet; + } // end if motion_score + shared_data->active = signal; } - } - if ( noteSet.size() > 0 ) - noteSetMap[LINKED_CAUSE] = noteSet; - } - - if ( (!signal_change && signal) && (function == RECORD || function == MOCORD) ) { - if ( event ) { - if ( section_length ) { - // TODO: Wouldn't this be clearer if we just did something like if now - event->start > section_length ? - int section_mod = timestamp->tv_sec % section_length; - Debug( 3, "Section length (%d) Last Section Mod(%d), new section mod(%d)", section_length, last_section_mod, section_mod ); - // This is not clear, but basically due to pauses, etc we might not get section_mod == 0 - if ( section_mod < last_section_mod ) { - //if ( state == IDLE || state == TAPE || event_close_mode == CLOSE_TIME ) { - //if ( state == TAPE ) { - //shared_data->state = state = IDLE; - //Info( "%s: %03d - Closing event %d, section end", name, image_count, event->Id() ) - //} else { + + // If we aren't recording, check linked monitors to see if we should be. + if ( n_linked_monitors > 0 ) { + Event::StringSet noteSet; + for ( int i=0; i < n_linked_monitors; i++ ) { + if ( ! linked_monitors[i]->isConnected() ) + linked_monitors[i]->connect(); + + if ( linked_monitors[i]->isConnected() && linked_monitors[i]->hasAlarmed() ) { + if ( !event ) { + if ( cause.length() ) + cause += ", "; + cause += LINKED_CAUSE; + } + noteSet.insert( linked_monitors[i]->Name() ); + score += 50; + } + } // end foreach linked_monitor + if ( noteSet.size() > 0 ) + noteSetMap[LINKED_CAUSE] = noteSet; + } // end if linked_monitors + + if ( function == RECORD || function == MOCORD ) { + // If doing record, check to see if we need to close the event or not. + + if ( event ) { + if ( section_length ) { + // TODO: Wouldn't this be clearer if we just did something like if now - event->start > section_length ? + int section_mod = timestamp->tv_sec % section_length; + Debug( 3, "Section length (%d) Last Section Mod(%d), new section mod(%d)", section_length, last_section_mod, section_mod ); + // This is not clear, but basically due to pauses, etc we might not get section_mod == 0 + if ( section_mod < last_section_mod ) { Info( "%s: %03d - Closing event %d, section end forced ", name, image_count, event->Id() ); - //} - closeEvent(); - last_section_mod = 0; - //} else { - //Debug( 2, "Time to close event, but state (%d) is not IDLE or TAPE and event_close_mode is not CLOSE_TIME (%d)", state, event_close_mode ); - //} - } else { - last_section_mod = section_mod; - } - } // end if section_length - } // end if event - - if ( ! event ) { - // Create event - event = new Event( this, *timestamp, "Continuous", noteSetMap ); - shared_data->last_event_id = event->Id(); - video_store_data->recording = event->StartTime(); - - Info( "%s: %03d - Opening new event %d, section start", name, image_count, event->Id() ); - - /* To prevent cancelling out an existing alert\prealarm\alarm state */ - if ( state == IDLE ) { - shared_data->state = state = TAPE; - } - } // end if ! event - } - - if ( score ) { -Debug(9, "Score: (%d)", score ); - if ( (state == IDLE || state == TAPE || state == PREALARM ) ) { - if ( Event::PreAlarmCount() >= (alarm_frame_count-1) ) { - Info( "%s: %03d - Gone into alarm state", name, image_count ); - shared_data->state = state = ALARM; - if ( signal_change || (function != MOCORD && state != ALERT) ) { - int pre_index; - int pre_event_images = pre_event_count; - - if ( analysis_fps ) { - // If analysis fps is set, - // compute the index for pre event images in the dedicated buffer - pre_index = image_count % pre_event_buffer_count; -Debug(3, "Pre Index = (%d) = image_count(%d) %% pre_event_buffer_count (%d)", pre_index, image_count, pre_event_buffer_count ); - - // Seek forward the next filled slot in to the buffer (oldest data) - // from the current position - // ICON: I think this is supposed to handle when we havn't recorded enough images. - while ( pre_event_images && !pre_event_buffer[pre_index].timestamp.tv_sec ) { - pre_index = (pre_index + 1)%pre_event_buffer_count; - // Slot is empty, removing image from counter - pre_event_images--; - } -Debug(3, "creating new event"); - event = new Event( this, pre_event_buffer[pre_index].timestamp, cause, noteSetMap ); - } else { - // If analysis fps is not set (analysis performed at capturing framerate), - // compute the index for pre event images in the capturing buffer - if ( alarm_frame_count > 1 ) - pre_index = ((index + image_buffer_count) - ((alarm_frame_count - 1) + pre_event_count))%image_buffer_count; - else - pre_index = ((index + image_buffer_count) - pre_event_count)%image_buffer_count; - - // Seek forward the next filled slot in to the buffer (oldest data) - // from the current position - while ( pre_event_images && !image_buffer[pre_index].timestamp.tv_sec ) { - pre_index = (pre_index + 1)%image_buffer_count; - // Slot is empty, removing image from counter - pre_event_images--; - } - - event = new Event( this, image_buffer[pre_index].timestamp, cause, noteSetMap ); - } - shared_data->last_event_id = event->Id(); - //set up video store data - snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "%s", event->getEventFile()); - video_store_data->recording = event->StartTime(); - - Info( "%s: %03d - Opening new event %d, alarm start", name, image_count, event->Id() ); - - if ( pre_event_images ) { - Debug(2,"Have pre_event_image"); - if ( analysis_fps ) { - Debug(2,"Have analysis_fps"); - for ( int i = 0; i < pre_event_images; i++ ) { - timestamps[i] = &pre_event_buffer[pre_index].timestamp; - images[i] = pre_event_buffer[pre_index].image; - pre_index = (pre_index + 1)%pre_event_buffer_count; - } + closeEvent(); + last_section_mod = 0; } else { - for ( int i = 0; i < pre_event_images; i++ ) { - event->AddPacket( &image_buffer[pre_index] ); -#if 0 - timestamps[i] = &image_buffer[pre_index].timestamp; - images[i] = image_buffer[pre_index].image; -#endif - pre_index = (pre_index + 1)%image_buffer_count; + last_section_mod = section_mod; + } + } // end if section_length + } // end if event + + if ( ! event ) { + // Create event + event = new Event( this, *timestamp, "Continuous", noteSetMap ); + shared_data->last_event_id = event->Id(); + video_store_data->recording = event->StartTime(); + Info( "%s: %03d - Opening new event %d, section start", name, image_count, event->Id() ); + /* To prevent cancelling out an existing alert\prealarm\alarm state */ + if ( state == IDLE ) { + shared_data->state = state = TAPE; + } + } // end if ! event + } // end if RECORDING + + if ( score ) { + Debug(9, "Score: (%d)", score ); + if ( (state == IDLE || state == TAPE || state == PREALARM ) ) { + if ( Event::PreAlarmCount() >= (alarm_frame_count-1) ) { + Info( "%s: %03d - Gone into alarm state", name, image_count ); + shared_data->state = state = ALARM; + if ( (function != MOCORD && state != ALERT) ) { + event = new Event( this, *timestamp, cause, noteSetMap ); + shared_data->last_event_id = event->Id(); + ZMPacket *queued_packet = packetqueue.popPacket(); + do { + event->AddPacket( queued_packet ); + } while ( queued_packet != *analysis_it ); + } + } else if ( state != PREALARM ) { + Info( "%s: %03d - Gone into prealarm state", name, image_count ); + shared_data->state = state = PREALARM; + } + } else if ( state == ALERT ) { + Info( "%s: %03d - Gone back into alarm state", name, image_count ); + shared_data->state = state = ALARM; + } + last_alarm_count = image_count; + } else { // no score? + if ( state == ALARM ) { + Info( "%s: %03d - Gone into alert state", name, image_count ); + shared_data->state = state = ALERT; + } else if ( state == ALERT ) { + if ( image_count-last_alarm_count > post_event_count ) { + Info( "%s: %03d - Left alarm state (%d) - %d(%d) images", name, image_count, event->Id(), event->Frames(), event->AlarmFrames() ); + //if ( function != MOCORD || event_close_mode == CLOSE_ALARM || event->Cause() == SIGNAL_CAUSE ) + if ( function != MOCORD || event_close_mode == CLOSE_ALARM ) { + shared_data->state = state = IDLE; + Info( "%s: %03d - Closing event %d, alarm end%s", name, image_count, event->Id(), (function==MOCORD)?", section truncated":"" ); + closeEvent(); + } else { + shared_data->state = state = TAPE; + } + } + } else if ( state == PREALARM ) { + // Back to IDLE + shared_data->state = state = function != MOCORD ? IDLE : TAPE; + } + if ( Event::PreAlarmCount() ) + Event::EmptyPreAlarmFrames(); + } // end if score or not + + if ( state == PREALARM || state == ALARM ) { + if ( config.create_analysis_images ) { + bool got_anal_image = false; + alarm_image.Assign( *snap_image ); + for( int i = 0; i < n_zones; i++ ) { + if ( zones[i]->Alarmed() ) { + if ( zones[i]->AlarmImage() ) { + alarm_image.Overlay( *(zones[i]->AlarmImage()) ); + got_anal_image = true; + } + if ( config.record_event_stats || state == ALARM ) { + zones[i]->RecordStats( event ); } } - - //event->AddFrames( pre_event_images, images, timestamps ); + } // end foreach zone + if ( got_anal_image ) { + (*analysis_it)->analysis_image = &alarm_image; } - if ( alarm_frame_count ) { - event->SavePreAlarmFrames(); - } - } - } else if ( state != PREALARM ) { - Info( "%s: %03d - Gone into prealarm state", name, image_count ); - shared_data->state = state = PREALARM; - } - } else if ( state == ALERT ) { - Info( "%s: %03d - Gone back into alarm state", name, image_count ); - shared_data->state = state = ALARM; - } - last_alarm_count = image_count; - } else { // no score? - if ( state == ALARM ) { - Info( "%s: %03d - Gone into alert state", name, image_count ); - shared_data->state = state = ALERT; - } else if ( state == ALERT ) { - if ( image_count-last_alarm_count > post_event_count ) { - Info( "%s: %03d - Left alarm state (%d) - %d(%d) images", name, image_count, event->Id(), event->Frames(), event->AlarmFrames() ); - //if ( function != MOCORD || event_close_mode == CLOSE_ALARM || event->Cause() == SIGNAL_CAUSE ) - if ( function != MOCORD || event_close_mode == CLOSE_ALARM ) { - shared_data->state = state = IDLE; - Info( "%s: %03d - Closing event %d, alarm end%s", name, image_count, event->Id(), (function==MOCORD)?", section truncated":"" ); - closeEvent(); - } else { - shared_data->state = state = TAPE; - } - } - } else if ( state == PREALARM ) { - // Back to IDLE - shared_data->state = state = function != MOCORD ? IDLE : TAPE; - } - if ( Event::PreAlarmCount() ) - Event::EmptyPreAlarmFrames(); - } // end if score or not - - if ( state != IDLE ) { - if ( state == PREALARM || state == ALARM ) { - if ( config.create_analysis_images ) { - bool got_anal_image = false; - alarm_image.Assign( *snap_image ); - for( int i = 0; i < n_zones; i++ ) { - if ( zones[i]->Alarmed() ) { - if ( zones[i]->AlarmImage() ) { - alarm_image.Overlay( *(zones[i]->AlarmImage()) ); - got_anal_image = true; - } - if ( config.record_event_stats && state == ALARM ) { + } else if ( config.record_event_stats && state == ALARM ) { + for ( int i = 0; i < n_zones; i++ ) { + if ( zones[i]->Alarmed() ) { zones[i]->RecordStats( event ); } + } // end foreach zone + } // analsys_images or record stats + + event->AddPacket( snap, score ); + if ( noteSetMap.size() > 0 ) + event->updateNotes( noteSetMap ); + } else if ( state == ALERT ) { + // Alert means this frame has no motion, but we were alarmed and are still recording. + event->AddPacket( snap ); + if ( noteSetMap.size() > 0 ) + event->updateNotes( noteSetMap ); + } else if ( state == TAPE ) { + if ( !(image_count%(frame_skip+1)) ) { + if ( config.bulk_frame_interval > 1 ) { + event->AddPacket( snap, (event->Frames()AddPacket( snap ); } } - if ( got_anal_image ) { - if ( state == PREALARM ) - // AddPreAlarmFrame just copies/buffers these frames in the event. If we go back to idle, we will drop them. - Event::AddPreAlarmFrame( snap_image, *timestamp, score, &alarm_image ); - else - //event->AddFrame( snap_image, *timestamp, score, &alarm_image ); - event->AddPacket( snap, score, &alarm_image ); - } else { - if ( state == PREALARM ) - Event::AddPreAlarmFrame( snap_image, *timestamp, score ); - else - //event->AddFrame( snap_image, *timestamp, score ); - event->AddPacket( snap, score ); - } - } else { - for( int i = 0; i < n_zones; i++ ) { - if ( zones[i]->Alarmed() ) { - if ( config.record_event_stats && state == ALARM ) { - zones[i]->RecordStats( event ); - } - } - } - if ( state == PREALARM ) - Event::AddPreAlarmFrame( snap_image, *timestamp, score ); - else - event->AddPacket( snap, score ); - //event->AddFrame( snap_image, *timestamp, score ); } - if ( event && noteSetMap.size() > 0 ) - event->updateNotes( noteSetMap ); - } else if ( state == ALERT ) { - // Alert means this frame has no motion, but we were alarmed and are still recording. - event->AddPacket( snap ); - if ( noteSetMap.size() > 0 ) - event->updateNotes( noteSetMap ); - } else if ( state == TAPE ) { - - if ( !(image_count%(frame_skip+1)) ) { - if ( config.bulk_frame_interval > 1 ) { - event->AddPacket( snap, (event->Frames()AddPacket( snap ); - } + if ( function == MODECT || function == MOCORD ) { + ref_image.Blend( *snap_image, ( state==ALARM ? alarm_ref_blend_perc : ref_blend_perc ) ); } - } - } // end if ! IDLE - } else { -Debug(3,"Not ready?"); - } - } else { - Debug(3, "trigger == off"); - if ( event ) { - Info( "%s: %03d - Closing event %d, trigger off", name, image_count, event->Id() ); - closeEvent(); - } - shared_data->state = state = IDLE; - last_section_mod = 0; - } // end if ( trigger_data->trigger_state != TRIGGER_OFF ) + last_signal = signal; + } // end if signal change or signal - if ( (!signal_change && signal) && (function == MODECT || function == MOCORD) ) { - if ( state == ALARM ) { - ref_image.Blend( *snap_image, alarm_ref_blend_perc ); + } else { + Debug(3,"Not ready?"); + } } else { - ref_image.Blend( *snap_image, ref_blend_perc ); - } - } - last_signal = signal; + Debug(3, "trigger == off"); + if ( event ) { + Info( "%s: %03d - Closing event %d, trigger off", name, image_count, event->Id() ); + closeEvent(); + } + shared_data->state = state = IDLE; + last_section_mod = 0; + } // end if ( trigger_data->trigger_state != TRIGGER_OFF ) - shared_data->last_read_index = index % image_buffer_count; - shared_data->last_read_time = now.tv_sec; + shared_data->last_read_index = snap->image_index; + shared_data->last_read_time = now.tv_sec; + } // end while not at end of packetqueue mutex.unlock(); analysis_image_count++; @@ -2897,7 +2718,7 @@ int Monitor::Capture() { if ( (index == shared_data->last_read_index) && (function > MONITOR) ) { Warning( "Buffer overrun at index %d, image %d, slow down capture, speed up analysis or increase ring buffer size", index, image_count ); time_t now = time(0); - double approxFps = double(image_buffer_count)/double(now-image_buffer[index].timestamp.tv_sec); + double approxFps = double(image_buffer_count)/double(now-image_buffer[index].timestamp->tv_sec); time_t last_read_delta = now - shared_data->last_read_time; if ( last_read_delta > (image_buffer_count/approxFps) ) { Warning( "Last image read from shared memory %ld seconds ago, zma may have gone away", last_read_delta ) @@ -2905,10 +2726,9 @@ int Monitor::Capture() { } } - Image* capture_image = image_buffer[index].image; ZMPacket *packet = &image_buffer[index]; - // clears frame packet->reset(); + Image* capture_image = packet->image; int captureResult = 0; unsigned int deinterlacing_value = deinterlacing & 0xff; @@ -2919,7 +2739,7 @@ int Monitor::Capture() { } /* Capture a new next image */ captureResult = camera->Capture(*packet); - gettimeofday( &packet->timestamp, NULL ); + gettimeofday( packet->timestamp, NULL ); if ( FirstCapture ) { FirstCapture = 0; @@ -2928,7 +2748,7 @@ int Monitor::Capture() { } } else { captureResult = camera->Capture(*packet); - gettimeofday( &packet->timestamp, NULL ); + gettimeofday( packet->timestamp, NULL ); if ( captureResult < 0 ) { // Unable to capture image for temporary reason // Fake a signal loss image @@ -2942,23 +2762,41 @@ int Monitor::Capture() { } else if ( captureResult > 0 ) { // Analysis thread will take care of consuming and emptying the packets. - packetqueue.queuePacket( packet ); if ( packet->packet.stream_index == video_stream_id ) { + Debug(2, "Have video packet"); if ( packet->packet.size && ! packet->in_frame ) { packet->codec_type = camera->get_VideoStream()->codecpar->codec_type; - if ( packet->decode( camera->get_VideoCodecContext() ) ) + // Have an av_packet, + if ( packetqueue.video_packet_count || ( packet->packet.flags & AV_PKT_FLAG_KEY ) || event ) { + Debug(2, "Queueing packet"); + packetqueue.queuePacket( packet ); + } + + Debug(2,"About to decode"); + if ( packet->decode( camera->get_VideoCodecContext() ) ) { +Debug(2,"Getimage"); packet->get_image(); + } } else { // If not a AVPacket, then assume video for now. packet->codec_type = camera->get_VideoStream()->codecpar->codec_type; + Debug(2, "Queueing packet"); + packetqueue.queuePacket( packet ); } } else { // probably audio - packet->image = NULL; - packet->codec_type = camera->get_AudioStream()->codecpar->codec_type; - packet->decode( camera->get_AudioCodecContext() ); + Debug(2, "Have audio packet (%d) != (%d) ", packet->packet.stream_index, video_stream_id ); + // Only queue if we have some video packets in there. + if ( packetqueue.video_packet_count || event ) { + Debug(2, "Queueing packet"); + packet->image = NULL; + packet->image_index = -1; + packet->codec_type = camera->get_AudioStream()->codecpar->codec_type; + packet->decode( camera->get_AudioCodecContext() ); + packetqueue.queuePacket( packet ); + } // Don't update last_write_index because that is used for live streaming - shared_data->last_write_time = image_buffer[index].timestamp.tv_sec; + shared_data->last_write_time = image_buffer[index].timestamp->tv_sec; mutex.unlock(); return 1; } @@ -2999,7 +2837,7 @@ int Monitor::Capture() { capture_image->MaskPrivacy( privacy_bitmask ); if ( config.timestamp_on_capture ) { - TimestampImage( capture_image, &packet->timestamp ); + TimestampImage( capture_image, packet->timestamp ); } #if 0 @@ -3048,7 +2886,7 @@ int Monitor::Capture() { shared_data->signal = CheckSignal(capture_image); shared_data->last_write_index = index; - shared_data->last_write_time = image_buffer[index].timestamp.tv_sec; + shared_data->last_write_time = image_buffer[index].timestamp->tv_sec; image_count++; } else { // result == 0 // Question is, do we update last_write_index etc? @@ -3063,25 +2901,25 @@ int Monitor::Capture() { if ( !captureResult ) { gettimeofday( &now, NULL ); } else { - now.tv_sec = image_buffer[index].timestamp.tv_sec; + now.tv_sec = image_buffer[index].timestamp->tv_sec; } // If we are too fast, we get div by zero. This seems to happen in the case of audio packets. if ( now.tv_sec != last_fps_time ) { - fps = double(fps_report_interval)/(now.tv_sec-last_fps_time); + capture_fps = double(fps_report_interval)/(now.tv_sec-last_fps_time); //Info( "%d -> %d -> %d", fps_report_interval, now, last_fps_time ); //Info( "%d -> %d -> %lf -> %lf", now-last_fps_time, fps_report_interval/(now-last_fps_time), double(fps_report_interval)/(now-last_fps_time), fps ); - Info( "%s: %d - Capturing at %.2lf fps", name, image_count, fps ); + Info( "%s: %d - Capturing at %.2lf fps", name, image_count, capture_fps ); last_fps_time = now.tv_sec; static char sql[ZM_SQL_SML_BUFSIZ]; - snprintf( sql, sizeof(sql), "UPDATE Monitors SET CaptureFPS='%.2lf' WHERE Id=%d", fps, id ); + snprintf( sql, sizeof(sql), "UPDATE Monitors SET CaptureFPS='%.2lf' WHERE Id=%d", capture_fps, id ); if ( mysql_query( &dbconn, sql ) ) { Error( "Can't run query: %s", mysql_error( &dbconn ) ); } else { Debug(2,"toofast");} } // end if too fast }else { -Debug(2,"Nor reopting fps"); +Debug(2,"Nor reporting fps"); } // end if should report fps // Icon: I'm not sure these should be here. They have nothing to do with capturing @@ -3379,6 +3217,7 @@ unsigned int Monitor::SubpixelOrder() const { return( camera->SubpixelOrder() ); int Monitor::PrimeCapture() { int ret = camera->PrimeCapture(); video_stream_id = ret ? camera->get_VideoStreamId() : -1; + Debug(2, "Video stream id is (%d)", video_stream_id ); return ret; } int Monitor::PreCapture() { @@ -3389,10 +3228,6 @@ int Monitor::PostCapture() { } Monitor::Orientation Monitor::getOrientation() const { return orientation; } -ZMPacket *Monitor::getSnapshot() { - return &image_buffer[ shared_data->last_write_index%image_buffer_count ]; -} - // Wait for camera to get an image, and then assign it as the base reference image. So this should be done as the first task in the analysis thread startup. void Monitor::get_ref_image() { while ( diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 9129d5a3a..fc582440a 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -166,6 +166,7 @@ protected: VideoStore *videoStore; zm_packetqueue packetqueue; Mutex mutex; + std::list::iterator analysis_it; // Iterator into the packetqueue. Theoretically points to the most recently analyzed packet class MonitorLink { protected: @@ -188,6 +189,7 @@ protected: volatile TriggerData *trigger_data; volatile VideoStoreData *video_store_data; + int last_state; int last_event_id; @@ -245,14 +247,13 @@ protected: #if HAVE_LIBSWSCALE struct SwsContext *mConvertContext; #endif - bool record_audio; // Whether to store the audio that we receive - + bool record_audio; // Whether to store the audio that we receive int brightness; // The statically saved brightness of the camera int contrast; // The statically saved contrast of the camera int hue; // The statically saved hue of the camera int colour; // The statically saved colour of the camera - char event_prefix[64]; // The prefix applied to event names as they are created - char label_format[64]; // The format of the timestamp on the images + char event_prefix[64]; // The prefix applied to event names as they are created + char label_format[64]; // The format of the timestamp on the images Coord label_coord; // The coordinates of the timestamp on the images int label_size; // Size of the timestamp on the images int image_buffer_count; // Size of circular image buffer, at least twice the size of the pre_event_count @@ -263,10 +264,10 @@ protected: int post_event_count; // How many unalarmed images must occur before the alarm state is reset int stream_replay_buffer; // How many frames to store to support DVR functions, IGNORED from this object, passed directly into zms now int section_length; // How long events should last in continuous modes - bool adaptive_skip; // Whether to use the newer adaptive algorithm for this monitor + bool adaptive_skip; // Whether to use the newer adaptive algorithm for this monitor int frame_skip; // How many frames to skip in continuous modes int motion_frame_skip; // How many frames to skip in motion detection - double analysis_fps; // Target framerate for video analysis + double analysis_fps_limit; // Target framerate for video analysis unsigned int analysis_update_delay; // How long we wait before updating analysis parameters int capture_delay; // How long we wait between capture frames int alarm_capture_delay; // How long we wait between capture frames when in alarm state @@ -276,9 +277,11 @@ protected: int alarm_ref_blend_perc; // Percentage of new image going into reference image during alarm. bool track_motion; // Whether this monitor tries to track detected motion Rgb signal_check_colour; // The colour that the camera will emit when no video signal detected - bool embed_exif; // Whether to embed Exif data into each image frame or not + bool embed_exif; // Whether to embed Exif data into each image frame or not + + double capture_fps; // Current capturing fps + double analysis_fps; // Current analysis fps - double fps; Image delta_image; Image ref_image; Image alarm_image; // Used in creating analysis images, will be initialized in Analysis @@ -317,9 +320,10 @@ protected: TriggerData *trigger_data; VideoStoreData *video_store_data; - ZMPacket *image_buffer; + struct timeval *shared_timestamps; + unsigned char *shared_images; + ZMPacket *image_buffer; ZMPacket next_buffer; /* Used by four field deinterlacing */ - ZMPacket *pre_event_buffer; int video_stream_id; // will be filled in PrimeCapture @@ -460,8 +464,8 @@ public: unsigned int GetPreEventCount() const { return pre_event_count; }; State GetState() const; int GetImage( int index=-1, int scale=100 ); - ZMPacket *getSnapshot(); - struct timeval GetTimestamp( int index=-1 ) const; + ZMPacket *getSnapshot( int index=-1 ); + struct timeval GetTimestamp( int index=-1 ); void UpdateAdaptiveSkip(); useconds_t GetAnalysisRate(); unsigned int GetAnalysisUpdateDelay() const { return( analysis_update_delay ); } @@ -471,6 +475,7 @@ public: unsigned int GetLastWriteIndex() const; unsigned int GetLastEvent() const; double GetFPS() const; + void UpdateAnalysisFPS(); void ForceAlarmOn( int force_score, const char *force_case, const char *force_text="" ); void ForceAlarmOff(); void CancelForced(); diff --git a/src/zm_monitorstream.cpp b/src/zm_monitorstream.cpp index 60f782c86..3362017a7 100644 --- a/src/zm_monitorstream.cpp +++ b/src/zm_monitorstream.cpp @@ -670,13 +670,16 @@ Debug(2, "Have checking command Queue for connkey: %d", connkey ); if ( (frame_mod == 1) || ((frame_count%frame_mod) == 0) ) { if ( !paused && !delayed ) { // Send the next frame + // ZMPacket *snap = &monitor->image_buffer[index]; + Image *image = snap->image;// This works because connect rebuilds the image_buffer links + struct timeval *timestamp = snap->timestamp; - if ( !sendFrame( snap->image, &snap->timestamp ) ) { + if ( !sendFrame( image, timestamp ) ) { Debug(2, "sendFrame failed, quiting."); zm_terminate = true; } - last_frame_timestamp = snap->timestamp; + last_frame_timestamp = *timestamp; //frame_sent = true; temp_read_index = temp_write_index; @@ -684,14 +687,14 @@ Debug(2, "Have checking command Queue for connkey: %d", connkey ); } if ( buffered_playback ) { if ( monitor->shared_data->valid ) { - if ( monitor->image_buffer[index].timestamp.tv_sec ) { + if ( monitor->shared_timestamps[index].tv_sec ) { int temp_index = temp_write_index%temp_image_buffer_count; Debug( 2, "Storing frame %d", temp_index ); if ( !temp_image_buffer[temp_index].valid ) { snprintf( temp_image_buffer[temp_index].file_name, sizeof(temp_image_buffer[0].file_name), "%s/zmswap-i%05d.jpg", swap_path, temp_index ); temp_image_buffer[temp_index].valid = true; } - temp_image_buffer[temp_index].timestamp = monitor->image_buffer[index].timestamp; + temp_image_buffer[temp_index].timestamp = monitor->shared_timestamps[index]; monitor->image_buffer[index].image->WriteJpeg( temp_image_buffer[temp_index].file_name, config.jpeg_file_quality ); temp_write_index = MOD_ADD( temp_write_index, 1, temp_image_buffer_count ); if ( temp_write_index == temp_read_index ) { @@ -770,7 +773,7 @@ void MonitorStream::SingleImage( int scale ) { int img_buffer_size = 0; static JOCTET img_buffer[ZM_MAX_IMAGE_SIZE]; Image scaled_image; - ZMPacket *snap = monitor->getSnapshot(); + ZMPacket *snap = &(monitor->image_buffer[monitor->shared_data->last_write_index]); Image *snap_image = snap->image; if ( scale != ZM_SCALE_BASE ) { @@ -779,7 +782,7 @@ void MonitorStream::SingleImage( int scale ) { snap_image = &scaled_image; } if ( !config.timestamp_on_capture ) { - monitor->TimestampImage( snap_image, &snap->timestamp ); + monitor->TimestampImage( snap_image, snap->timestamp ); } snap_image->EncodeJpeg( img_buffer, &img_buffer_size ); @@ -799,7 +802,7 @@ void MonitorStream::SingleImageRaw( int scale ) { snap_image = &scaled_image; } if ( !config.timestamp_on_capture ) { - monitor->TimestampImage( snap_image, &snap->timestamp ); + monitor->TimestampImage( snap_image, snap->timestamp ); } fprintf( stdout, "Content-Length: %d\r\n", snap_image->Size() ); @@ -821,7 +824,7 @@ void MonitorStream::SingleImageZip( int scale ) { snap_image = &scaled_image; } if ( !config.timestamp_on_capture ) { - monitor->TimestampImage( snap_image, &snap->timestamp ); + monitor->TimestampImage( snap_image, snap->timestamp ); } snap_image->Zip( img_buffer, &img_buffer_size ); diff --git a/src/zm_packet.cpp b/src/zm_packet.cpp index 3ddfcc8c7..7add41192 100644 --- a/src/zm_packet.cpp +++ b/src/zm_packet.cpp @@ -33,46 +33,9 @@ ZMPacket::ZMPacket( ) { buffer = NULL; av_init_packet( &packet ); packet.size = 0; // So we can detect whether it has been filled. - timestamp = (struct timeval){0}; -} - -ZMPacket::ZMPacket( Image *i ) { - keyframe = 1; - image = i; - in_frame = NULL; - out_frame = NULL; - buffer = NULL; - av_init_packet( &packet ); - timestamp = (struct timeval){0}; -} - -ZMPacket::ZMPacket( AVPacket *p ) { - image = NULL; - av_init_packet( &packet ); - set_packet( p ); - keyframe = p->flags & AV_PKT_FLAG_KEY; - buffer = NULL; - in_frame = NULL; - out_frame = NULL; -} - -ZMPacket::ZMPacket( AVPacket *p, struct timeval *t ) { - image = NULL; - av_init_packet( &packet ); - set_packet( p ); - timestamp = *t; - keyframe = p->flags & AV_PKT_FLAG_KEY; - buffer = NULL; - in_frame = NULL; - out_frame = NULL; -} -ZMPacket::ZMPacket( AVPacket *p, AVFrame *f, Image *i ) { - av_init_packet( &packet ); - set_packet( p ); - image = i; - buffer = NULL; - in_frame = NULL; - out_frame = f; + timestamp = NULL; + analysis_image = NULL; + image_index = -1; } ZMPacket::~ZMPacket() { @@ -88,8 +51,13 @@ ZMPacket::~ZMPacket() { if ( buffer ) { av_freep( &buffer ); } + if ( analysis_image ) { + delete analysis_image; + analysis_image = NULL; + } // We assume the image was allocated elsewhere, so we just unref it. image = NULL; + timestamp = NULL; } void ZMPacket::reset() { @@ -108,10 +76,18 @@ void ZMPacket::reset() { //Debug(4,"freeing buffer"); av_freep( &buffer ); } + if ( analysis_image ) { + delete analysis_image; + analysis_image = NULL; + } + if ( (! image) && timestamp ) { + delete timestamp; + timestamp = NULL; + } } int ZMPacket::decode( AVCodecContext *ctx ) { - Debug(4, "about to decode video" ); + Debug(4, "about to decode video, image_index is (%d)", image_index ); if ( in_frame ) { Error("Already have a frame?"); @@ -196,7 +172,7 @@ AVPacket *ZMPacket::set_packet( AVPacket *p ) { if ( zm_av_packet_ref( &packet, p ) < 0 ) { Error("error refing packet"); } - gettimeofday( ×tamp, NULL ); + gettimeofday( timestamp, NULL ); keyframe = p->flags & AV_PKT_FLAG_KEY; return &packet; } diff --git a/src/zm_packet.h b/src/zm_packet.h index 0cfaee112..10ac87a5b 100644 --- a/src/zm_packet.h +++ b/src/zm_packet.h @@ -37,10 +37,13 @@ class ZMPacket { AVPacket packet; // Input packet, undecoded AVFrame *in_frame; // Input image, decoded Theoretically only filled if needed. AVFrame *out_frame; // Input image, decoded Theoretically only filled if needed. - uint8_t *buffer; - Image *image; // Our internal image object representing this frame - struct timeval timestamp; + uint8_t *buffer; + Image *image; // Our internal image object representing this frame + Image *analysis_image; // Our internal image object representing this frame + int score; + struct timeval *timestamp; AVMediaType codec_type; + int image_index; public: AVPacket *av_packet() { return &packet; } AVPacket *set_packet( AVPacket *p ) ; @@ -57,7 +60,6 @@ class ZMPacket { explicit ZMPacket( Image *image ); ZMPacket(); ~ZMPacket(); - }; #endif /* ZM_PACKET_H */ diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index 5326e18d2..65b560cdf 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -24,9 +24,8 @@ #define VIDEO_QUEUESIZE 200 #define AUDIO_QUEUESIZE 50 -zm_packetqueue::zm_packetqueue(){ +zm_packetqueue::zm_packetqueue() { video_packet_count = 0; - } zm_packetqueue::~zm_packetqueue() { @@ -48,7 +47,7 @@ ZMPacket* zm_packetqueue::popPacket( ) { ZMPacket *packet = pktQueue.front(); pktQueue.pop_front(); - if ( packet->codec_type == AVMEDIA_TYPE_VIDEO ) { + if ( packet->codec_type == AVMEDIA_TYPE_VIDEO ) video_packet_count -= 1; return packet; @@ -84,7 +83,7 @@ unsigned int zm_packetqueue::clearQueue( unsigned int frames_to_keep, int stream Debug(3, "Hit end of queue, still need (%d) video keyframes", frames_to_keep ); } else { AVPacket *av_packet = &( (*it)->packet ); - while ( ( av_packet->stream_index != stream_id ) || ! ( av_packet->flags & AV_PKT_FLAG_KEY ) && it != pktQueue.rend() ) { + while ( ( av_packet->stream_index != stream_id ) || ! ( av_packet->flags & AV_PKT_FLAG_KEY ) && ( it != pktQueue.rend() ) ) { ++it; } } @@ -118,7 +117,7 @@ unsigned int zm_packetqueue::size() { return pktQueue.size(); } -unsigned in zm_packetqueue::get_video_packet_count() { +unsigned int zm_packetqueue::get_video_packet_count() { return video_packet_count; } @@ -141,7 +140,7 @@ void zm_packetqueue::clear_unwanted_packets( timeval *recording_started, int mVi && ( av_packet->stream_index == mVideoStreamId ) && - timercmp( &(zm_packet->timestamp), recording_started, < ) + timercmp( zm_packet->timestamp, recording_started, < ) ) { Debug(3, "Found keyframe before start with stream index (%d) with keyframe (%d)", av_packet->stream_index, ( av_packet->flags & AV_PKT_FLAG_KEY ) ); break; diff --git a/src/zm_packetqueue.h b/src/zm_packetqueue.h index eba585566..36f7208f1 100644 --- a/src/zm_packetqueue.h +++ b/src/zm_packetqueue.h @@ -41,9 +41,8 @@ public: unsigned int size(); unsigned int get_video_packet_count(); void clear_unwanted_packets( timeval *recording, int mVideoStreamId ); -private: std::list pktQueue; - unsigned int video_packets; // keep track of how many video packets we have, because we shouldn't have more than image_buffer_count + unsigned int video_packet_count; // keep track of how many video packets we have, because we shouldn't have more than image_buffer_count }; #endif /* ZM_PACKETQUEUE_H */ diff --git a/src/zm_remote_camera.h b/src/zm_remote_camera.h index 545fce48f..f1ee5db3b 100644 --- a/src/zm_remote_camera.h +++ b/src/zm_remote_camera.h @@ -45,6 +45,7 @@ protected: std::string username; std::string password; std::string auth64; + struct addrinfo *hp; // Reworked authentication system // First try without authentication, even if we have a username and password @@ -53,8 +54,6 @@ protected: // subsequent requests can set the required authentication header. bool mNeedAuth; zm::Authenticator* mAuthenticator; -protected: - struct addrinfo *hp; public: RemoteCamera( diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index c381faaba..3baca5ae7 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -976,10 +976,10 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { } // end if no out_frame if ( ! video_last_pts ) { - video_last_pts = zm_packet->timestamp.tv_sec*1000000 + zm_packet->timestamp.tv_usec; + video_last_pts = zm_packet->timestamp->tv_sec*1000000 + zm_packet->timestamp->tv_usec; zm_packet->out_frame->pts = 0; } else { - zm_packet->out_frame->pts = ( zm_packet->timestamp.tv_sec*1000000 + zm_packet->timestamp.tv_usec ) - video_last_pts; + zm_packet->out_frame->pts = ( zm_packet->timestamp->tv_sec*1000000 + zm_packet->timestamp->tv_usec ) - video_last_pts; } // Do this to allow the encoder to choose whether to use I/P/B frame @@ -1030,10 +1030,10 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { opkt.size = ipkt->size; opkt.flags = ipkt->flags; if ( ! video_last_pts ) { - video_last_pts = zm_packet->timestamp.tv_sec*1000000 + zm_packet->timestamp.tv_usec; + video_last_pts = zm_packet->timestamp->tv_sec*1000000 + zm_packet->timestamp->tv_usec; opkt.dts = opkt.pts = 0; } else { - opkt.dts = opkt.pts = ( zm_packet->timestamp.tv_sec*1000000 + zm_packet->timestamp.tv_usec ) - video_last_pts; + opkt.dts = opkt.pts = ( zm_packet->timestamp->tv_sec*1000000 + zm_packet->timestamp->tv_usec ) - video_last_pts; } } opkt.duration = 0; From 81c46073a70943793c2159730ba3c27fc02a42e2 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 27 Nov 2017 11:57:08 -0500 Subject: [PATCH 0050/2339] remove some brackets --- web/includes/functions.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index e2a93849b..7cb81c23e 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -1325,7 +1325,7 @@ function addFilterTerm( $filter, $position, $term=false ) { unset( $term['cnj'] ); array_splice( $filter['Query']['terms'], $position, 0, array( $term?$term:array() ) ); - return( $filter ); + return $filter; } function delFilterTerm( $filter, $position ) { @@ -1335,7 +1335,7 @@ function delFilterTerm( $filter, $position ) { $position = count($filter['Query']['terms']); array_splice( $filter['Query']['terms'], $position, 1 ); - return( $filter ); + return $filter; } function getPagination( $pages, $page, $maxShortcuts, $query, $querySep='&' ) { From 106351a9f3f66b9485a8d4364ea035d626db5fdc Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 27 Nov 2017 11:57:42 -0500 Subject: [PATCH 0051/2339] don't get zma status --- web/skins/classic/views/console.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index 584fe6c62..789c3b3ef 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -114,7 +114,7 @@ for ( $i = 0; $i < count($displayMonitors); $i++ ) { if ( $maxHeight < $scaleHeight ) $maxHeight = $scaleHeight; } $monitor['zmc'] = zmcStatus( $monitor ); - $monitor['zma'] = zmaStatus( $monitor ); + #$monitor['zma'] = zmaStatus( $monitor ); $zoneCount += $monitor['ZoneCount']; $counts = array(); @@ -125,7 +125,6 @@ for ( $i = 0; $i < count($displayMonitors); $i++ ) { array( 'cnj' => 'and', 'attr' => 'MonitorId', 'op' => '=', 'val' => $monitor['Id'] ) ); parseFilter( $filter ); - #$counts[] = 'count(if(1'.$filter['sql'].",1,NULL)) AS EventCount$j, SUM(if(1".$filter['sql'].",DiskSpace,NULL)) As DiskSpace$j"; $monitor['eventCounts'][$j]['filter'] = $filter; $eventCounts[$j]['totalevents'] += $monitor[$j.'Events']; $eventCounts[$j]['totaldiskspace'] += $monitor[$j.'EventDiskSpace']; From d1886b5536cd03d77f4e73af10460bf8c0777e51 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 27 Nov 2017 14:57:24 -0500 Subject: [PATCH 0052/2339] wip --- src/zm_analysis_thread.cpp | 4 +-- src/zm_monitor.cpp | 61 +++++++++++++++++++++----------------- src/zm_packetqueue.cpp | 8 ++--- src/zm_videostore.cpp | 15 ++++++---- 4 files changed, 50 insertions(+), 38 deletions(-) diff --git a/src/zm_analysis_thread.cpp b/src/zm_analysis_thread.cpp index 8d2c14551..1efee5999 100644 --- a/src/zm_analysis_thread.cpp +++ b/src/zm_analysis_thread.cpp @@ -36,10 +36,10 @@ int AnalysisThread::run() { } if ( !monitor->Analyse() ) { -//Debug(4, "Sleeping for %d", monitor->Active()?ZM_SAMPLE_RATE:ZM_SUSPENDED_RATE); +Debug(2, "Sleeping for %d", monitor->Active()?ZM_SAMPLE_RATE:ZM_SUSPENDED_RATE); usleep(monitor->Active()?ZM_SAMPLE_RATE:ZM_SUSPENDED_RATE); } else if ( analysis_rate ) { -//Debug(4, "Sleeping for %d", analysis_rate); +Debug(2, "Sleeping for %d", analysis_rate); usleep(analysis_rate); } diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 7c7b85922..2995a2259 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -799,10 +799,10 @@ double Monitor::GetFPS() const { useconds_t Monitor::GetAnalysisRate() { capture_fps = GetFPS(); if ( !analysis_fps_limit ) { - return( 0 ); + return 0; } else if ( analysis_fps_limit > capture_fps ) { Warning( "Analysis fps (%.2f) is greater than capturing fps (%.2f)", analysis_fps_limit, capture_fps ); - return( 0 ); + return 0; } else { return( ( 1000000 / analysis_fps_limit ) - ( 1000000 / capture_fps ) ); } @@ -1241,14 +1241,23 @@ bool Monitor::Analyse() { // If do have an event, then analysis_it should point to the head of the queue, because we would have emptied it on event creation. unsigned int index = ( shared_data->last_read_index + 1 ) % image_buffer_count; + Debug(2, "Analysis index (%d), last_Write(%d)", index, shared_data->last_write_index ); + if ( analysis_it == packetqueue.pktQueue.end() ) { + Debug(2, "Analysis index (%d), last_Write(%d), at end of queue", index, shared_data->last_write_index ); + } // Move to next packet. - while ( ( index != shared_data->last_write_index ) && ( analysis_it != packetqueue.pktQueue.end() ) ) { + while ( ( index != shared_data->last_write_index ) && ( *analysis_it != packetqueue.pktQueue.back() ) ) { ++analysis_it; ZMPacket *snap = *analysis_it; struct timeval *timestamp = snap->timestamp; Image *snap_image = snap->image; Debug(2, "Analysing image (%d)", snap->image_index ); + if ( snap->image_index == -1 ) { + Debug(2, "skipping because audio"); + continue; + } + int last_section_mod = 0; @@ -1306,7 +1315,9 @@ bool Monitor::Analyse() { shared_data->active = signal; ref_image = *snap_image; - } else if ( signal ) { + }// else + + if ( signal ) { if ( Active() && (function == MODECT || function == MOCORD) ) { Debug(3, "signal and active and modect"); Event::StringSet zoneSet; @@ -1466,12 +1477,12 @@ bool Monitor::Analyse() { } // analsys_images or record stats mutex.lock(); - snap = packetqueue.popPacket(); + ZMPacket *pack = packetqueue.popPacket(); mutex.unlock(); - event->AddPacket( snap, score ); - if ( snap->image_index == -1 ) { - delete snap; - snap = NULL; + event->AddPacket( pack, score ); + if ( pack->image_index == -1 ) { + delete pack; + pack = NULL; } if ( noteSetMap.size() > 0 ) @@ -1479,28 +1490,28 @@ bool Monitor::Analyse() { } else if ( state == ALERT ) { // Alert means this frame has no motion, but we were alarmed and are still recording. mutex.lock(); - snap = packetqueue.popPacket(); + ZMPacket *pack = packetqueue.popPacket(); mutex.unlock(); - event->AddPacket( snap, score ); - if ( snap->image_index == -1 ) { - delete snap; - snap = NULL; + event->AddPacket( pack, score ); + if ( pack->image_index == -1 ) { + delete pack; + pack = NULL; } if ( noteSetMap.size() > 0 ) event->updateNotes( noteSetMap ); } else if ( state == TAPE ) { if ( !(image_count%(frame_skip+1)) ) { mutex.lock(); - snap = packetqueue.popPacket(); + ZMPacket *pack = packetqueue.popPacket(); mutex.unlock(); if ( config.bulk_frame_interval > 1 ) { - event->AddPacket( snap, (event->Frames()AddPacket( pack, (event->Frames()AddPacket( snap ); + event->AddPacket( pack ); } - if ( snap->image_index == -1 ) { - delete snap; - snap = NULL; + if ( pack->image_index == -1 ) { + delete pack; + pack = NULL; } } } @@ -1508,7 +1519,7 @@ bool Monitor::Analyse() { ref_image.Blend( *snap_image, ( state==ALARM ? alarm_ref_blend_perc : ref_blend_perc ) ); } last_signal = signal; - } // end if signal change or signal + } // end if signal } else { Debug(3,"Not ready?"); @@ -1525,11 +1536,10 @@ bool Monitor::Analyse() { shared_data->last_read_index = snap->image_index; shared_data->last_read_time = now.tv_sec; + analysis_image_count++; } // end while not at end of packetqueue //mutex.unlock(); - analysis_image_count++; - return true; } @@ -2759,7 +2769,7 @@ int Monitor::Capture() { } ZMPacket *packet = &image_buffer[index]; - Debug(2,"Reset index(%d)", index ); + Debug(2,"Reset index(%d) of (%d)", index, image_buffer_count ); packet->reset(); Image* capture_image = packet->image; int captureResult = 0; @@ -2802,11 +2812,8 @@ int Monitor::Capture() { // Only queue if we have some video packets in there. if ( packetqueue.video_packet_count || event ) { // Need to copy it into another ZMPacket. - Debug(2, "Copyingg packet"); ZMPacket *audio_packet = new ZMPacket( *packet ); - Debug(2, "Copyingg packet"); audio_packet->codec_type = camera->get_AudioStream()->codecpar->codec_type; - //packet->decode( camera->get_AudioCodecContext() ); Debug(2, "Queueing packet"); packetqueue.queuePacket( audio_packet ); } diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index 10a66c086..f1ce41ec7 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -81,13 +81,13 @@ unsigned int zm_packetqueue::clearQueue( unsigned int frames_to_keep, int stream // Might not be starting with a keyframe, but should always start with a keyframe if ( frames_to_keep ) { - Debug(3, "Hit end of queue, still need (%d) video keyframes", frames_to_keep ); + Debug(4, "Hit end of queue, still need (%d) video keyframes", frames_to_keep ); } else { if ( it != pktQueue.rend() ) { - Debug(2, "Not rend"); + Debug(4, "Not rend"); ZMPacket *zm_packet = *it; - Debug(2, "packet %x %d", zm_packet, zm_packet->image_index); + Debug(4, "packet %x %d", zm_packet, zm_packet->image_index); AVPacket *av_packet = &(zm_packet->packet); while ( @@ -96,7 +96,7 @@ unsigned int zm_packetqueue::clearQueue( unsigned int frames_to_keep, int stream (( av_packet->stream_index != stream_id ) || ! ( av_packet->flags & AV_PKT_FLAG_KEY )) ) { zm_packet = *it; - Debug(2, "packet %x %d", zm_packet, zm_packet->image_index); + Debug(4, "packet %x %d", zm_packet, zm_packet->image_index); ++it; av_packet = &( (*it)->packet ); } diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index ab7ff5f1e..3356466bb 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -86,10 +86,9 @@ VideoStore::VideoStore( video_in_stream_index = video_in_stream->index; #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) video_in_ctx = avcodec_alloc_context3(NULL); - Debug(2, "copy to context"); + Debug(2, "copy to video_in_context"); avcodec_parameters_to_context(video_in_ctx, video_in_stream->codecpar); - Debug(2, "dump to context"); zm_dump_codecpar( video_in_stream->codecpar ); //video_in_ctx.codec_id = video_in_stream->codecpar.codec_id; #else @@ -138,12 +137,10 @@ Debug(2,"Copied video context from input stream"); avcodec_copy_context( video_out_ctx, video_in_ctx ); #endif video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate - // Same codec, just copy the packets, otherwise we have to decode/encode - video_out_codec = (AVCodec *)video_in_ctx->codec; // Only set orientation if doing passthrough, otherwise the frame image will be rotated Monitor::Orientation orientation = monitor->getOrientation(); - Debug(3, "Have orientation"); if ( orientation ) { + Debug(3, "Have orientation"); if ( orientation == Monitor::ROTATE_0 ) { } else if ( orientation == Monitor::ROTATE_90 ) { dsr = av_dict_set(&video_out_stream->metadata, "rotate", "90", 0); @@ -175,6 +172,14 @@ Debug(2,"Copied video context from input stream"); default: break; } + // Same codec, just copy the packets, otherwise we have to decode/encode + video_out_codec = avcodec_find_encoder(AV_CODEC_ID_H264); + if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, NULL)) < 0 ) { + Warning("Can't open video codec (%s)! %s, trying h264", + video_out_codec->name, + av_make_error_string(ret).c_str() + ); + } } else { From 81fa2019107d29ef87c9f0ce3ebb3b38af8b5a9a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 27 Nov 2017 15:43:06 -0500 Subject: [PATCH 0053/2339] init last_signal --- src/zm_monitor.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 2995a2259..b2712198e 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -352,6 +352,7 @@ Monitor::Monitor( first_alarm_count = 0; last_alarm_count = 0; state = IDLE; + last_signal = false; if ( alarm_frame_count < 1 ) alarm_frame_count = 1; @@ -590,9 +591,9 @@ Monitor::~Monitor() { if ( (deinterlacing & 0xff) == 4) { delete next_buffer.image; } -#if 0 +#if 1 for ( int i = 0; i < image_buffer_count; i++ ) { - delete image_buffer[i]; + delete image_buffer[i].image; } #endif delete[] image_buffer; @@ -1453,11 +1454,12 @@ bool Monitor::Analyse() { if ( state == PREALARM || state == ALARM ) { if ( config.create_analysis_images ) { bool got_anal_image = false; - alarm_image.Assign( *snap_image ); + Image *anal_image = new Image( *snap_image ); + //alarm_image.Assign( *snap_image ); for( int i = 0; i < n_zones; i++ ) { if ( zones[i]->Alarmed() ) { if ( zones[i]->AlarmImage() ) { - alarm_image.Overlay( *(zones[i]->AlarmImage()) ); + anal_image->Overlay( *(zones[i]->AlarmImage()) ); got_anal_image = true; } if ( config.record_event_stats || state == ALARM ) { @@ -1466,7 +1468,9 @@ bool Monitor::Analyse() { } } // end foreach zone if ( got_anal_image ) { - (*analysis_it)->analysis_image = &alarm_image; + (*analysis_it)->analysis_image = anal_image; + } else { + delete anal_image; } } else if ( config.record_event_stats && state == ALARM ) { for ( int i = 0; i < n_zones; i++ ) { @@ -2791,6 +2795,7 @@ int Monitor::Capture() { } } else { captureResult = camera->Capture(*packet); + Debug(2, "Reset timestamp"); gettimeofday( packet->timestamp, NULL ); if ( captureResult < 0 ) { // Unable to capture image for temporary reason From 9d91d4ce4544393245c52c64c0c102fa5c45ce65 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 27 Nov 2017 15:43:16 -0500 Subject: [PATCH 0054/2339] relocate code for readability --- src/zm_event.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 2b0268387..4fc4c7b2b 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -68,7 +68,6 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string } static char sql[ZM_SQL_MED_BUFSIZ]; - struct tm *stime = localtime( &start_time.tv_sec ); snprintf( sql, sizeof(sql), "INSERT INTO Events ( MonitorId, StorageId, Name, StartTime, Width, Height, Cause, Notes, StateId, Orientation, Videoed, DefaultVideo, SaveJPEGs ) values ( %d, %d, 'New Event', from_unixtime( %ld ), %d, %d, '%s', '%s', %d, %d, %d, '', %d )", monitor->Id(), storage->Id(), @@ -99,6 +98,7 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string struct stat statbuf; char id_file[PATH_MAX]; + struct tm *stime = localtime( &start_time.tv_sec ); if ( config.use_deep_storage ) { char *path_ptr = path; From db5cf998add345abc2fae2a79c08b8532e5801f7 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 27 Nov 2017 15:43:21 -0500 Subject: [PATCH 0055/2339] Turn off debug --- scripts/ZoneMinder/lib/ZoneMinder/Object.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Object.pm b/scripts/ZoneMinder/lib/ZoneMinder/Object.pm index 44351de65..4f7538548 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Object.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Object.pm @@ -47,7 +47,7 @@ use vars qw/ $AUTOLOAD $log $dbh/; *log = \$ZoneMinder::Logger::logger; *dbh = \$ZoneMinder::Database::dbh; -my $debug = 1; +my $debug = 0; use constant DEBUG_ALL=>0; sub new { From 6e4abf83d0ddc1fcdc043ca7d19673d256fafab5 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 28 Nov 2017 08:29:03 -0500 Subject: [PATCH 0056/2339] wip --- src/zm_analysis_thread.cpp | 4 ++- src/zm_local_camera.cpp | 7 ++--- src/zm_monitor.cpp | 56 +++++++++++++++++++++++++++++--------- 3 files changed, 49 insertions(+), 18 deletions(-) diff --git a/src/zm_analysis_thread.cpp b/src/zm_analysis_thread.cpp index 1efee5999..261f0e18f 100644 --- a/src/zm_analysis_thread.cpp +++ b/src/zm_analysis_thread.cpp @@ -37,10 +37,12 @@ int AnalysisThread::run() { if ( !monitor->Analyse() ) { Debug(2, "Sleeping for %d", monitor->Active()?ZM_SAMPLE_RATE:ZM_SUSPENDED_RATE); - usleep(monitor->Active()?ZM_SAMPLE_RATE:ZM_SUSPENDED_RATE); + usleep(100*(monitor->Active()?ZM_SAMPLE_RATE:ZM_SUSPENDED_RATE)); } else if ( analysis_rate ) { Debug(2, "Sleeping for %d", analysis_rate); usleep(analysis_rate); + } else { +Debug(2, "Not Sleeping"); } //sigprocmask(SIG_UNBLOCK, &block_set, 0); diff --git a/src/zm_local_camera.cpp b/src/zm_local_camera.cpp index da43776a7..d7e9f398f 100644 --- a/src/zm_local_camera.cpp +++ b/src/zm_local_camera.cpp @@ -1906,8 +1906,9 @@ int LocalCamera::PrimeCapture() { } } #endif // ZM_HAS_V4L1 +mVideoStreamId = 0; - return( 0 ); + return 0; } int LocalCamera::PreCapture() { @@ -2054,6 +2055,7 @@ int LocalCamera::Capture( ZMPacket &zm_packet ) { zm_packet.image->Assign(width, height, colours, subpixelorder, buffer, imagesize); } // end if doing conversion or not + zm_packet.keyframe = 1; return 1; } // end int LocalCamera::Capture() @@ -2142,10 +2144,7 @@ AVStream *LocalCamera::get_VideoStream() { } else { Error("Can't create video stream"); } - } else { - Debug(2,"Have videostream"); } - Debug(2,"Get videoStream"); return video_stream; } diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index b2712198e..e9477dcbd 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1226,8 +1226,6 @@ bool Monitor::Analyse() { return false; } - struct timeval now; - gettimeofday( &now, NULL ); // if have event, sent frames until we find a video packet, at which point do analysis. Adaptive skip should only affect which frames we do analysis on. @@ -1240,15 +1238,38 @@ bool Monitor::Analyse() { } } + // If do have an event, then analysis_it should point to the head of the queue, because we would have emptied it on event creation. unsigned int index = ( shared_data->last_read_index + 1 ) % image_buffer_count; + + if ( ! packetqueue.size() ) { + Debug(2, "PacketQueue is empty" ); + return false; + } + Debug(2, "PacketQueue size (%d)", packetqueue.size() ); + + // The idea is that iterator_id never gets to the end. + +// analysis_it is == end when queue is empty? Debug(2, "Analysis index (%d), last_Write(%d)", index, shared_data->last_write_index ); if ( analysis_it == packetqueue.pktQueue.end() ) { - Debug(2, "Analysis index (%d), last_Write(%d), at end of queue", index, shared_data->last_write_index ); + Debug(2, "Analysis index (%d), last_Write(%d), at end of queue", index, shared_data->last_write_index ); + analysis_it = packetqueue.pktQueue.begin(); + return false; } + std::list::iterator next_it = analysis_it; + Debug(2, "next_it (%x)", next_it ); + ++next_it; + + struct timeval now; + gettimeofday( &now, NULL ); + int packets_processed = 0; // Move to next packet. - while ( ( index != shared_data->last_write_index ) && ( *analysis_it != packetqueue.pktQueue.back() ) ) { - ++analysis_it; + while ( ( index != shared_data->last_write_index ) && ( next_it != packetqueue.pktQueue.end() ) ) { + analysis_it = next_it; + ++next_it; + Debug(2, "Analysis index (%d), last_Write(%d), *it: (%x) (%d)", index, shared_data->last_write_index, *analysis_it, (*analysis_it)->image_index ); + packets_processed += 1; ZMPacket *snap = *analysis_it; struct timeval *timestamp = snap->timestamp; @@ -1408,12 +1429,13 @@ bool Monitor::Analyse() { shared_data->last_event_id = event->Id(); mutex.lock(); std::list::iterator it = packetqueue.pktQueue.begin(); - while( packetqueue.size() && it != analysis_it ) { + while( packetqueue.size() && ( it != analysis_it ) ) { ZMPacket *queued_packet = packetqueue.popPacket(); event->AddPacket( queued_packet ); if ( queued_packet->image_index == -1 ) { delete queued_packet; } + it = packetqueue.pktQueue.begin(); } mutex.unlock(); // The analysis packet will be added below. @@ -1507,6 +1529,8 @@ bool Monitor::Analyse() { if ( !(image_count%(frame_skip+1)) ) { mutex.lock(); ZMPacket *pack = packetqueue.popPacket(); +Debug(2,"adding packet (%x)", pack ); +Debug(2,"adding packet (%x) (%d)", pack, pack->image_index ); mutex.unlock(); if ( config.bulk_frame_interval > 1 ) { event->AddPacket( pack, (event->Frames() 0 ) return true; +return false; } void Monitor::Reload() { @@ -2830,11 +2855,6 @@ int Monitor::Capture() { Debug(2, "Have video packet"); packet->codec_type = camera->get_VideoStream()->codecpar->codec_type; - // Have an av_packet, - if ( packetqueue.video_packet_count || ( packet->packet.flags & AV_PKT_FLAG_KEY ) || event ) { - Debug(2, "Queueing packet"); - packetqueue.queuePacket( packet ); - } if ( packet->packet.size && ! packet->in_frame ) { Debug(2,"About to decode"); @@ -2842,6 +2862,15 @@ int Monitor::Capture() { Debug(2,"Getimage"); packet->get_image(); } + // Have an av_packet, + if ( packetqueue.video_packet_count || ( packet->packet.flags & AV_PKT_FLAG_KEY ) || event ) { + Debug(2, "Queueing packet"); + packetqueue.queuePacket( packet ); + } + } else { + // Non-avpackets are all keyframes. + Debug(2, "Queueing packet"); + packetqueue.queuePacket( packet ); } /* Deinterlacing */ @@ -3206,9 +3235,10 @@ bool Monitor::DumpSettings( char *output, bool verbose ) { unsigned int Monitor::Colours() const { return( camera->Colours() ); } unsigned int Monitor::SubpixelOrder() const { return( camera->SubpixelOrder() ); } + int Monitor::PrimeCapture() { int ret = camera->PrimeCapture(); - video_stream_id = ret ? camera->get_VideoStreamId() : -1; + video_stream_id = ret ? -1 : camera->get_VideoStreamId(); Debug(2, "Video stream id is (%d)", video_stream_id ); return ret; } From f0ffa34c4d766e726a08c78948959add7d3c8e20 Mon Sep 17 00:00:00 2001 From: APHW2 MFGENG Date: Tue, 28 Nov 2017 12:58:20 -0800 Subject: [PATCH 0057/2339] set videostreamid --- src/zm_remote_camera_nvsocket.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/zm_remote_camera_nvsocket.cpp b/src/zm_remote_camera_nvsocket.cpp index ae5eb3faa..d6e7c7401 100644 --- a/src/zm_remote_camera_nvsocket.cpp +++ b/src/zm_remote_camera_nvsocket.cpp @@ -183,6 +183,7 @@ int RemoteCameraNVSocket::PrimeCapture() { Disconnect(); return -1; } + mVideoStreamId=0; return 0; } From 84c901a01b4142203b65aa7e5de8231028bd3b1c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 30 Nov 2017 15:01:48 -0500 Subject: [PATCH 0058/2339] don't write non-frames --- src/zm_event.cpp | 4 ++-- src/zm_videostore.cpp | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index dab9af809..0997c9a3f 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -429,8 +429,8 @@ void Event::AddFramesInternal( int n_frames, int start_frame, Image **images, st void Event::AddPacket( ZMPacket *packet, int score, Image *alarm_image ) { - if ( videoStore ) { have_video_keyframe = have_video_keyframe || ( packet->codec_type == AVMEDIA_TYPE_VIDEO && ( packet->packet.flags & AV_PKT_FLAG_KEY ) ); + if ( videoStore ) { if ( have_video_keyframe ) { videoStore->writePacket( packet ); } else { @@ -438,7 +438,7 @@ void Event::AddPacket( ZMPacket *packet, int score, Image *alarm_image ) { } //FIXME if it fails, we should write a jpeg } - if ( packet->codec_type == AVMEDIA_TYPE_VIDEO ) { + if ( have_video_keyframe && ( packet->codec_type == AVMEDIA_TYPE_VIDEO ) ) { AddFrame( packet->image, *packet->timestamp, score, alarm_image ); } // end if is video return; diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 4bdd5430a..500dd380d 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -786,6 +786,7 @@ bool VideoStore::setup_resampler() { return false; } #endif + audio_out_stream->time_base = (AVRational){1, audio_out_ctx->sample_rate}; AVDictionary *opts = NULL; av_dict_set(&opts, "strict", "experimental", 0); // Needed to allow AAC From c52d7c60eb2c43064d2c44695cc29c2e23d6c90e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 30 Nov 2017 15:19:31 -0500 Subject: [PATCH 0059/2339] finish deprecating zma --- src/CMakeLists.txt | 10 +-- src/zm_ffmpeg_camera.cpp | 7 ++ src/zma.cpp | 183 --------------------------------------- 3 files changed, 11 insertions(+), 189 deletions(-) delete mode 100644 src/zma.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 46bffac74..838d0e3d2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,28 +3,26 @@ # Create files from the .in files 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) +# Group together all the source files that are used by all the binaries (zmc, zmu, zms etc) set(ZM_BIN_SRC_FILES zm_analysis_thread.cpp 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_eventstream.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_monitorstream.cpp zm_ffmpeg.cpp zm_ffmpeg_input.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_nvsocket.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_swscale.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 zm_storage.cpp) # A fix for cmake recompiling the source files for every target. 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(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(zms zm ${ZM_EXTRA_LIBS} ${ZM_BIN_LIBS}) # Generate man files for the binaries destined for the bin folder -FOREACH(CBINARY zma zmc zmu) +FOREACH(CBINARY zmc zmu) POD2MAN(${CMAKE_CURRENT_SOURCE_DIR}/${CBINARY}.cpp zoneminder-${CBINARY} 8) -ENDFOREACH(CBINARY zma zmc zmu) +ENDFOREACH(CBINARY zmc zmu) -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 zmc 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}") diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index f99e56561..b562125d3 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -245,7 +245,14 @@ int FfmpegCamera::OpenFfmpeg() { Debug ( 1, "Calling avformat_open_input for %s", mPath.c_str() ); + last_event_id = monitor->GetLastEventId() ; + video_writer_event_id = monitor->GetVideoWriterEventId(); + Debug(2, "last_event(%d), our current (%d), mpath (%s)", last_event_id, video_writer_event_id, mPath.c_str() ); mFormatContext = avformat_alloc_context( ); + + last_event_id = monitor->GetLastEventId() ; + video_writer_event_id = monitor->GetVideoWriterEventId(); + Debug(2, "last_event(%d), our current (%d), mpath (%s)", last_event_id, video_writer_event_id, mPath.c_str() ); //mFormatContext->interrupt_callback.callback = FfmpegInterruptCallback; //mFormatContext->interrupt_callback.opaque = this; // Speed up find_stream_info diff --git a/src/zma.cpp b/src/zma.cpp deleted file mode 100644 index 9f49cdd76..000000000 --- a/src/zma.cpp +++ /dev/null @@ -1,183 +0,0 @@ -// -// ZoneMinder Analysis Daemon, $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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// - -/* - -=head1 NAME - -zma - The ZoneMinder Analysis daemon - -=head1 SYNOPSIS - - zma -m - zma --monitor - zma -h - zma --help - zma -v - zma --version - -=head1 DESCRIPTION - -This is the component that goes through the captured frames and checks them -for motion which might generate an alarm or event. It generally keeps up with -the Capture daemon but if very busy may skip some frames to prevent it falling -behind. - -=head1 OPTIONS - - -m, --monitor_id - ID of the monitor to analyse - -h, --help - Display usage information - -v, --version - Print the installed version of ZoneMinder - -=cut - -*/ - -#include -#include - -#include "zm.h" -#include "zm_db.h" -#include "zm_signal.h" -#include "zm_monitor.h" - -void Usage() { - fprintf( stderr, "zma -m \n" ); - fprintf( stderr, "Options:\n" ); - fprintf( stderr, " -m, --monitor : Specify which monitor to use\n" ); - fprintf( stderr, " -h, --help : This screen\n" ); - fprintf( stderr, " -v, --version : Report the installed version of ZoneMinder\n" ); - exit( 0 ); -} - -int main( int argc, char *argv[] ) { - self = argv[0]; - - srand( getpid() * time( 0 ) ); - - int id = -1; - - static struct option long_options[] = { - {"monitor", 1, 0, 'm'}, - {"help", 0, 0, 'h'}, - {"version", 0, 0, 'v'}, - {0, 0, 0, 0} - }; - - while (1) { - int option_index = 0; - - int c = getopt_long (argc, argv, "m:h:v", long_options, &option_index); - if ( c == -1 ) { - break; - } - - switch (c) { - case 'm': - id = atoi(optarg); - break; - case 'h': - case '?': - Usage(); - break; - case 'v': - std::cout << ZM_VERSION << "\n"; - exit(0); - default: - //fprintf( stderr, "?? getopt returned character code 0%o ??\n", c ); - break; - } - } - - if (optind < argc) { - fprintf( stderr, "Extraneous options, " ); - while (optind < argc) - printf ("%s ", argv[optind++]); - printf ("\n"); - Usage(); - } - - if ( id < 0 ) { - fprintf( stderr, "Bogus monitor %d\n", id ); - Usage(); - exit( 0 ); - } - - char log_id_string[16]; - snprintf( log_id_string, sizeof(log_id_string), "zma_m%d", id ); - - zmLoadConfig(); - - logInit( log_id_string ); - - hwcaps_detect(); - - Monitor *monitor = Monitor::Load( id, true, Monitor::ANALYSIS ); - - if ( monitor ) { - Info( "In mode %d/%d, warming up", monitor->GetFunction(), monitor->Enabled() ); - - zmSetDefaultHupHandler(); - zmSetDefaultTermHandler(); - zmSetDefaultDieHandler(); - - sigset_t block_set; - sigemptyset( &block_set ); - - useconds_t analysis_rate = monitor->GetAnalysisRate(); - unsigned int analysis_update_delay = monitor->GetAnalysisUpdateDelay(); - time_t last_analysis_update_time, cur_time; - monitor->UpdateAdaptiveSkip(); - last_analysis_update_time = time( 0 ); - - while( !zm_terminate ) { - // Process the next image - sigprocmask( SIG_BLOCK, &block_set, 0 ); - - // Some periodic updates are required for variable capturing framerate - if ( analysis_update_delay ) { - cur_time = time( 0 ); - if ( (unsigned int)( cur_time - last_analysis_update_time ) > analysis_update_delay ) { - analysis_rate = monitor->GetAnalysisRate(); - monitor->UpdateAdaptiveSkip(); - last_analysis_update_time = cur_time; - } - } - - if ( !monitor->Analyse() ) { - usleep( monitor->Active()?ZM_SAMPLE_RATE:ZM_SUSPENDED_RATE ); - } else if ( analysis_rate ) { - usleep( analysis_rate ); - } - - if ( zm_reload ) { - monitor->Reload(); - zm_reload = false; - } - sigprocmask( SIG_UNBLOCK, &block_set, 0 ); - } - delete monitor; - } else { - fprintf( stderr, "Can't find monitor with id of %d\n", id ); - } - Image::Deinitialise(); - logTerm(); - zmDbClose(); - return( 0 ); -} From 556c4d8851792c9b4d4e4e147ee9057ead4fea27 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 30 Nov 2017 16:10:30 -0500 Subject: [PATCH 0060/2339] debug --- src/zm_analysis_thread.cpp | 4 ++++ src/zm_ffmpeg_camera.cpp | 44 +++++++++++++------------------------- src/zm_monitor.cpp | 4 +++- src/zm_thread.cpp | 1 + 4 files changed, 23 insertions(+), 30 deletions(-) diff --git a/src/zm_analysis_thread.cpp b/src/zm_analysis_thread.cpp index 261f0e18f..94ed09d03 100644 --- a/src/zm_analysis_thread.cpp +++ b/src/zm_analysis_thread.cpp @@ -11,11 +11,15 @@ AnalysisThread::~AnalysisThread() { } int AnalysisThread::run() { + Debug(2, "In run"); useconds_t analysis_rate = monitor->GetAnalysisRate(); + Debug(2, "after getanalysisrate"); unsigned int analysis_update_delay = monitor->GetAnalysisUpdateDelay(); + Debug(2, "after getanalysisUpdateDelay"); time_t last_analysis_update_time, cur_time; monitor->UpdateAdaptiveSkip(); + Debug(2, "after UpdateAdaptiveSkip"); last_analysis_update_time = time(0); Debug(2, "THREAD: Getting ref image"); diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index b562125d3..4f9f42fea 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -206,10 +206,6 @@ int FfmpegCamera::PostCapture() { int FfmpegCamera::OpenFfmpeg() { Debug ( 2, "OpenFfmpeg called." ); - uint32_t last_event_id = monitor->GetLastEventId() ; - uint32_t video_writer_event_id = monitor->GetVideoWriterEventId(); - Debug(2, "last_event(%d), our current (%d)", last_event_id, video_writer_event_id ); - int ret; mOpenStart = time(NULL); @@ -221,10 +217,12 @@ int FfmpegCamera::OpenFfmpeg() { if ( av_open_input_file( &mFormatContext, mPath.c_str(), NULL, 0, NULL ) != 0 ) #else // Handle options - AVDictionary *opts = 0; + AVDictionary *opts = NULL; ret = av_dict_parse_string(&opts, Options().c_str(), "=", ",", 0); if ( ret < 0 ) { - Warning("Could not parse ffmpeg input options list '%s'\n", Options().c_str()); + Warning("Could not parse ffmpeg input options list '%s'", Options().c_str()); + } else { + Debug(2,"Could not parse ffmpeg input options list '%s'", Options().c_str()); } // Set transport method as specified by method field, rtpUni is default @@ -243,25 +241,12 @@ int FfmpegCamera::OpenFfmpeg() { Warning("Could not set rtsp_transport method '%s'\n", method.c_str()); } - Debug ( 1, "Calling avformat_open_input for %s", mPath.c_str() ); + Debug ( 1, "Calling avformat_alloc_context for %s", mPath.c_str() ); - last_event_id = monitor->GetLastEventId() ; - video_writer_event_id = monitor->GetVideoWriterEventId(); - Debug(2, "last_event(%d), our current (%d), mpath (%s)", last_event_id, video_writer_event_id, mPath.c_str() ); mFormatContext = avformat_alloc_context( ); - last_event_id = monitor->GetLastEventId() ; - video_writer_event_id = monitor->GetVideoWriterEventId(); - Debug(2, "last_event(%d), our current (%d), mpath (%s)", last_event_id, video_writer_event_id, mPath.c_str() ); - //mFormatContext->interrupt_callback.callback = FfmpegInterruptCallback; - //mFormatContext->interrupt_callback.opaque = this; - // Speed up find_stream_info - //FIXME can speed up initial analysis but need sensible parameters... - //mFormatContext->probesize = 32; - //mFormatContext->max_analyze_duration = 32; - last_event_id = monitor->GetLastEventId() ; - video_writer_event_id = monitor->GetVideoWriterEventId(); - Debug(2, "last_event(%d), our current (%d), mpath (%s)", last_event_id, video_writer_event_id, mPath.c_str() ); + monitor->GetLastEventId() ; + Debug(2, "before avformat_open_input" ); if ( avformat_open_input( &mFormatContext, mPath.c_str(), NULL, &opts ) != 0 ) #endif @@ -270,15 +255,15 @@ int FfmpegCamera::OpenFfmpeg() { Error( "Unable to open input %s due to: %s", mPath.c_str(), strerror(errno) ); return -1; } + Debug(2, "afte avformat_open_input" ); + monitor->GetLastEventId() ; AVDictionaryEntry *e = NULL; while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { Warning( "Option %s not recognized by ffmpeg", e->key); } - last_event_id = monitor->GetLastEventId() ; - video_writer_event_id = monitor->GetVideoWriterEventId(); - Debug(2, "last_event(%d), our current (%d)", last_event_id, video_writer_event_id ); + monitor->GetLastEventId() ; mIsOpening = false; Debug ( 1, "Opened input" ); @@ -397,12 +382,13 @@ int FfmpegCamera::OpenFfmpeg() { } else { Debug(1, "Video Found decoder"); zm_dump_stream_format(mFormatContext, mVideoStreamId, 0, 0); - // Open the codec + + // Open the codec #if !LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 8, 0) - Debug ( 1, "Calling avcodec_open" ); - if ( avcodec_open(mVideoCodecContext, mVideoCodec) < 0 ){ + Debug ( 1, "Calling avcodec_open" ); + if ( avcodec_open(mVideoCodecContext, mVideoCodec) < 0 ){ #else - Debug ( 1, "Calling avcodec_open2" ); + Debug ( 1, "Calling video avcodec_open2" ); if ( avcodec_open2(mVideoCodecContext, mVideoCodec, &opts) < 0 ) { #endif AVDictionaryEntry *e = NULL; diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 2b2af06b9..8fe1e0d1e 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -769,10 +769,11 @@ uint32_t Monitor::GetLastEventId() const { // This function is crap. double Monitor::GetFPS() const { int index1 = shared_data->last_write_index; - if ( index1 == image_buffer_count ) { + if ( index1 >= image_buffer_count ) { // last_write_index only has this value on startup before capturing anything. return 0.0; } + Debug(2, "index1(%d)", index1); ZMPacket *snap1 = &image_buffer[index1]; if ( !snap1->timestamp->tv_sec ) { // This should be impossible @@ -783,6 +784,7 @@ double Monitor::GetFPS() const { int image_count = image_buffer_count; int index2 = (index1+1)%image_buffer_count; + Debug(2, "index2(%d)", index2); ZMPacket *snap2 = &image_buffer[index2]; // the timestamp pointers are initialized on connection, so that's redundant // tv_sec is probably only zero during the first loop of capturing, so this basically just counts the unused images. diff --git a/src/zm_thread.cpp b/src/zm_thread.cpp index 1232ac5f0..fe0b9ecb1 100644 --- a/src/zm_thread.cpp +++ b/src/zm_thread.cpp @@ -263,6 +263,7 @@ void *Thread::mThreadFunc( void *arg ) thisPtr->mThreadCondition.signal(); thisPtr->mThreadMutex.unlock(); thisPtr->mRunning = true; + Debug(2,"Runnning"); thisPtr->status = thisPtr->run(); thisPtr->mRunning = false; Debug( 2, "Exiting thread, status %p", (void *)&(thisPtr->status) ); From 4cc5838c66778816b74ba6c57f32b4ae51515083 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 30 Nov 2017 19:26:51 -0500 Subject: [PATCH 0061/2339] whitespace & cleanup --- src/zm_videostore.cpp | 174 +++++++++++++++++++++++++----------------- 1 file changed, 102 insertions(+), 72 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 3356466bb..7b964eead 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -62,7 +62,7 @@ VideoStore::VideoStore( // Couldn't deduce format from filename, trying from format name if ( !oc ) { avformat_alloc_output_context2(&oc, NULL, format, filename); - if (!oc) { + if ( !oc ) { Fatal( "Could not create video storage stream %s as no out ctx" " could not be assigned based on filename or format %s", @@ -70,13 +70,12 @@ VideoStore::VideoStore( } else { Debug(4, "Success alocating out ctx"); } - } // end if ! oc + } // end if ! oc Debug(2, "Success opening output contect"); AVDictionary *pmetadata = NULL; - int dsr = av_dict_set(&pmetadata, "title", "Zoneminder Security Recording", 0); - if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__); - Debug(2, "Success setting up dictcontect"); + ret = av_dict_set(&pmetadata, "title", "Zoneminder Security Recording", 0); + if ( ret < 0 ) Warning("%s:%d: title set failed", __FILE__, __LINE__); oc->metadata = pmetadata; out_format = oc->oformat; @@ -87,14 +86,12 @@ VideoStore::VideoStore( #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) video_in_ctx = avcodec_alloc_context3(NULL); Debug(2, "copy to video_in_context"); - avcodec_parameters_to_context(video_in_ctx, - video_in_stream->codecpar); + avcodec_parameters_to_context(video_in_ctx, video_in_stream->codecpar); zm_dump_codecpar( video_in_stream->codecpar ); -//video_in_ctx.codec_id = video_in_stream->codecpar.codec_id; #else video_in_ctx = video_in_stream->codec; -Debug(2,"Copied video context from input stream"); - zm_dump_codec(video_in_ctx); + Debug(2,"Copied video context from input stream"); + zm_dump_codec(video_in_ctx); #endif // Fix deprecated formats switch ( video_in_ctx->pix_fmt ) { @@ -124,8 +121,7 @@ Debug(2,"Copied video context from input stream"); // Copy params from instream to ctx if ( video_in_stream && ( video_in_ctx->codec_id == AV_CODEC_ID_H264 ) ) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - ret = avcodec_parameters_to_context(video_out_ctx, - video_in_stream->codecpar); + ret = avcodec_parameters_to_context(video_out_ctx, video_in_stream->codecpar); if ( ret < 0 ) { Error("Could not initialize ctx parameteres"); return; @@ -155,6 +151,13 @@ Debug(2,"Copied video context from input stream"); Warning("Unsupported Orientation(%d)", orientation); } } + if ( oc->oformat->flags & AVFMT_GLOBALHEADER ) { +#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) + video_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; +#else + video_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; +#endif + } // Fix deprecated formats switch ( video_out_ctx->pix_fmt ) { case AV_PIX_FMT_YUVJ420P : @@ -192,11 +195,12 @@ Debug(2,"Copied video context from input stream"); video_out_ctx->width = monitor->Width(); video_out_ctx->height = monitor->Height(); video_out_ctx->codec_type = AVMEDIA_TYPE_VIDEO; - if (oc->oformat->flags & AVFMT_GLOBALHEADER) { + + if ( oc->oformat->flags & AVFMT_GLOBALHEADER ) { #if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) - video_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; + video_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; #else - video_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; + video_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; #endif } @@ -222,8 +226,6 @@ Debug(2,"Copied video context from input stream"); video_out_ctx->codec_id = AV_CODEC_ID_H264; //video_in_ctx->sample_aspect_ratio; - /* take first format from list of supported formats */ - //video_out_ctx->pix_fmt = video_out_codec->pix_fmts[0]; video_out_ctx->pix_fmt = AV_PIX_FMT_YUV420P; /* video time_base can be set to whatever is handy and supported by encoder */ video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate @@ -384,7 +386,7 @@ Error("Codec not set"); 0); Debug(2, "Got something other than AAC (%s)", error_buffer); - if (!setup_resampler()) { + if ( !setup_resampler() ) { return; } } else { @@ -396,7 +398,7 @@ Error("Codec not set"); #else avformat_new_stream(oc, (AVCodec *)audio_in_ctx->codec); #endif - if (!audio_out_stream) { + if ( !audio_out_stream ) { Error("Unable to create audio out stream\n"); audio_out_stream = NULL; } else { @@ -405,37 +407,33 @@ Error("Codec not set"); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) audio_out_ctx = avcodec_alloc_context3(audio_out_codec); // Copy params from instream to ctx - ret = avcodec_parameters_to_context(audio_out_ctx, - audio_in_stream->codecpar); - if (ret < 0) { + if ( (ret = avcodec_parameters_to_context(audio_out_ctx, audio_in_stream->codecpar) ) < 0 ) { Error("Unable to copy audio params to ctx %s\n", av_make_error_string(ret).c_str()); } - ret = avcodec_parameters_from_context(audio_out_stream->codecpar, - audio_out_ctx); - if (ret < 0) { + // Then from ctx to out_stream + ret = avcodec_parameters_from_context(audio_out_stream->codecpar, audio_out_ctx); + if ( ret < 0 ) { Error("Unable to copy audio params to stream %s\n", av_make_error_string(ret).c_str()); } - if (!audio_out_ctx->codec_tag) { + if ( !audio_out_ctx->codec_tag ) { audio_out_ctx->codec_tag = av_codec_get_tag( oc->oformat->codec_tag, audio_in_ctx->codec_id); - Debug(2, "Setting audio codec tag to %d", - audio_out_ctx->codec_tag); + Debug(2, "Setting audio codec tag to %d", audio_out_ctx->codec_tag); } - #else audio_out_ctx = audio_out_stream->codec; ret = avcodec_copy_context(audio_out_ctx, audio_in_ctx); audio_out_ctx->codec_tag = 0; #endif - if (ret < 0) { + if ( ret < 0 ) { Error("Unable to copy audio ctx %s\n", av_make_error_string(ret).c_str()); audio_out_stream = NULL; } else { - if (audio_out_ctx->channels > 1) { + if ( audio_out_ctx->channels > 1 ) { Warning("Audio isn't mono, changing it."); audio_out_ctx->channels = 1; } else { @@ -477,15 +475,12 @@ bool VideoStore::open() { } } - // os->ctx_inited = 1; - // avio_flush(ctx->pb); - // av_dict_free(&opts); zm_dump_stream_format(oc, 0, 0, 1); if (audio_out_stream) zm_dump_stream_format(oc, 1, 0, 1); AVDictionary *opts = NULL; // av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0); - av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0); + av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0); // av_dict_set(&opts, "movflags", // "frag_keyframe+empty_moov+default_base_moof", 0); if ( (ret = avformat_write_header(oc, &opts)) < 0 ) { @@ -511,10 +506,11 @@ void VideoStore::write_audio_packet( AVPacket &pkt ) { pkt.pts = audio_next_pts; pkt.dts = audio_next_dts; - if (pkt.duration > 0) + if ( pkt.duration > 0 ) { pkt.duration = av_rescale_q(pkt.duration, audio_out_ctx->time_base, audio_out_stream->time_base); + } audio_next_pts += pkt.duration; audio_next_dts += pkt.duration; @@ -525,20 +521,23 @@ void VideoStore::write_audio_packet( AVPacket &pkt ) { } VideoStore::~VideoStore() { - if ( video_out_ctx->codec_id != video_in_ctx->codec_id ) { + if ( video_out_ctx->codec_id != video_in_ctx->codec_id || audio_out_codec ) { Debug(2,"Different codecs between in and out"); + // The codec queues data. We need to send a flush command and out + // whatever we get. Failures are not fatal. + AVPacket pkt; + // WIthout these we seg fault I don't know why. + pkt.data = NULL; + pkt.size = 0; + av_init_packet(&pkt); +// I got crashes if the codec didn't do DELAY, so let's test for it. #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) if ( video_out_ctx->codec && ( video_out_ctx->codec->capabilities & AV_CODEC_CAP_DELAY ) ) { #else if ( video_out_ctx->codec && ( video_out_ctx->codec->capabilities & CODEC_CAP_DELAY ) ) { #endif - // The codec queues data. We need to send a flush command and out - // whatever we get. Failures are not fatal. - AVPacket pkt; - av_init_packet(&pkt); - #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) // Put encoder into flushing mode avcodec_send_frame(video_out_ctx, NULL); @@ -552,40 +551,36 @@ Debug(2,"Different codecs between in and out"); break; } #else - while (1) { - // WIthout these we seg fault I don't know why. - pkt.data = NULL; - pkt.size = 0; - av_init_packet(&pkt); - int got_packet = 0; - ret = avcodec_encode_video2(video_out_ctx, &pkt, NULL, &got_packet); - if ( ret < 0 ) { - Error("ERror encoding video while flushing (%d) (%s)", ret, - av_err2str(ret)); - break; - } - if (!got_packet) { - break; - } + while (1) { + // WIthout these we seg fault I don't know why. + pkt.data = NULL; + pkt.size = 0; + av_init_packet(&pkt); + int got_packet = 0; + ret = avcodec_encode_video2(video_out_ctx, &pkt, NULL, &got_packet); + if ( ret < 0 ) { + Error("ERror encoding video while flushing (%d) (%s)", ret, + av_err2str(ret)); + break; + } + if (!got_packet) { + break; + } #endif - int keyframe = pkt.flags & AV_PKT_FLAG_KEY; -Debug(3, "dts:%d, pts:%d, keyframe:%d", pkt.dts, pkt.pts, keyframe ); - //pkt.dts = video_next_dts; - pkt.pts = pkt.dts; - //pkt.duration = video_last_duration; - write_video_packet(pkt); - zm_av_packet_unref(&pkt); - } // while have buffered frames - } // end if have delay capability + int keyframe = pkt.flags & AV_PKT_FLAG_KEY; + Debug(3, "dts:%d, pts:%d, keyframe:%d", pkt.dts, pkt.pts, keyframe ); + //pkt.dts = video_next_dts; + pkt.pts = pkt.dts; + //pkt.duration = video_last_duration; + write_video_packet(pkt); + zm_av_packet_unref(&pkt); + } // while have buffered frames + } // end if have delay capability } // end if have buffered video if ( audio_out_codec ) { // The codec queues data. We need to send a flush command and out // whatever we get. Failures are not fatal. - AVPacket pkt; - // WIthout these we seg fault I don't know why. - pkt.data = NULL; - pkt.size = 0; av_init_packet(&pkt); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) @@ -593,6 +588,42 @@ Debug(3, "dts:%d, pts:%d, keyframe:%d", pkt.dts, pkt.pts, keyframe ); avcodec_send_frame(audio_out_ctx, NULL); while (1) { ret = avcodec_receive_packet(audio_out_ctx, &pkt); + // WIthout these we seg fault I don't know why. + pkt.data = NULL; + pkt.size = 0; + // WIthout these we seg fault I don't know why. + pkt.data = NULL; + pkt.size = 0; + // WIthout these we seg fault I don't know why. + pkt.data = NULL; + pkt.size = 0; + // WIthout these we seg fault I don't know why. + pkt.data = NULL; + pkt.size = 0; + // WIthout these we seg fault I don't know why. + pkt.data = NULL; + pkt.size = 0; + // WIthout these we seg fault I don't know why. + pkt.data = NULL; + pkt.size = 0; + // WIthout these we seg fault I don't know why. + pkt.data = NULL; + pkt.size = 0; + // WIthout these we seg fault I don't know why. + pkt.data = NULL; + pkt.size = 0; + // WIthout these we seg fault I don't know why. + pkt.data = NULL; + pkt.size = 0; + // WIthout these we seg fault I don't know why. + pkt.data = NULL; + pkt.size = 0; + // WIthout these we seg fault I don't know why. + pkt.data = NULL; + pkt.size = 0; + // WIthout these we seg fault I don't know why. + pkt.data = NULL; + pkt.size = 0; if (ret < 0) { if (AVERROR_EOF != ret) { Error("ERror encoding audio while flushing (%d) (%s)", ret, @@ -700,8 +731,7 @@ bool VideoStore::setup_resampler() { audio_in_ctx->codec_id #endif ); - ret = avcodec_open2(audio_in_ctx, audio_in_codec, NULL); - if (ret < 0) { + if ( (ret = avcodec_open2(audio_in_ctx, audio_in_codec, NULL)) < 0 ) { Error("Can't open in codec!"); return false; } From 4e26bde140dcb8146079b2f4855cb17d7235ad4c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 30 Nov 2017 22:18:02 -0500 Subject: [PATCH 0062/2339] merge fix --- src/zm_videostore.cpp | 65 +++++++++---------------------------------- 1 file changed, 13 insertions(+), 52 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index b8eb6b947..779d0e46b 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -508,6 +508,7 @@ void VideoStore::write_audio_packet( AVPacket &pkt ) { pkt.pts = audio_next_pts; pkt.dts = audio_next_dts; + Debug(2, "writing audio packet pts(%d) dts(%d) duration(%d)", pkt.pts, pkt.dts, pkt.duration); if ( pkt.duration > 0 ) { pkt.duration = av_rescale_q(pkt.duration, audio_out_ctx->time_base, @@ -516,11 +517,10 @@ void VideoStore::write_audio_packet( AVPacket &pkt ) { audio_next_pts += pkt.duration; audio_next_dts += pkt.duration; - Debug(2, "writing audio packet pts(%d) dts(%d) duration(%d)", pkt.pts, - pkt.dts, pkt.duration); + Debug(2, "writing audio packet pts(%d) dts(%d) duration(%d)", pkt.pts, pkt.dts, pkt.duration); pkt.stream_index = audio_out_stream->index; av_interleaved_write_frame(oc, &pkt); -} +} // end void VideoStore::Write_audio_packet( AVPacket &pkt ) VideoStore::~VideoStore() { if ( video_out_ctx->codec_id != video_in_ctx->codec_id || audio_out_codec ) { @@ -589,58 +589,17 @@ Debug(2,"Different codecs between in and out"); // Put encoder into flushing mode avcodec_send_frame(audio_out_ctx, NULL); while (1) { - ret = avcodec_receive_packet(audio_out_ctx, &pkt); - // WIthout these we seg fault I don't know why. - pkt.data = NULL; - pkt.size = 0; - // WIthout these we seg fault I don't know why. - pkt.data = NULL; - pkt.size = 0; - // WIthout these we seg fault I don't know why. - pkt.data = NULL; - pkt.size = 0; - // WIthout these we seg fault I don't know why. - pkt.data = NULL; - pkt.size = 0; - // WIthout these we seg fault I don't know why. - pkt.data = NULL; - pkt.size = 0; - // WIthout these we seg fault I don't know why. - pkt.data = NULL; - pkt.size = 0; - // WIthout these we seg fault I don't know why. - pkt.data = NULL; - pkt.size = 0; - // WIthout these we seg fault I don't know why. - pkt.data = NULL; - pkt.size = 0; - // WIthout these we seg fault I don't know why. - pkt.data = NULL; - pkt.size = 0; - // WIthout these we seg fault I don't know why. - pkt.data = NULL; - pkt.size = 0; - // WIthout these we seg fault I don't know why. - pkt.data = NULL; - pkt.size = 0; - // WIthout these we seg fault I don't know why. - pkt.data = NULL; - pkt.size = 0; - if (ret < 0) { + if ( (ret = avcodec_receive_packet(audio_out_ctx, &pkt) ) < 0 ) { if (AVERROR_EOF != ret) { - Error("ERror encoding audio while flushing (%d) (%s)", ret, - av_err2str(ret)); + Error("ERror encoding audio while flushing (%d) (%s)", ret, av_err2str(ret)); } break; } #else while (1) { int got_packet = 0; - ret = - avcodec_encode_audio2(audio_out_ctx, &pkt, NULL, &got_packet); - if (ret < 0) { - Error("ERror encoding audio while flushing (%d) (%s)", ret, - av_err2str(ret)); + if ( (ret = avcodec_encode_audio2(audio_out_ctx, &pkt, NULL, &got_packet)) < 0 ) { + Error("ERror encoding audio while flushing (%d) (%s)", ret, av_err2str(ret)); break; } Debug(1, "Have audio encoder, need to flush it's out"); @@ -650,14 +609,14 @@ Debug(2,"Different codecs between in and out"); #endif write_audio_packet(pkt); zm_av_packet_unref(&pkt); - } // while have buffered frames - } // end if audio_out_codec + } // while have buffered frames + } // end if audio_out_codec // Flush Queues av_interleaved_write_frame(oc, NULL); /* Write the trailer before close */ - if (int rc = av_write_trailer(oc)) { + if ( int rc = av_write_trailer(oc) ) { Error("Error writing trailer %s", av_err2str(rc)); } else { Debug(3, "Sucess Writing trailer"); @@ -780,7 +739,7 @@ bool VideoStore::setup_resampler() { if ( audio_out_codec->supported_samplerates ) { int found = 0; - for ( int i=0; audio_out_codec->supported_samplerates[i]; i++) { + for ( int i=0; audio_out_codec->supported_samplerates[i]; i++ ) { if ( audio_out_ctx->sample_rate == audio_out_codec->supported_samplerates[i]) { found = 1; @@ -815,6 +774,8 @@ bool VideoStore::setup_resampler() { Error("Could not initialize stream parameteres"); return false; } +#else + avcodec_copy_context( audio_out_stream->codec, audio_out_ctx ); #endif audio_out_stream->time_base = (AVRational){1, audio_out_ctx->sample_rate}; From 967368ce07ca472ca6d9a4d4bbbdf46049be1bb4 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 30 Nov 2017 22:18:33 -0500 Subject: [PATCH 0063/2339] testing --- src/zm_monitor.cpp | 2 +- src/zm_videostore.cpp | 22 ++++++++++++++++++++-- web/skins/classic/views/console.php | 7 +++---- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 8fe1e0d1e..9c4e2af89 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1275,7 +1275,7 @@ bool Monitor::Analyse() { Debug(2, "skipping because audio"); if ( ! packetqueue.increment_analysis_it() ) { Debug(2, "No more packets to analyse"); - break; + return false; } continue; } diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 500dd380d..2aa5785f8 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -539,6 +539,8 @@ Debug(2,"Different codecs between in and out"); // The codec queues data. We need to send a flush command and out // whatever we get. Failures are not fatal. AVPacket pkt; + pkt.data = NULL; + pkt.size = 0; av_init_packet(&pkt); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) @@ -604,6 +606,9 @@ Debug(3, "dts:%d, pts:%d, keyframe:%d", pkt.dts, pkt.pts, keyframe ); } #else while (1) { + pkt.data = NULL; + pkt.size = 0; + av_init_packet(&pkt); int got_packet = 0; ret = avcodec_encode_audio2(audio_out_ctx, &pkt, NULL, &got_packet); @@ -732,6 +737,10 @@ bool VideoStore::setup_resampler() { } Debug(2, "Have audio out codec"); + // Now copy them to the out stream + audio_out_stream = avformat_new_stream(oc, audio_out_codec); + +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) // audio_out_ctx = audio_out_stream->codec; audio_out_ctx = avcodec_alloc_context3(audio_out_codec); if ( !audio_out_ctx ) { @@ -739,6 +748,9 @@ bool VideoStore::setup_resampler() { audio_out_stream = NULL; return false; } +#else + audio_out_ctx = audio_out_stream->codec; +#endif /* put sample parameters */ audio_out_ctx->bit_rate = audio_in_ctx->bit_rate; @@ -776,8 +788,6 @@ bool VideoStore::setup_resampler() { audio_out_ctx->time_base = (AVRational){1, audio_out_ctx->sample_rate}; - // Now copy them to the out stream - audio_out_stream = avformat_new_stream(oc, audio_out_codec); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) if ( (ret = avcodec_parameters_from_context(audio_out_stream->codecpar, @@ -785,6 +795,7 @@ bool VideoStore::setup_resampler() { Error("Could not initialize stream parameteres"); return false; } + audio_out_stream->codecpar->frame_size = audio_out_ctx->frame_size; #endif audio_out_stream->time_base = (AVRational){1, audio_out_ctx->sample_rate}; @@ -807,6 +818,13 @@ bool VideoStore::setup_resampler() { audio_out_ctx->channels, audio_out_ctx->sample_fmt, audio_out_ctx->channel_layout, audio_out_ctx->frame_size); + Debug(1, + "Audio out bit_rate (%d) sample_rate(%d) channels(%d) fmt(%d) " + "layout(%d) frame_size(%d)", + audio_out_stream->codec->bit_rate, audio_out_stream->codec->sample_rate, + audio_out_stream->codec->channels, audio_out_stream->codec->sample_fmt, + audio_out_stream->codec->channel_layout, audio_out_stream->codec->frame_size); + /** Create a new frame to store the audio samples. */ if ( ! in_frame ) { if (!(in_frame = zm_av_frame_alloc())) { diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index 789c3b3ef..f2d8dc983 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -114,7 +114,6 @@ for ( $i = 0; $i < count($displayMonitors); $i++ ) { if ( $maxHeight < $scaleHeight ) $maxHeight = $scaleHeight; } $monitor['zmc'] = zmcStatus( $monitor ); - #$monitor['zma'] = zmaStatus( $monitor ); $zoneCount += $monitor['ZoneCount']; $counts = array(); @@ -189,9 +188,9 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { $dclass = 'errorText'; } else { // https://github.com/ZoneMinder/ZoneMinder/issues/1082 - if ( !$monitor['zma'] && $monitor['Function']!='Monitor' ) - $dclass = 'warnText'; - else + //if ( a'] && $monitor['Function']!='Monitor' ) + //$dclass = 'warnText'; + //else $dclass = 'infoText'; } if ( $monitor['Function'] == 'None' ) From 6e17bfefddcbe9d6abf1df9652ead6f3ae849dee Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 1 Dec 2017 10:30:58 -0500 Subject: [PATCH 0064/2339] fix printouts on 32bit --- src/zm_ffmpeg.cpp | 37 +++++++------ src/zm_thread.cpp | 123 ++++++++++++++---------------------------- src/zm_videostore.cpp | 20 +++---- 3 files changed, 70 insertions(+), 110 deletions(-) diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index e2abe03f5..d943d399b 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -106,26 +106,25 @@ static int parse_key_value_pair(AVDictionary **pm, const char **buf, return ret; } int av_dict_parse_string(AVDictionary **pm, const char *str, - const char *key_val_sep, const char *pairs_sep, - int flags) - { - if (!str) - return 0; - - /* ignore STRDUP flags */ - flags &= ~(AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL); - - while (*str) { - int ret; - if ( (ret = parse_key_value_pair(pm, &str, key_val_sep, pairs_sep, flags)) < 0) - return ret; - - if (*str) - str++; - } - - return 0; + const char *key_val_sep, const char *pairs_sep, + int flags) { + if (!str) + return 0; + + /* ignore STRDUP flags */ + flags &= ~(AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL); + + while (*str) { + int ret; + if ( (ret = parse_key_value_pair(pm, &str, key_val_sep, pairs_sep, flags)) < 0) + return ret; + + if (*str) + str++; } + + return 0; +} #endif #endif // HAVE_LIBAVUTIL diff --git a/src/zm_thread.cpp b/src/zm_thread.cpp index fe0b9ecb1..430aa55b0 100644 --- a/src/zm_thread.cpp +++ b/src/zm_thread.cpp @@ -27,8 +27,7 @@ #include #include -struct timespec getTimeout( int secs ) -{ +struct timespec getTimeout( int secs ) { struct timespec timeout; struct timeval temp_timeout; gettimeofday( &temp_timeout, 0 ); @@ -37,65 +36,56 @@ struct timespec getTimeout( int secs ) return( timeout ); } -struct timespec getTimeout( double secs ) -{ +struct timespec getTimeout( double secs ) { struct timespec timeout; struct timeval temp_timeout; gettimeofday( &temp_timeout, 0 ); timeout.tv_sec = temp_timeout.tv_sec + int(secs); timeout.tv_nsec = temp_timeout.tv_usec += (long int)(1000000000.0*(secs-int(secs))); - if ( timeout.tv_nsec > 1000000000 ) - { + if ( timeout.tv_nsec > 1000000000 ) { timeout.tv_sec += 1; timeout.tv_nsec -= 1000000000; } return( timeout ); } -Mutex::Mutex() -{ +Mutex::Mutex() { if ( pthread_mutex_init( &mMutex, NULL ) < 0 ) - throw ThreadException( stringtf( "Unable to create pthread mutex: %s", strerror(errno) ) ); + Fatal( "Unable to create pthread mutex: %s", strerror(errno) ); } -Mutex::~Mutex() -{ +Mutex::~Mutex() { if ( locked() ) Warning( "Destroying mutex when locked" ); if ( pthread_mutex_destroy( &mMutex ) < 0 ) - throw ThreadException( stringtf( "Unable to destroy pthread mutex: %s", strerror(errno) ) ); + Fatal( "Unable to destroy pthread mutex: %s", strerror(errno) ); } -void Mutex::lock() -{ +void Mutex::lock() { if ( pthread_mutex_lock( &mMutex ) < 0 ) throw ThreadException( stringtf( "Unable to lock pthread mutex: %s", strerror(errno) ) ); //Debug(3, "Lock"); } -void Mutex::lock( int secs ) -{ +void Mutex::lock( int secs ) { struct timespec timeout = getTimeout( secs ); if ( pthread_mutex_timedlock( &mMutex, &timeout ) < 0 ) throw ThreadException( stringtf( "Unable to timedlock pthread mutex: %s", strerror(errno) ) ); } -void Mutex::lock( double secs ) -{ +void Mutex::lock( double secs ) { struct timespec timeout = getTimeout( secs ); if ( pthread_mutex_timedlock( &mMutex, &timeout ) < 0 ) throw ThreadException( stringtf( "Unable to timedlock pthread mutex: %s", strerror(errno) ) ); } -void Mutex::unlock() -{ +void Mutex::unlock() { if ( pthread_mutex_unlock( &mMutex ) < 0 ) throw ThreadException( stringtf( "Unable to unlock pthread mutex: %s", strerror(errno) ) ); //Debug(3, "unLock"); } -bool Mutex::locked() -{ +bool Mutex::locked() { int state = pthread_mutex_trylock( &mMutex ); if ( state != 0 && state != EBUSY ) throw ThreadException( stringtf( "Unable to trylock pthread mutex: %s", strerror(errno) ) ); @@ -104,27 +94,23 @@ bool Mutex::locked() return( state == EBUSY ); } -Condition::Condition( Mutex &mutex ) : mMutex( mutex ) -{ +Condition::Condition( Mutex &mutex ) : mMutex( mutex ) { if ( pthread_cond_init( &mCondition, NULL ) < 0 ) - throw ThreadException( stringtf( "Unable to create pthread condition: %s", strerror(errno) ) ); + Fatal( "Unable to create pthread condition: %s", strerror(errno) ); } -Condition::~Condition() -{ +Condition::~Condition() { if ( pthread_cond_destroy( &mCondition ) < 0 ) - throw ThreadException( stringtf( "Unable to destroy pthread condition: %s", strerror(errno) ) ); + Fatal( "Unable to destroy pthread condition: %s", strerror(errno) ); } -void Condition::wait() -{ +void Condition::wait() { // Locking done outside of this function if ( pthread_cond_wait( &mCondition, mMutex.getMutex() ) < 0 ) throw ThreadException( stringtf( "Unable to wait pthread condition: %s", strerror(errno) ) ); } -bool Condition::wait( int secs ) -{ +bool Condition::wait( int secs ) { // Locking done outside of this function Debug( 8, "Waiting for %d seconds", secs ); struct timespec timeout = getTimeout( secs ); @@ -133,8 +119,7 @@ bool Condition::wait( int secs ) return( errno != ETIMEDOUT ); } -bool Condition::wait( double secs ) -{ +bool Condition::wait( double secs ) { // Locking done outside of this function struct timespec timeout = getTimeout( secs ); if ( pthread_cond_timedwait( &mCondition, mMutex.getMutex(), &timeout ) < 0 && errno != ETIMEDOUT ) @@ -142,36 +127,31 @@ bool Condition::wait( double secs ) return( errno != ETIMEDOUT ); } -void Condition::signal() -{ +void Condition::signal() { if ( pthread_cond_signal( &mCondition ) < 0 ) throw ThreadException( stringtf( "Unable to signal pthread condition: %s", strerror(errno) ) ); } -void Condition::broadcast() -{ +void Condition::broadcast() { if ( pthread_cond_broadcast( &mCondition ) < 0 ) throw ThreadException( stringtf( "Unable to broadcast pthread condition: %s", strerror(errno) ) ); } -template const T ThreadData::getValue() const -{ +template const T ThreadData::getValue() const { mMutex.lock(); const T valueCopy = mValue; mMutex.unlock(); return( valueCopy ); } -template T ThreadData::setValue( const T value ) -{ +template T ThreadData::setValue( const T value ) { mMutex.lock(); const T valueCopy = mValue = value; mMutex.unlock(); return( valueCopy ); } -template const T ThreadData::getUpdatedValue() const -{ +template const T ThreadData::getUpdatedValue() const { Debug( 8, "Waiting for value update, %p", this ); mMutex.lock(); mChanged = false; @@ -184,8 +164,7 @@ template const T ThreadData::getUpdatedValue() const return( valueCopy ); } -template const T ThreadData::getUpdatedValue( double secs ) const -{ +template const T ThreadData::getUpdatedValue( double secs ) const { Debug( 8, "Waiting for value update, %.2f secs, %p", secs, this ); mMutex.lock(); mChanged = false; @@ -198,8 +177,7 @@ template const T ThreadData::getUpdatedValue( double secs ) const return( valueCopy ); } -template const T ThreadData::getUpdatedValue( int secs ) const -{ +template const T ThreadData::getUpdatedValue( int secs ) const { Debug( 8, "Waiting for value update, %d secs, %p", secs, this ); mMutex.lock(); mChanged = false; @@ -212,8 +190,7 @@ template const T ThreadData::getUpdatedValue( int secs ) const return( valueCopy ); } -template void ThreadData::updateValueSignal( const T value ) -{ +template void ThreadData::updateValueSignal( const T value ) { Debug( 8, "Updating value with signal, %p", this ); mMutex.lock(); mValue = value; @@ -223,8 +200,7 @@ template void ThreadData::updateValueSignal( const T value ) Debug( 9, "Updated value, %p", this ); } -template void ThreadData::updateValueBroadcast( const T value ) -{ +template void ThreadData::updateValueBroadcast( const T value ) { Debug( 8, "Updating value with broadcast, %p", this ); mMutex.lock(); mValue = value; @@ -243,21 +219,18 @@ Thread::Thread() : Debug( 1, "Creating thread" ); } -Thread::~Thread() -{ +Thread::~Thread() { Debug( 1, "Destroying thread %d", mPid ); if ( mStarted ) join(); } -void *Thread::mThreadFunc( void *arg ) -{ +void *Thread::mThreadFunc( void *arg ) { Debug( 2, "Invoking thread" ); Thread *thisPtr = (Thread *)arg; thisPtr->status = 0; - try - { + try { thisPtr->mThreadMutex.lock(); thisPtr->mPid = thisPtr->id(); thisPtr->mThreadCondition.signal(); @@ -268,9 +241,7 @@ void *Thread::mThreadFunc( void *arg ) thisPtr->mRunning = false; Debug( 2, "Exiting thread, status %p", (void *)&(thisPtr->status) ); return (void *)&(thisPtr->status); - } - catch ( const ThreadException &e ) - { + } catch ( const ThreadException &e ) { Error( "%s", e.getMessage().c_str() ); thisPtr->mRunning = false; Debug( 2, "Exiting thread after exception, status %p", (void *)-1 ); @@ -278,14 +249,12 @@ void *Thread::mThreadFunc( void *arg ) } } -void Thread::start() -{ +void Thread::start() { Debug( 1, "Starting thread" ); if ( isThread() ) throw ThreadException( "Can't self start thread" ); mThreadMutex.lock(); - if ( !mStarted ) - { + if ( !mStarted ) { pthread_attr_t threadAttrs; pthread_attr_init( &threadAttrs ); pthread_attr_setscope( &threadAttrs, PTHREAD_SCOPE_SYSTEM ); @@ -294,9 +263,7 @@ void Thread::start() if ( pthread_create( &mThread, &threadAttrs, mThreadFunc, this ) < 0 ) throw ThreadException( stringtf( "Can't create thread: %s", strerror(errno) ) ); pthread_attr_destroy( &threadAttrs ); - } - else - { + } else { Error( "Attempt to start already running thread %d", mPid ); } mThreadCondition.wait(); @@ -304,37 +271,29 @@ void Thread::start() Debug( 1, "Started thread %d", mPid ); } -void Thread::join() -{ +void Thread::join() { Debug( 1, "Joining thread %d", mPid ); if ( isThread() ) throw ThreadException( "Can't self join thread" ); mThreadMutex.lock(); - if ( mPid >= 0 ) - { - if ( mStarted ) - { + if ( mPid >= 0 ) { + if ( mStarted ) { void *threadStatus = 0; if ( pthread_join( mThread, &threadStatus ) < 0 ) throw ThreadException( stringtf( "Can't join sender thread: %s", strerror(errno) ) ); mStarted = false; Debug( 1, "Thread %d exited, status %p", mPid, threadStatus ); - } - else - { + } else { Warning( "Attempt to join already finished thread %d", mPid ); } - } - else - { + } else { Warning( "Attempt to join non-started thread %d", mPid ); } mThreadMutex.unlock(); Debug( 1, "Joined thread %d", mPid ); } -void Thread::kill( int signal ) -{ +void Thread::kill( int signal ) { pthread_kill( mThread, signal ); } diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index cd28e352f..cb7908892 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -174,6 +174,7 @@ VideoStore::VideoStore( video_out_ctx->pix_fmt = AV_PIX_FMT_YUV440P; break; default: + video_out_ctx->pix_fmt = AV_PIX_FMT_YUV420P; break; } // Same codec, just copy the packets, otherwise we have to decode/encode @@ -542,7 +543,7 @@ VideoStore::~VideoStore() { } #endif int keyframe = pkt.flags & AV_PKT_FLAG_KEY; - Debug(3, "dts:%d, pts:%d, keyframe:%d", pkt.dts, pkt.pts, keyframe ); + Debug(3, "dts:%I64d, pts:%I64d, keyframe:%d", pkt.dts, pkt.pts, keyframe ); //pkt.dts = video_next_dts; pkt.pts = pkt.dts; //pkt.duration = video_last_duration; @@ -891,7 +892,7 @@ void VideoStore::dumpPacket(AVPacket *pkt) { snprintf(b, sizeof(b), " pts: %" PRId64 ", dts: %" PRId64 ", data: %p, size: %d, sindex: %d, dflags: %04x, s-pos: %" PRId64 - ", c-duration: %" PRId64 "\n", + ", duration: %" PRId64 "\n", pkt->pts, pkt->dts, pkt->data, @@ -1057,7 +1058,7 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { } opkt.duration = 0; -Debug(3, "dts:%d, pts:%d, keyframe:%d", opkt.dts, opkt.pts, opkt.flags & AV_PKT_FLAG_KEY ); +Debug(3, "dts:%" PRId64 ", pts:%" PRId64 ", keyframe:%d", opkt.dts, opkt.pts, opkt.flags & AV_PKT_FLAG_KEY ); write_video_packet( opkt ); zm_av_packet_unref(&opkt); @@ -1068,7 +1069,7 @@ void VideoStore::write_video_packet( AVPacket &opkt ) { if ( opkt.dts > opkt.pts ) { Debug(1, - "opkt.dts(%d) must be <= opkt.pts(%d). Decompression must happen " + "opkt.dts(%" PRId64 ") must be <= opkt.pts(%" PRId64 "). Decompression must happen " "before presentation.", opkt.dts, opkt.pts); opkt.dts = opkt.pts; @@ -1085,7 +1086,7 @@ void VideoStore::write_video_packet( AVPacket &opkt ) { //av_packet_rescale_ts( &opkt, video_out_ctx->time_base, video_out_stream->time_base ); Debug(1, - "writing video packet pts(%d) dts(%d) duration(%d) packet_count(%d)", + "writing video packet pts(%" PRId64 ") dts(%" PRId64 ") duration(%" PRId64 ") packet_count(%d)", opkt.pts, opkt.dts, opkt.duration, packets_written ); if ( (opkt.data == NULL) || (opkt.size < 1) ) { Warning("%s:%d: Mangled AVPacket: discarding frame", __FILE__, __LINE__); @@ -1308,7 +1309,7 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { // audio_last_dts = ipkt->dts; if ( opkt.dts > opkt.pts ) { Debug(1, - "opkt.dts(%d) must be <= opkt.pts(%d). Decompression must happen " + "opkt.dts(%" PRId64 ") must be <= opkt.pts(%" PRId64 "). Decompression must happen " "before presentation.", opkt.dts, opkt.pts); opkt.dts = opkt.pts; @@ -1317,8 +1318,8 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { //opkt.duration = out_frame ? out_frame->nb_samples : ipkt->duration; // opkt.duration = av_rescale_q(ipkt->duration, audio_in_stream->time_base, // audio_out_stream->time_base); - Debug(2, "opkt.pts (%d), opkt.dts(%d) opkt.duration = (%d)", opkt.pts, - opkt.dts, opkt.duration); + Debug(2, "opkt.pts (%" PRId64 "), opkt.dts(%" PRId64 ") opkt.duration = (%" PRId64 ")", + opkt.pts, opkt.dts, opkt.duration); // pkt.pos: byte position in stream, -1 if unknown opkt.pos = -1; @@ -1351,7 +1352,8 @@ int VideoStore::write_packets( zm_packetqueue &queue ) { 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, queue.size() ); + Debug(2, "Writing queued packet stream: %d KEY %d, remaining (%d)", + avp->stream_index, avp->flags & AV_PKT_FLAG_KEY, queue.size() ); int ret = this->writePacket( queued_packet ); if ( ret < 0 ) { //Less than zero and we skipped a frame From 128ae823312b29786094dc9156bcb3eff82e4c4e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 1 Dec 2017 10:33:10 -0500 Subject: [PATCH 0065/2339] add a debug for when in addpacket and no videostore --- src/zm_event.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index c312c4c2f..f59ce4c97 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -437,6 +437,8 @@ void Event::AddPacket( ZMPacket *packet, int score, Image *alarm_image ) { Debug(2, "No video keyframe yet, not writing"); } //FIXME if it fails, we should write a jpeg + } else { + Debug(2,"AddPacket but no videostore?!"); } if ( have_video_keyframe && ( packet->codec_type == AVMEDIA_TYPE_VIDEO ) ) { AddFrame( packet->image, *packet->timestamp, score, alarm_image ); From 2e3fda488e126e54dc04aca94e3f41c5dd46f113 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 1 Dec 2017 14:33:51 -0500 Subject: [PATCH 0066/2339] more debug --- src/zm_local_camera.cpp | 3 +-- src/zm_monitor.cpp | 57 ++++++++++++++++++++++++----------------- src/zm_monitor.h | 12 ++++++--- src/zm_videostore.cpp | 9 +++++-- 4 files changed, 50 insertions(+), 31 deletions(-) diff --git a/src/zm_local_camera.cpp b/src/zm_local_camera.cpp index a7e951be2..72aa669c8 100644 --- a/src/zm_local_camera.cpp +++ b/src/zm_local_camera.cpp @@ -1919,7 +1919,6 @@ int LocalCamera::PreCapture() { int LocalCamera::Capture( ZMPacket &zm_packet ) { // We assume that the avpacket is allocated, and just needs to be filled - Debug( 3, "Capturing" ); static uint8_t* buffer = NULL; int buffer_bytesused = 0; int capture_frame = -1; @@ -1954,7 +1953,7 @@ int LocalCamera::Capture( ZMPacket &zm_packet ) { } return -1; } - Debug(3, "Captured a frame"); + Debug(5, "Captured a frame"); v4l2_data.bufptr = &vid_buf; capture_frame = v4l2_data.bufptr->index; diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 1ac336888..18234459d 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -353,8 +353,10 @@ Monitor::Monitor( event_count = 0; image_count = 0; analysis_image_count = 0; + + // How many frames we need to have before we start analysing ready_count = warmup_count; - first_alarm_count = 0; + last_alarm_count = 0; state = IDLE; last_signal = false; @@ -411,6 +413,7 @@ Monitor::Monitor( } memset( mem_ptr, 0, mem_size ); shared_data->size = sizeof(SharedData); + Debug( 1, "shared.size=%d", shared_data->size ); shared_data->active = enabled; shared_data->signal = false; shared_data->state = IDLE; @@ -451,7 +454,8 @@ Monitor::Monitor( start_time = last_fps_time = time( 0 ); event = 0; - last_section_mod =0; + last_section_mod = 0; + pre_event_buffer_count = pre_event_count + alarm_frame_count + warmup_count- 1; Debug( 1, "Monitor %s\ function: %d\ @@ -459,7 +463,9 @@ Monitor::Monitor( IBC = %d, WUC = %d, pEC = %d, PEC = %d, EAF = %d, FRI = %d, RBP = %d, ARBP = %d, FM = %d", name, function, label_format, label_coord.X(), label_coord.Y(), label_size, - image_buffer_count, warmup_count, pre_event_count, post_event_count, alarm_frame_count, fps_report_interval, ref_blend_perc, alarm_ref_blend_perc, track_motion + image_buffer_count, warmup_count, + pre_event_count, post_event_count, alarm_frame_count, + fps_report_interval, ref_blend_perc, alarm_ref_blend_perc, track_motion ); n_linked_monitors = 0; @@ -563,7 +569,6 @@ bool Monitor::connect() { /* Allocate a buffer for the next image */ next_buffer.image = new Image( width, height, camera->Colours(), camera->SubpixelOrder()); } - pre_event_buffer_count = pre_event_count + alarm_frame_count - 1; Debug(3, "Success connecting"); return true; @@ -752,8 +757,9 @@ unsigned int Monitor::GetLastWriteIndex() const { } uint32_t Monitor::GetLastEventId() const { - Debug(2, "mem_ptr(%x), State(%d) last_read_index(%d) last_read_time(%d) last_event(%d)", + Debug(2, "mem_ptr(%x), size(%d) State(%d) last_read_index(%d) last_read_time(%d) last_event(%d)", mem_ptr, + shared_data->size, shared_data->state, shared_data->last_read_index, shared_data->last_read_time, @@ -777,7 +783,7 @@ double Monitor::GetFPS() const { } struct timeval time1 = *snap1->timestamp; - int image_count = image_buffer_count; + int fps_image_count = image_buffer_count; int index2 = (index1+1)%image_buffer_count; Debug(2, "index2(%d)", index2); @@ -791,7 +797,7 @@ double Monitor::GetFPS() const { } index2 = (index2+1)%image_buffer_count; snap2 = &image_buffer[ index2 ]; - image_count--; + fps_image_count--; } struct timeval time2 = *snap2->timestamp; @@ -799,10 +805,11 @@ double Monitor::GetFPS() const { if ( ! time_diff ) { return 0.0; } - double curr_fps = image_count/time_diff; + double curr_fps = fps_image_count/time_diff; if ( curr_fps < 0.0 ) { - Error( "Negative FPS %f, time_diff = %lf (%d:%ld.%ld - %d:%ld.%ld), ibc: %d", curr_fps, time_diff, index2, time2.tv_sec, time2.tv_usec, index1, time1.tv_sec, time1.tv_usec, image_buffer_count ); + Error( "Negative FPS %f, time_diff = %lf (%d:%ld.%ld - %d:%ld.%ld), ibc: %d", + curr_fps, time_diff, index2, time2.tv_sec, time2.tv_usec, index1, time1.tv_sec, time1.tv_usec, image_buffer_count ); return 0.0; } return curr_fps; @@ -1236,6 +1243,7 @@ bool Monitor::Analyse() { Warning("SHouldn't be doing Analyze when not Enabled"); return false; } + GetLastEventId(); // if have event, sent frames until we find a video packet, at which point do analysis. Adaptive skip should only affect which frames we do analysis on. @@ -1294,7 +1302,7 @@ bool Monitor::Analyse() { if ( !signal ) { signalText = "Lost"; if ( event ) { - Info( "%s: %03d - Closing event %d, signal loss", name, image_count, event->Id() ); + Info( "%s: %03d - Closing event %d, signal loss", name, analysis_image_count, event->Id() ); closeEvent(); last_section_mod = 0; } @@ -1374,7 +1382,7 @@ bool Monitor::Analyse() { Debug( 3, "Section length (%d) Last Section Mod(%d), tv_sec(%d) new section mod(%d)", section_length, last_section_mod, timestamp->tv_sec, section_mod ); // This is not clear, but basically due to pauses, etc we might not get section_mod == 0 if ( section_mod < last_section_mod ) { - Info( "%s: %03d - Closing event %d, section end forced ", name, image_count, event->Id() ); + Info( "%s: %03d - Closing event %d, section end forced ", name, analysis_image_count, event->Id() ); closeEvent(); last_section_mod = 0; } else { @@ -1388,7 +1396,7 @@ bool Monitor::Analyse() { event = new Event( this, *timestamp, "Continuous", noteSetMap ); shared_data->last_event_id = event->Id(); video_store_data->recording = event->StartTime(); - Info( "%s: %03d - Opening new event %d, section start", name, image_count, event->Id() ); + Info( "%s: %03d - Opening new event %d, section start", name, analysis_image_count, event->Id() ); /* To prevent cancelling out an existing alert\prealarm\alarm state */ if ( state == IDLE ) { shared_data->state = state = TAPE; @@ -1400,32 +1408,32 @@ bool Monitor::Analyse() { Debug(9, "Score: (%d)", score ); if ( (state == IDLE || state == TAPE || state == PREALARM ) ) { if ( Event::PreAlarmCount() >= (alarm_frame_count-1) ) { - Info( "%s: %03d - Gone into alarm state", name, image_count ); + Info( "%s: %03d - Gone into alarm state", name, analysis_image_count ); shared_data->state = state = ALARM; if ( (function != MOCORD && state != ALERT) ) { event = new Event( this, *timestamp, cause, noteSetMap ); shared_data->last_event_id = event->Id(); } } else if ( state != PREALARM ) { - Info( "%s: %03d - Gone into prealarm state", name, image_count ); + Info( "%s: %03d - Gone into prealarm state", name, analysis_image_count ); shared_data->state = state = PREALARM; } } else if ( state == ALERT ) { - Info( "%s: %03d - Gone back into alarm state", name, image_count ); + Info( "%s: %03d - Gone back into alarm state", name, analysis_image_count ); shared_data->state = state = ALARM; } - last_alarm_count = image_count; + last_alarm_count = analysis_image_count; } else { // no score? if ( state == ALARM ) { - Info( "%s: %03d - Gone into alert state", name, image_count ); + Info( "%s: %03d - Gone into alert state", name, analysis_image_count ); shared_data->state = state = ALERT; } else if ( state == ALERT ) { - if ( image_count-last_alarm_count > post_event_count ) { - Info( "%s: %03d - Left alarm state (%d) - %d(%d) images", name, image_count, event->Id(), event->Frames(), event->AlarmFrames() ); + if ( analysis_image_count-last_alarm_count > post_event_count ) { + Info( "%s: %03d - Left alarm state (%d) - %d(%d) images", name, analysis_image_count, event->Id(), event->Frames(), event->AlarmFrames() ); //if ( function != MOCORD || event_close_mode == CLOSE_ALARM || event->Cause() == SIGNAL_CAUSE ) if ( function != MOCORD || event_close_mode == CLOSE_ALARM ) { shared_data->state = state = IDLE; - Info( "%s: %03d - Closing event %d, alarm end%s", name, image_count, event->Id(), (function==MOCORD)?", section truncated":"" ); + Info( "%s: %03d - Closing event %d, alarm end%s", name, analysis_image_count, event->Id(), (function==MOCORD)?", section truncated":"" ); closeEvent(); } else { shared_data->state = state = TAPE; @@ -1478,7 +1486,7 @@ bool Monitor::Analyse() { if ( noteSetMap.size() > 0 ) event->updateNotes( noteSetMap ); } else if ( state == TAPE ) { - if ( !(image_count%(frame_skip+1)) ) { + if ( !(analysis_image_count%(frame_skip+1)) ) { } } if ( function == MODECT || function == MOCORD ) { @@ -1489,11 +1497,12 @@ bool Monitor::Analyse() { } else { Debug(3,"Not ready?"); + return false; } } else { Debug(3, "trigger == off"); if ( event ) { - Info( "%s: %03d - Closing event %d, trigger off", name, image_count, event->Id() ); + Info( "%s: %03d - Closing event %d, trigger off", name, analysis_image_count, event->Id() ); closeEvent(); } shared_data->state = state = IDLE; @@ -3110,7 +3119,7 @@ unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &z shared_data->alarm_x = alarm_centre.X(); shared_data->alarm_y = alarm_centre.Y(); - Info( "Got alarm centre at %d,%d, at count %d", shared_data->alarm_x, shared_data->alarm_y, image_count ); + Info( "Got alarm centre at %d,%d, at count %d", shared_data->alarm_x, shared_data->alarm_y, analysis_image_count ); } else { shared_data->alarm_x = shared_data->alarm_y = -1; } @@ -3194,7 +3203,7 @@ int Monitor::PrimeCapture() { video_stream_id = camera->get_VideoStreamId(); packetqueue = new zm_packetqueue( pre_event_buffer_count, video_stream_id ); } - Debug(2, "Video stream id is (%d)", video_stream_id ); + Debug(2, "Video stream id is (%d), minimum_packets to keep in buffer(%d)", video_stream_id, pre_event_buffer_count ); return ret; } int Monitor::PreCapture() { diff --git a/src/zm_monitor.h b/src/zm_monitor.h index b0128c423..13a215e48 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -100,7 +100,7 @@ protected: typedef enum { CLOSE_TIME, CLOSE_IDLE, CLOSE_ALARM } EventCloseMode; - /* sizeof(SharedData) expected to be 336 bytes on 32bit and 64bit */ + /* sizeof(SharedData) expected to be 344 bytes on 32bit and 64bit */ typedef struct { uint32_t size; /* +0 */ uint32_t last_write_index; /* +4 */ @@ -425,9 +425,15 @@ public: return( event_prefix ); } inline bool Ready() { - if ( function <= MONITOR ) + if ( function <= MONITOR ) { + Error("Should not be calling Ready if the function doesn't include motion detection"); return( false ); - return( image_count > ready_count ); + } + if ( image_count > ready_count ) { + return true; + } + Debug(2, "Not ready because image_count(%d) <= ready_count(%d)", image_count, ready_count ); + return false; } inline bool Active() { if ( function <= MONITOR ) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index cb7908892..c4f599182 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -976,7 +976,8 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { } else if ( zm_packet->image ) { Debug(2,"Have an image, convert it"); //Go straight to out frame - swscale.Convert(zm_packet->image, + swscale.Convert( + zm_packet->image, zm_packet->buffer, codec_imgsize, (AVPixelFormat)zm_packet->image->AVPixFormat(), @@ -997,6 +998,7 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { if ( ! video_last_pts ) { video_last_pts = zm_packet->timestamp->tv_sec*1000000 + zm_packet->timestamp->tv_usec; + Debug(2, "No video_lsat_pts, set to (%d)", video_last_pts ); zm_packet->out_frame->pts = 0; } else { zm_packet->out_frame->pts = ( zm_packet->timestamp->tv_sec*1000000 + zm_packet->timestamp->tv_usec ) - video_last_pts; @@ -1040,6 +1042,9 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { return 0; } #endif + opkt.dts = opkt.pts; + if ( zm_packet->keyframe ) + opkt.flags |= AV_PKT_FLAG_KEY; } else { AVPacket *ipkt = &zm_packet->packet; @@ -1058,7 +1063,7 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { } opkt.duration = 0; -Debug(3, "dts:%" PRId64 ", pts:%" PRId64 ", keyframe:%d", opkt.dts, opkt.pts, opkt.flags & AV_PKT_FLAG_KEY ); + Debug(3, "dts:%" PRId64 ", pts:%" PRId64 ", keyframe:%d", opkt.dts, opkt.pts, opkt.flags & AV_PKT_FLAG_KEY ); write_video_packet( opkt ); zm_av_packet_unref(&opkt); From b87e45912531c16e59e4dee72545e2bd41db04ea Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 1 Dec 2017 14:48:30 -0500 Subject: [PATCH 0067/2339] still corrupting memory --- src/zm_monitor.cpp | 1 + src/zm_videostore.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 18234459d..9c18bf179 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -2745,6 +2745,7 @@ Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) { int Monitor::Capture() { static int FirstCapture = 1; // Used in de-interlacing to indicate whether this is the even or odd image + GetLastEventId(); unsigned int index = image_count % image_buffer_count; if ( (index == shared_data->last_read_index) && (function > MONITOR) ) { diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index c4f599182..a7cadfbb3 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -46,7 +46,7 @@ VideoStore::VideoStore( packets_written = 0; frame_count = 0; - av_register_all(); + FFMPEGInit(); Info("Opening video storage stream %s format: %s", filename, format); From 4a9c31a15d679667544e946de99da44d5dd12372 Mon Sep 17 00:00:00 2001 From: APHW2 MFGENG Date: Fri, 1 Dec 2017 15:42:19 -0800 Subject: [PATCH 0068/2339] wip --- src/zm_monitor.cpp | 35 +++++++++++++++++++----------- src/zm_remote_camera_nvsocket.cpp | 6 ++--- src/zm_videostore.cpp | 9 ++++++-- web/skins/classic/views/events.php | 2 +- 4 files changed, 33 insertions(+), 19 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 9c18bf179..e0c71572a 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1243,17 +1243,14 @@ bool Monitor::Analyse() { Warning("SHouldn't be doing Analyze when not Enabled"); return false; } - GetLastEventId(); // if have event, sent frames until we find a video packet, at which point do analysis. Adaptive skip should only affect which frames we do analysis on. - // If do have an event, then analysis_it should point to the head of the queue, because we would have emptied it on event creation. - unsigned int index = ( shared_data->last_read_index + 1 ) % image_buffer_count; - int packets_processed = 0; ZMPacket *snap; while ( ( snap = packetqueue->get_analysis_packet() ) && ( snap->score == -1 ) ) { + unsigned int index = snap->image_index; Debug(2, "Analysis index (%d), last_Write(%d)", index, shared_data->last_write_index); packets_processed += 1; @@ -1411,8 +1408,12 @@ bool Monitor::Analyse() { Info( "%s: %03d - Gone into alarm state", name, analysis_image_count ); shared_data->state = state = ALARM; if ( (function != MOCORD && state != ALERT) ) { +if ( event ) { +Error("Already ahve evnet!"); +} else { event = new Event( this, *timestamp, cause, noteSetMap ); shared_data->last_event_id = event->Id(); +} } } else if ( state != PREALARM ) { Info( "%s: %03d - Gone into prealarm state", name, analysis_image_count ); @@ -1510,24 +1511,32 @@ bool Monitor::Analyse() { } // end if ( trigger_data->trigger_state != TRIGGER_OFF ) if ( event ) { + int last_write = shared_data->last_write_index; + int written = 0; ZMPacket *queued_packet; //popPacket will increment analysis_it if neccessary, so this will write out all packets in queue + // We can't just loop here forever, because we may be capturing just as fast, and never leave the loop. + // Only loop until we hit the analysis index while ( ( queued_packet = packetqueue->popPacket() ) ) { - Debug(2,"adding packet (%x) (%d)", queued_packet, queued_packet->image_index ); + Debug(2,"adding packet (%d) qp lwindex(%d), written(%d)", queued_packet->image_index, last_write, written ); event->AddPacket( queued_packet ); +written ++; if ( queued_packet->image_index == -1 ) { delete queued_packet; - queued_packet = NULL; + } else if ( snap == queued_packet ) { + packetqueue->increment_analysis_it(); + break; } + // encoding can take a long time, so + shared_data->last_read_time = time(NULL); } // end while write out queued_packets + queued_packet = NULL; } else { packetqueue->increment_analysis_it(); } shared_data->last_read_index = snap->image_index; - struct timeval now; - gettimeofday(&now, NULL); - shared_data->last_read_time = now.tv_sec; + shared_data->last_read_time = time(NULL); analysis_image_count++; } // end while not at end of packetqueue if ( packets_processed > 0 ) @@ -2760,7 +2769,6 @@ int Monitor::Capture() { } ZMPacket *packet = &image_buffer[index]; - Debug(2,"Reset index(%d) of (%d)", index, image_buffer_count ); packet->reset(); Image* capture_image = packet->image; int captureResult = 0; @@ -2781,7 +2789,6 @@ int Monitor::Capture() { } } else { captureResult = camera->Capture(*packet); - Debug(2, "Reset timestamp"); gettimeofday( packet->timestamp, NULL ); if ( captureResult < 0 ) { // Unable to capture image for temporary reason @@ -2814,7 +2821,6 @@ int Monitor::Capture() { return 1; } - Debug(2, "Have video packet"); packet->codec_type = camera->get_VideoStream()->codecpar->codec_type; if ( packet->packet.size && ! packet->in_frame ) { @@ -2826,8 +2832,11 @@ int Monitor::Capture() { // Have an av_packet, mutex.lock(); if ( packetqueue->video_packet_count || packet->keyframe || event ) { + Debug(2, "Have video packet for index (%d)", index ); //Debug(2, "Queueing video packet"); packetqueue->queuePacket( packet ); + } else { + Debug(2, "Not queiing video packet for index (%d)", index ); } mutex.unlock(); } else { @@ -3202,7 +3211,7 @@ int Monitor::PrimeCapture() { int ret = camera->PrimeCapture(); if ( ret == 0 ) { video_stream_id = camera->get_VideoStreamId(); - packetqueue = new zm_packetqueue( pre_event_buffer_count, video_stream_id ); + packetqueue = new zm_packetqueue( image_buffer_count, video_stream_id ); } Debug(2, "Video stream id is (%d), minimum_packets to keep in buffer(%d)", video_stream_id, pre_event_buffer_count ); return ret; diff --git a/src/zm_remote_camera_nvsocket.cpp b/src/zm_remote_camera_nvsocket.cpp index d6e7c7401..1ba91942b 100644 --- a/src/zm_remote_camera_nvsocket.cpp +++ b/src/zm_remote_camera_nvsocket.cpp @@ -208,6 +208,7 @@ int RemoteCameraNVSocket::Capture( ZMPacket &zm_packet ) { } zm_packet.image->Assign( width, height, colours, subpixelorder, buffer, imagesize ); + zm_packet.keyframe = 1; return 1; } @@ -233,9 +234,8 @@ AVStream *RemoteCameraNVSocket::get_VideoStream() { } else { Error("Can't create video stream"); } -} else { -Debug(2,"Have videostream"); + } else { + Debug(5,"Have videostream"); } -Debug(2,"Get videoStream"); return video_stream; } diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index a7cadfbb3..573c96970 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -1003,6 +1003,13 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { } else { zm_packet->out_frame->pts = ( zm_packet->timestamp->tv_sec*1000000 + zm_packet->timestamp->tv_usec ) - video_last_pts; } + if ( zm_packet->keyframe ) { +Debug(2, "Setting keyframe"); + zm_packet->out_frame->key_frame =1; +Debug(2, "Setting keyframe (%d)", zm_packet->out_frame->key_frame ); +} else { +Debug(2, "Not Setting keyframe"); +} // Do this to allow the encoder to choose whether to use I/P/B frame #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) @@ -1043,8 +1050,6 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { } #endif opkt.dts = opkt.pts; - if ( zm_packet->keyframe ) - opkt.flags |= AV_PKT_FLAG_KEY; } else { AVPacket *ipkt = &zm_packet->packet; diff --git a/web/skins/classic/views/events.php b/web/skins/classic/views/events.php index 0166fb6b1..cd8103afc 100644 --- a/web/skins/classic/views/events.php +++ b/web/skins/classic/views/events.php @@ -222,7 +222,7 @@ Warning("Not Using snapshot" . $event->Path().'/snapshot.jpg' ); $imgHtml = ''. validHtmlStr('Event '.$event->Id()) .''; echo makePopupLink( - '?view=frame&eid='.$event->Id().'&fid='.$thumbData['FrameId'], + '?view=frame&eid='.$event->Id().'&fid='.( isset($thumbData['FrameId']) ? $thumbData['FrameId'] : 'snapshot' ), 'zmImage', array( 'image', reScale( $event->Width(), $scale ), reScale( $event->Height(), $scale ) ), $imgHtml From 3ca9b3687729223fadfb20233416e4d82cbd0ada Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 1 Dec 2017 18:50:28 -0500 Subject: [PATCH 0069/2339] fixes to compile on old ffmpeg --- src/zm_ffmpeg.cpp | 3 +-- src/zm_monitor.cpp | 8 ++++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index e2abe03f5..e031f0123 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -415,8 +415,7 @@ int zm_receive_frame( AVCodecContext *context, AVFrame *frame, AVPacket &packet int frameComplete; while ( !frameComplete ) { if ( (ret = zm_avcodec_decode_video( context, frame, &frameComplete, &packet )) < 0 ) { - Error( "Unable to decode frame at frame %d: %s, continuing", - streams[packet.stream_index].frame_count, + Error( "Unable to decode frame at frame: %s, continuing", av_make_error_string(ret).c_str() ); return 0; } diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 2b2af06b9..eef74d1b0 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -2811,7 +2811,11 @@ int Monitor::Capture() { if ( packetqueue.video_packet_count || event ) { // Need to copy it into another ZMPacket. ZMPacket *audio_packet = new ZMPacket( *packet ); +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) audio_packet->codec_type = camera->get_AudioStream()->codecpar->codec_type; +#else + audio_packet->codec_type = camera->get_AudioStream()->codec->codec_type; +#endif Debug(2, "Queueing packet"); packetqueue.queuePacket( audio_packet ); } @@ -2822,7 +2826,11 @@ int Monitor::Capture() { } Debug(2, "Have video packet"); +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) packet->codec_type = camera->get_VideoStream()->codecpar->codec_type; +#else + packet->codec_type = camera->get_VideoStream()->codec->codec_type; +#endif if ( packet->packet.size && ! packet->in_frame ) { //Debug(2,"About to decode"); From b1019267d839115aea197c6825685d28bcec3f78 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 2 Dec 2017 08:12:04 -0500 Subject: [PATCH 0070/2339] try moving codec selection up above ctx allocation so that it allocates a priv_data --- src/zm_local_camera.cpp | 2 +- src/zm_videostore.cpp | 181 +++++++++++++++++++--------------------- 2 files changed, 88 insertions(+), 95 deletions(-) diff --git a/src/zm_local_camera.cpp b/src/zm_local_camera.cpp index 72aa669c8..c7ae6bbb1 100644 --- a/src/zm_local_camera.cpp +++ b/src/zm_local_camera.cpp @@ -2047,7 +2047,7 @@ int LocalCamera::Capture( ZMPacket &zm_packet ) { } } else { - Debug( 3, "No format conversion performed. Assigning the image" ); + Debug( 5, "No format conversion performed. Assigning the image" ); /* No conversion was performed, the image is in the V4L buffers and needs to be copied into the shared memory */ zm_packet.image->Assign(width, height, colours, subpixelorder, buffer, imagesize); diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index a7cadfbb3..e2d561429 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -117,12 +117,31 @@ VideoStore::VideoStore( video_in_stream_index = 0; } - video_out_ctx = avcodec_alloc_context3(NULL); + if ( monitor->OutputCodec() == "mjpeg" ) { + video_out_codec = avcodec_find_encoder_by_name("mjpeg"); + if ( ! video_out_codec ) { + Debug(1, "Didn't find omx"); + video_out_codec = avcodec_find_encoder(AV_CODEC_ID_MJPEG); + } + video_out_ctx->codec_id = video_out_codec->id; + video_out_ctx->pix_fmt = AV_PIX_FMT_YUVJ422P; + + } else if ( monitor->OutputCodec() == "h264" ) { + video_out_codec = avcodec_find_encoder_by_name("h264_omx"); + if ( ! video_out_codec ) { + Debug(1, "Didn't find omx"); + video_out_codec = avcodec_find_encoder(AV_CODEC_ID_H264); + } + video_out_ctx = avcodec_alloc_context3( video_out_codec ); + } // Copy params from instream to ctx if ( video_in_stream && ( video_in_ctx->codec_id == AV_CODEC_ID_H264 ) ) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) ret = avcodec_parameters_to_context(video_out_ctx, video_in_stream->codecpar); +#else + ret = avcodec_copy_context( video_out_ctx, video_in_ctx ); +#endif if ( ret < 0 ) { Error("Could not initialize ctx parameteres"); return; @@ -130,9 +149,6 @@ VideoStore::VideoStore( Debug(2, "Going to dump the outctx"); zm_dump_codec(video_out_ctx); } -#else - avcodec_copy_context( video_out_ctx, video_in_ctx ); -#endif video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate // Only set orientation if doing passthrough, otherwise the frame image will be rotated Monitor::Orientation orientation = monitor->getOrientation(); @@ -177,14 +193,6 @@ VideoStore::VideoStore( video_out_ctx->pix_fmt = AV_PIX_FMT_YUV420P; break; } - // Same codec, just copy the packets, otherwise we have to decode/encode - video_out_codec = avcodec_find_encoder(AV_CODEC_ID_H264); - if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, NULL)) < 0 ) { - Warning("Can't open video codec (%s)! %s, trying h264", - video_out_codec->name, - av_make_error_string(ret).c_str() - ); - } } else { @@ -204,100 +212,77 @@ VideoStore::VideoStore( #else video_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; #endif - } + } - if ( monitor->OutputCodec() == "mjpeg" ) { - video_out_codec = avcodec_find_encoder_by_name("mjpeg"); - if ( ! video_out_codec ) { - Debug(1, "Didn't find omx"); - video_out_codec = avcodec_find_encoder(AV_CODEC_ID_MJPEG); - } - video_out_ctx->codec_id = video_out_codec->id; - video_out_ctx->pix_fmt = AV_PIX_FMT_YUVJ422P; - - } else if ( monitor->OutputCodec() == "h264" ) { - video_out_codec = avcodec_find_encoder_by_name("h264_omx"); - if ( ! video_out_codec ) { - Debug(1, "Didn't find omx"); - video_out_codec = avcodec_find_encoder(AV_CODEC_ID_H264); - } - if ( !video_out_codec ) { - Fatal("Could not find codec for H264"); - } - Debug(2, "Have video out codec"); - - video_out_ctx->codec_id = AV_CODEC_ID_H264; - //video_in_ctx->sample_aspect_ratio; - video_out_ctx->pix_fmt = AV_PIX_FMT_YUV420P; - /* video time_base can be set to whatever is handy and supported by encoder */ - video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate - //video_out_ctx->framerate = (AVRational){0,24}; // Unknown framerate -#if 1 - video_out_ctx->gop_size = 12; - video_out_ctx->qmin = 10; - video_out_ctx->qmax = 51; - video_out_ctx->qcompress = 0.6; - video_out_ctx->bit_rate = 4000000; + video_out_ctx->codec_id = AV_CODEC_ID_H264; + //video_in_ctx->sample_aspect_ratio; + video_out_ctx->pix_fmt = AV_PIX_FMT_YUV420P; + /* video time_base can be set to whatever is handy and supported by encoder */ + video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate + //video_out_ctx->framerate = (AVRational){0,24}; // Unknown framerate +#if 0 + video_out_ctx->gop_size = 12; + video_out_ctx->qmin = 10; + video_out_ctx->qmax = 51; + video_out_ctx->qcompress = 0.6; + video_out_ctx->bit_rate = 4000000; #endif video_out_ctx->max_b_frames = 1; - if (video_out_ctx->codec_id == AV_CODEC_ID_H264) + if ( video_out_ctx->codec_id == AV_CODEC_ID_H264 ) { + if ( video_out_ctx->priv_data ) { + Debug(2, "Setting preset to supoerfast"); av_opt_set(video_out_ctx->priv_data, "preset", "superfast", 0); - - AVDictionary *opts = 0; - std::string Options = monitor->GetEncoderOptions(); - ret = av_dict_parse_string(&opts, Options.c_str(), "=", ",#\n", 0); - if ( ret < 0 ) { - Warning("Could not parse ffmpeg encoder options list '%s'\n", Options.c_str()); + Debug(2, "Setting preset to supoerfast"); } else { - AVDictionaryEntry *e = NULL; - while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { - Debug( 3, "Encoder Option %s=%s", e->key, e->value ); - } + Debug(2, "Not setting priv_data"); } + } - if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) { - Warning("Can't open video codec (%s)! %s, trying h264", - video_out_codec->name, - av_make_error_string(ret).c_str() - ); - video_out_codec = avcodec_find_encoder_by_name("h264"); + AVDictionary *opts = 0; + std::string Options = monitor->GetEncoderOptions(); + ret = av_dict_parse_string(&opts, Options.c_str(), "=", ",#\n", 0); + if ( ret < 0 ) { + Warning("Could not parse ffmpeg encoder options list '%s'\n", Options.c_str()); + } else { + AVDictionaryEntry *e = NULL; + while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { + Debug( 3, "Encoder Option %s=%s", e->key, e->value ); + } + } + + if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) { + Warning("Can't open video codec (%s)! %s, trying h264", + video_out_codec->name, + av_make_error_string(ret).c_str() + ); + video_out_codec = avcodec_find_encoder_by_name("h264"); + if ( ! video_out_codec ) { + Error("Can't find h264 encoder"); + video_out_codec = avcodec_find_encoder_by_name("libx264"); if ( ! video_out_codec ) { - Error("Can't find h264 encoder"); - video_out_codec = avcodec_find_encoder_by_name("libx264"); - if ( ! video_out_codec ) { - Error("Can't find libx264 encoder"); - return; - } - } - if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) { - Error("Can't open video codec (%s)! %s", - video_out_codec->name, - av_make_error_string(ret).c_str() ); + Error("Can't find libx264 encoder"); return; } } -Debug(2,"Sucess opening codec"); - AVDictionaryEntry *e = NULL; - while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { - Warning( "Encoder Option %s not recognized by ffmpeg codec", e->key); + if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) { + Error("Can't open video codec (%s)! %s", + video_out_codec->name, + av_make_error_string(ret).c_str() ); + return; } - av_dict_free(&opts); + } + Debug(2,"Sucess opening codec"); + AVDictionaryEntry *e = NULL; + while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { + Warning( "Encoder Option %s not recognized by ffmpeg codec", e->key); + } + av_dict_free(&opts); - if ( !video_out_ctx->codec_tag ) { - video_out_ctx->codec_tag = - av_codec_get_tag(oc->oformat->codec_tag, AV_CODEC_ID_H264 ); - Debug(2, "No codec_tag, setting to h264 ? "); - } - } else { -Error("Codec not set"); - } // end if codec == h264 - - swscale.SetDefaults( - video_in_ctx->pix_fmt, - video_out_ctx->pix_fmt, - video_out_ctx->width, - video_out_ctx->height - ); + if ( !video_out_ctx->codec_tag ) { + video_out_ctx->codec_tag = + av_codec_get_tag(oc->oformat->codec_tag, AV_CODEC_ID_H264 ); + Debug(2, "No codec_tag, setting to h264 ? "); + } } // end if copying or trasncoding video_out_stream = avformat_new_stream(oc, video_out_codec); @@ -892,7 +877,13 @@ void VideoStore::dumpPacket(AVPacket *pkt) { snprintf(b, sizeof(b), " pts: %" PRId64 ", dts: %" PRId64 ", data: %p, size: %d, sindex: %d, dflags: %04x, s-pos: %" PRId64 - ", duration: %" PRId64 "\n", + ", duration: %" +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + PRId64 +#else + "d" +#endif + "\n", pkt->pts, pkt->dts, pkt->data, @@ -962,6 +953,7 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { out_frame->width = video_out_ctx->width; out_frame->height = video_out_ctx->height; out_frame->format = video_out_ctx->pix_fmt; + out_frame->duration = 0; if ( ! zm_packet->in_frame ) { Debug(2,"Have no in_frame"); @@ -1045,6 +1037,7 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { opkt.dts = opkt.pts; if ( zm_packet->keyframe ) opkt.flags |= AV_PKT_FLAG_KEY; + opkt.duration = 0; } else { AVPacket *ipkt = &zm_packet->packet; From bc525a4e01f42a74996547bb7dc195266ba9abea Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 2 Dec 2017 13:55:26 -0500 Subject: [PATCH 0071/2339] blah --- src/zm_camera.cpp | 7 +++++-- src/zm_ffmpeg.cpp | 8 ++++++-- src/zm_ffmpeg_camera.cpp | 18 +----------------- src/zm_ffmpeg_camera.h | 3 --- 4 files changed, 12 insertions(+), 24 deletions(-) diff --git a/src/zm_camera.cpp b/src/zm_camera.cpp index f9e0c154d..ce0a9bc60 100644 --- a/src/zm_camera.cpp +++ b/src/zm_camera.cpp @@ -36,6 +36,7 @@ Camera::Camera( unsigned int p_monitor_id, SourceType p_type, unsigned int p_wid mVideoStreamId(-1), mAudioStreamId(-1), mVideoCodecContext(NULL), + mAudioCodecContext(NULL), video_stream(NULL) { pixels = width * height; @@ -49,15 +50,17 @@ Camera::Camera( unsigned int p_monitor_id, SourceType p_type, unsigned int p_wid } else if(colours == ZM_COLOUR_RGB24 && ((imagesize % 64) != 0 || (imagesize % 12) != 0)) { Fatal("Image size is not multiples of 12 and 64"); } - monitor = NULL; + monitor = NULL; } Camera::~Camera() { } Monitor *Camera::getMonitor() { - if ( ! monitor ) + if ( ! monitor ) { + Warning("Loading monitor"); monitor = Monitor::Load( monitor_id, false, Monitor::QUERY ); + } return monitor; } diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index d943d399b..a96bced26 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -26,9 +26,13 @@ void FFMPEGInit() { static bool bInit = false; - if(!bInit) { + if ( !bInit ) { + if ( logDebugging() ) + av_log_set_level( AV_LOG_DEBUG ); + else + av_log_set_level( AV_LOG_QUIET ); av_register_all(); - av_log_set_level(AV_LOG_DEBUG); + avformat_network_init(); bInit = true; } } diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 4f9f42fea..1783183f2 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -88,7 +88,7 @@ FfmpegCamera::FfmpegCamera( int p_id, const std::string &p_path, const std::stri mOptions( p_options ) { if ( capture ) { - Initialise(); + FFMPEGInit(); } hwaccel = false; @@ -118,25 +118,9 @@ FfmpegCamera::~FfmpegCamera() { CloseFfmpeg(); - if ( capture ) { - Terminate(); - } avformat_network_deinit(); } -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() { -} - int FfmpegCamera::PrimeCapture() { mVideoStreamId = -1; mAudioStreamId = -1; diff --git a/src/zm_ffmpeg_camera.h b/src/zm_ffmpeg_camera.h index a5f4d1f12..9220ca46f 100644 --- a/src/zm_ffmpeg_camera.h +++ b/src/zm_ffmpeg_camera.h @@ -100,9 +100,6 @@ class FfmpegCamera : public Camera { const std::string &Options() const { return( mOptions ); } const std::string &Method() const { return( mMethod ); } - void Initialise(); - void Terminate(); - int PrimeCapture(); int PreCapture(); int Capture(ZMPacket &p); From b8f455ee7c46ad7524e9b09ae4ee64e0401247dc Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 3 Dec 2017 11:00:40 -0500 Subject: [PATCH 0072/2339] some cleanup, add a note about the lines that cause zm to crash --- src/zm_db.cpp | 7 ++++--- src/zm_db.h | 31 +++++++++++-------------------- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/src/zm_db.cpp b/src/zm_db.cpp index bb83d09ab..ac09dca13 100644 --- a/src/zm_db.cpp +++ b/src/zm_db.cpp @@ -25,11 +25,12 @@ MYSQL dbconn; -int zmDbConnected = false; +bool zmDbConnected = false; void zmDbConnect() { - if ( zmDbConnected ) - return; + // If these lines are uncommented, we get memory corruption and crashes + //if ( zmDbConnected ) + //return; if ( !mysql_init( &dbconn ) ) { Error( "Can't initialise database connection: %s", mysql_error( &dbconn ) ); diff --git a/src/zm_db.h b/src/zm_db.h index f9b158be8..f53a8c738 100644 --- a/src/zm_db.h +++ b/src/zm_db.h @@ -23,35 +23,26 @@ #include class zmDbRow { - private: - MYSQL_RES *result_set; - MYSQL_ROW row; - public: - zmDbRow() { result_set = NULL; row = NULL; }; - MYSQL_RES *fetch( const char *query ); - zmDbRow( MYSQL_RES *, MYSQL_ROW *row ); - ~zmDbRow(); + private: + MYSQL_RES *result_set; + MYSQL_ROW row; + public: + zmDbRow() { result_set = NULL; row = NULL; }; + MYSQL_RES *fetch( const char *query ); + zmDbRow( MYSQL_RES *, MYSQL_ROW *row ); + ~zmDbRow(); - char *operator[](unsigned int index) const { - return row[index]; - } + char *operator[](unsigned int index) const { + return row[index]; + } }; -#ifdef __cplusplus -extern "C" { -#endif extern MYSQL dbconn; -extern int zmDbConnected; - void zmDbConnect(); void zmDbClose(); MYSQL_RES * zmDbFetch( const char *query ); zmDbRow *zmDbFetchOne( const char *query ); -#ifdef __cplusplus -} /* extern "C" */ -#endif - #endif // ZM_DB_H From 61dd84de8213c52c0835b7250c625c930acf9e27 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 4 Dec 2017 18:06:42 -0500 Subject: [PATCH 0073/2339] move most of the codec init out of the constructor into open so that we can fail gracefully --- src/zm_videostore.cpp | 71 ++++++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 32 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index a1eb58a4c..86b6566a2 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -36,8 +36,10 @@ VideoStore::VideoStore( const char *format_in, AVStream *p_video_in_stream, AVStream *p_audio_in_stream, - Monitor *monitor + Monitor *p_monitor ) { + +monitor = p_monitor; video_in_stream = p_video_in_stream; audio_in_stream = p_audio_in_stream; filename = filename_in; @@ -45,9 +47,31 @@ VideoStore::VideoStore( packets_written = 0; frame_count = 0; + in_frame = NULL; + converted_in_samples = NULL; + audio_out_codec = NULL; + audio_in_codec = NULL; + audio_in_ctx = NULL; + audio_out_stream = NULL; + out_frame = NULL; +#ifdef HAVE_LIBAVRESAMPLE + resample_ctx = NULL; +#endif FFMPEGInit(); + video_last_pts = 0; + video_last_dts = 0; + audio_last_pts = 0; + audio_last_dts = 0; + video_next_pts = 0; + video_next_dts = 0; + audio_next_pts = 0; + audio_next_dts = 0; +Debug(2,"End VIdeoStore"); +} // VideoStore::VideoStore + +bool VideoStore::open() { Info("Opening video storage stream %s format: %s", filename, format); ret = avformat_alloc_output_context2(&oc, NULL, NULL, filename); @@ -80,7 +104,6 @@ VideoStore::VideoStore( oc->metadata = pmetadata; out_format = oc->oformat; - in_frame = NULL; if ( video_in_stream ) { video_in_stream_index = video_in_stream->index; @@ -144,7 +167,7 @@ VideoStore::VideoStore( #endif if ( ret < 0 ) { Error("Could not initialize ctx parameteres"); - return; + return false; } else { Debug(2, "Going to dump the outctx"); zm_dump_codec(video_out_ctx); @@ -199,7 +222,7 @@ VideoStore::VideoStore( /** Create a new frame to store the */ if ( !(video_in_frame = zm_av_frame_alloc()) ) { Error("Could not allocate video_in frame"); - return; + return false; } // Don't have an input stream, so need to tell it what we are sending it, or are transcoding video_out_ctx->width = monitor->Width(); @@ -220,7 +243,7 @@ VideoStore::VideoStore( /* video time_base can be set to whatever is handy and supported by encoder */ video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate //video_out_ctx->framerate = (AVRational){0,24}; // Unknown framerate -#if 0 +#if 1 video_out_ctx->gop_size = 12; video_out_ctx->qmin = 10; video_out_ctx->qmax = 51; @@ -261,14 +284,19 @@ VideoStore::VideoStore( video_out_codec = avcodec_find_encoder_by_name("libx264"); if ( ! video_out_codec ) { Error("Can't find libx264 encoder"); - return; + return false; } } if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) { - Error("Can't open video codec (%s)! %s", - video_out_codec->name, + Error("Can't open video codec (%s)! %s", video_out_codec->name, av_make_error_string(ret).c_str() ); - return; +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + // We allocate and copy in newer ffmpeg, so need to free it + avcodec_free_context(&video_out_ctx); +#endif + video_out_ctx=NULL; + + return false; } } Debug(2,"Sucess opening codec"); @@ -295,7 +323,7 @@ VideoStore::VideoStore( ret = avcodec_parameters_from_context(video_out_stream->codecpar, video_out_ctx); if ( ret < 0 ) { Error("Could not initialize stream parameteres"); - return; + return false; } zm_dump_codecpar(video_out_stream->codecpar); zm_dump_codec(video_out_ctx); @@ -318,15 +346,6 @@ VideoStore::VideoStore( video_out_ctx->time_base.num, video_out_ctx->time_base.den); - converted_in_samples = NULL; - audio_out_codec = NULL; - audio_in_codec = NULL; - audio_in_ctx = NULL; - audio_out_stream = NULL; - out_frame = NULL; -#ifdef HAVE_LIBAVRESAMPLE - resample_ctx = NULL; -#endif if ( audio_in_stream ) { Debug(3, "Have audio stream"); @@ -347,7 +366,7 @@ VideoStore::VideoStore( Debug(2, "Got something other than AAC (%s)", error_buffer); if ( !setup_resampler() ) { - return; + return false; } } else { Debug(3, "Got AAC"); @@ -414,18 +433,6 @@ VideoStore::VideoStore( } } // end if audio_in_stream - video_last_pts = 0; - video_last_dts = 0; - audio_last_pts = 0; - audio_last_dts = 0; - video_next_pts = 0; - video_next_dts = 0; - audio_next_pts = 0; - audio_next_dts = 0; -Debug(2,"End VIdeoStore"); -} // VideoStore::VideoStore - -bool VideoStore::open() { /* open the out file, if needed */ if (!(out_format->flags & AVFMT_NOFILE)) { ret = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE, NULL, NULL); From 13de2b60d4c11ff6d3f952a14cc8a9e807935540 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 4 Dec 2017 18:06:53 -0500 Subject: [PATCH 0074/2339] need to store the monitor object --- src/zm_videostore.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/zm_videostore.h b/src/zm_videostore.h index 4786770f9..55a99e0ee 100644 --- a/src/zm_videostore.h +++ b/src/zm_videostore.h @@ -19,6 +19,7 @@ class VideoStore; class VideoStore { private: + Monitor *monitor; AVOutputFormat *out_format; AVFormatContext *oc; AVStream *video_out_stream; From 0cfc42b9fd35f414977d4e1c270bc89a840bda80 Mon Sep 17 00:00:00 2001 From: APHW2 MFGENG Date: Tue, 5 Dec 2017 13:16:52 -0800 Subject: [PATCH 0075/2339] some cleanups/fixes --- src/zm_monitor.cpp | 11 ++++++----- src/zm_monitor.h | 1 + src/zm_packetqueue.cpp | 9 +++------ src/zm_packetqueue.h | 4 ++-- src/zm_videostore.cpp | 42 +++++++++++++++++++++++++----------------- src/zmc.cpp | 6 ++++-- 6 files changed, 41 insertions(+), 32 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index cfcd3dcb7..37cd48567 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -353,6 +353,7 @@ Monitor::Monitor( event_count = 0; image_count = 0; analysis_image_count = 0; + deinterlacing_value = deinterlacing & 0xff; // How many frames we need to have before we start analysing ready_count = warmup_count; @@ -564,7 +565,7 @@ bool Monitor::connect() { image_buffer[i].image = new Image( width, height, camera->Colours(), camera->SubpixelOrder(), &(shared_images[i*camera->ImageSize()]) ); image_buffer[i].image->HoldBuffer(true); /* Don't release the internal buffer or replace it with another */ } - if ( (deinterlacing & 0xff) == 4) { + if ( deinterlacing_value == 4 ) { /* Four field motion adaptive deinterlacing in use */ /* Allocate a buffer for the next image */ next_buffer.image = new Image( width, height, camera->Colours(), camera->SubpixelOrder()); @@ -600,7 +601,7 @@ Monitor::~Monitor() { closeEvent(); } - if ( (deinterlacing & 0xff) == 4) { + if ( deinterlacing_value == 4 ) { delete next_buffer.image; } #if 1 @@ -2764,7 +2765,6 @@ Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) { int Monitor::Capture() { static int FirstCapture = 1; // Used in de-interlacing to indicate whether this is the even or odd image - GetLastEventId(); unsigned int index = image_count % image_buffer_count; if ( (index == shared_data->last_read_index) && (function > MONITOR) ) { @@ -2776,6 +2776,8 @@ int Monitor::Capture() { Warning( "Last image read from shared memory %ld seconds ago, zma may have gone away", last_read_delta ) shared_data->last_read_index = image_buffer_count; } + } else { + Debug(2,"Current write index %d, last read index %d, current (%d)", shared_data->last_write_index, shared_data->last_read_index, index ); } ZMPacket *packet = &image_buffer[index]; @@ -2784,7 +2786,6 @@ int Monitor::Capture() { Image* capture_image = packet->image; int captureResult = 0; - unsigned int deinterlacing_value = deinterlacing & 0xff; if ( deinterlacing_value == 4 ) { if ( FirstCapture != 1 ) { /* Copy the next image into the shared memory */ @@ -2919,7 +2920,7 @@ int Monitor::Capture() { if ( now != last_fps_time ) { // # of images per interval / the amount of time it took capture_fps = double(fps_report_interval)/(now-last_fps_time); - Info( "%d -> %d -> %d", fps_report_interval, now, last_fps_time ); + //Info( "%d -> %d -> %d", fps_report_interval, now, last_fps_time ); //Info( "%d -> %d -> %lf -> %lf", now-last_fps_time, fps_report_interval/(now-last_fps_time), double(fps_report_interval)/(now-last_fps_time), fps ); Info( "%s: %d - Capturing at %.2lf fps", name, image_count, capture_fps ); last_fps_time = now; diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 13a215e48..bdddac4ec 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -232,6 +232,7 @@ protected: unsigned int v4l_captures_per_frame; Orientation orientation; // Whether the image has to be rotated at all unsigned int deinterlacing; + unsigned int deinterlacing_value; bool videoRecording; int savejpegspref; diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index b632b8730..15383a703 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -21,12 +21,9 @@ #include "zm_ffmpeg.h" #include -#define VIDEO_QUEUESIZE 200 -#define AUDIO_QUEUESIZE 50 - -zm_packetqueue::zm_packetqueue( unsigned int video_image_count, int p_video_stream_id ) { +zm_packetqueue::zm_packetqueue( int video_image_count, int p_video_stream_id ) { video_stream_id = p_video_stream_id; - max_video_packet_count = video_image_count; + max_video_packet_count = video_image_count-1; video_packet_count = 0; analysis_it = pktQueue.begin(); } @@ -39,7 +36,7 @@ bool zm_packetqueue::queuePacket( ZMPacket* zm_packet ) { pktQueue.push_back( zm_packet ); if ( zm_packet->codec_type == AVMEDIA_TYPE_VIDEO ) { video_packet_count += 1; - if ( video_packet_count > max_video_packet_count ) + if ( video_packet_count >= max_video_packet_count ) clearQueue( max_video_packet_count, video_stream_id ); } diff --git a/src/zm_packetqueue.h b/src/zm_packetqueue.h index 2ef5ba9fa..a3a4a5ee0 100644 --- a/src/zm_packetqueue.h +++ b/src/zm_packetqueue.h @@ -37,10 +37,10 @@ class zm_packetqueue { int video_stream_id; int video_packet_count; // keep track of how many video packets we have, because we shouldn't have more than image_buffer_count - unsigned int max_video_packet_count; + int max_video_packet_count; // allow a negative value to someday mean unlimited public: - zm_packetqueue( unsigned int p_max_video_packet_count, int p_video_stream_id ); + zm_packetqueue( int p_max_video_packet_count, int p_video_stream_id ); virtual ~zm_packetqueue(); bool queuePacket( ZMPacket* packet ); ZMPacket * popPacket( ); diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 86b6566a2..4685bc3d8 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -141,11 +141,13 @@ bool VideoStore::open() { } if ( monitor->OutputCodec() == "mjpeg" ) { +Debug(2,"Using mjpeg"); video_out_codec = avcodec_find_encoder_by_name("mjpeg"); if ( ! video_out_codec ) { - Debug(1, "Didn't find omx"); + Debug(1, "Didn't find mjpeg encoder"); video_out_codec = avcodec_find_encoder(AV_CODEC_ID_MJPEG); } + video_out_ctx = avcodec_alloc_context3( video_out_codec ); video_out_ctx->codec_id = video_out_codec->id; video_out_ctx->pix_fmt = AV_PIX_FMT_YUVJ422P; @@ -919,10 +921,10 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { // if we have to transcode if ( video_out_ctx->codec_id != video_in_ctx->codec_id ) { - Debug(3, "Have encoding video frame count (%d)", frame_count); + //Debug(3, "Have encoding video frame count (%d)", frame_count); if ( ! zm_packet->out_frame ) { - Debug(3, "Have no out frame"); + //Debug(3, "Have no out frame"); AVFrame *out_frame = zm_packet->out_frame = zm_av_frame_alloc(); if ( ! out_frame ) { Error("Unable to allocate a frame"); @@ -961,13 +963,11 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { out_frame->height = video_out_ctx->height; out_frame->format = video_out_ctx->pix_fmt; //out_frame->pkt_duration = 0; - out_frame->coded_picture_number = frame_count; - out_frame->display_picture_number = frame_count; if ( ! zm_packet->in_frame ) { - Debug(2,"Have no in_frame"); + //Debug(2,"Have no in_frame"); if ( zm_packet->packet.size ) { - Debug(2,"Decoding"); + //Debug(2,"Decoding"); if ( ! zm_packet->decode( video_in_ctx ) ) { Debug(2, "unable to decode yet."); return 0; @@ -975,7 +975,7 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { //Go straight to out frame swscale.Convert( zm_packet->in_frame, out_frame ); } else if ( zm_packet->image ) { - Debug(2,"Have an image, convert it"); + //Debug(2,"Have an image, convert it"); //Go straight to out frame swscale.Convert( zm_packet->image, @@ -997,26 +997,31 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { } // end if no in_frame } // end if no out_frame + zm_packet->out_frame->coded_picture_number = frame_count; + zm_packet->out_frame->display_picture_number = frame_count; + zm_packet->out_frame->sample_aspect_ratio = (AVRational){ 0, 1 }; + if ( ! video_last_pts ) { video_last_pts = zm_packet->timestamp->tv_sec*1000000 + zm_packet->timestamp->tv_usec; Debug(2, "No video_lsat_pts, set to (%" PRId64 ") secs(%d) usecs(%d)", video_last_pts, zm_packet->timestamp->tv_sec, zm_packet->timestamp->tv_usec ); zm_packet->out_frame->pts = 0; } else { + //uint64_t seconds = zm_packet->timestamp->tv_sec*1000000; zm_packet->out_frame->pts = ( zm_packet->timestamp->tv_sec*1000000 + zm_packet->timestamp->tv_usec ) - video_last_pts; - Debug(2, " Setting pts, set to (%" PRId64 ") from (%" PRIu64 " - secs(%d) usecs(%d)", - zm_packet->out_frame->pts, video_last_pts, zm_packet->timestamp->tv_sec, zm_packet->timestamp->tv_usec ); + Debug(2, " Setting pts for frame(%d), set to (%" PRId64 ") from (%" PRId64 " - secs(%d) usecs(%d)", + frame_count, zm_packet->out_frame->pts, video_last_pts, zm_packet->timestamp->tv_sec, zm_packet->timestamp->tv_usec ); } if ( zm_packet->keyframe ) { - Debug(2, "Setting keyframe was (%d)", zm_packet->out_frame->key_frame ); + //Debug(2, "Setting keyframe was (%d)", zm_packet->out_frame->key_frame ); zm_packet->out_frame->key_frame = 1; - Debug(2, "Setting keyframe (%d)", zm_packet->out_frame->key_frame ); + //Debug(2, "Setting keyframe (%d)", zm_packet->out_frame->key_frame ); } else { Debug(2, "Not Setting keyframe"); } - // Do this to allow the encoder to choose whether to use I/P/B frame #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + // Do this to allow the encoder to choose whether to use I/P/B frame zm_packet->out_frame->pict_type = AV_PICTURE_TYPE_NONE; if ( (ret = avcodec_send_frame(video_out_ctx, zm_packet->out_frame)) < 0 ) { Error("Could not send frame (error '%s')", av_make_error_string(ret).c_str()); @@ -1024,6 +1029,8 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { } av_init_packet(&opkt); + opkt.data = NULL; + opkt.size = 0; if ( (ret = avcodec_receive_packet(video_out_ctx, &opkt)) < 0 ) { zm_av_packet_unref(&opkt); if ( AVERROR(EAGAIN) == ret ) { @@ -1037,6 +1044,7 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { } return -1; } +//Debug(2, "Got packet using receive_packet, dts:%" PRId64 ", pts:%" PRId64 ", keyframe:%d", opkt.dts, opkt.pts, opkt.flags & AV_PKT_FLAG_KEY ); #else av_init_packet(&opkt); int data_present; @@ -1053,8 +1061,8 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { return 0; } #endif - opkt.dts = opkt.pts; - opkt.duration = 0; + //opkt.dts = opkt.pts; + //opkt.duration = 0; } else { AVPacket *ipkt = &zm_packet->packet; @@ -1073,7 +1081,7 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { } opkt.duration = 0; - Debug(3, "dts:%" PRId64 ", pts:%" PRId64 ", keyframe:%d", opkt.dts, opkt.pts, opkt.flags & AV_PKT_FLAG_KEY ); + Debug(3, "dts:%" PRId64 ", pts:%" PRId64 ", duration:%" PRId64 ", keyframe:%d", opkt.dts, opkt.pts, opkt.duration, opkt.flags & AV_PKT_FLAG_KEY ); write_video_packet( opkt ); zm_av_packet_unref(&opkt); @@ -1090,7 +1098,7 @@ void VideoStore::write_video_packet( AVPacket &opkt ) { opkt.dts = opkt.pts; } - opkt.pos = -1; + //opkt.pos = -1; opkt.stream_index = video_out_stream->index; //video_next_dts += opkt.duration; diff --git a/src/zmc.cpp b/src/zmc.cpp index ed7ae5c91..5110827bf 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -254,6 +254,7 @@ int main(int argc, char *argv[]) { last_capture_times[i].tv_sec = last_capture_times[i].tv_usec = 0; capture_delays[i] = monitors[i]->GetCaptureDelay(); alarm_capture_delays[i] = monitors[i]->GetAlarmCaptureDelay(); + Debug(2, "capture delay(%l) alarm delay(%l)", capture_delays[i], alarm_capture_delays[i] ); Monitor::Function function = monitors[0]->GetFunction(); if ( function == Monitor::MODECT || function == Monitor::MOCORD || function == Monitor::RECORD) { @@ -278,10 +279,11 @@ int main(int argc, char *argv[]) { for ( int j = 0; j < n_monitors; j++ ) { if ( last_capture_times[j].tv_sec ) { DELTA_TIMEVAL(delta_time, now, last_capture_times[j], DT_PREC_3); + // capture_delay is the amount of time we should sleep to achieve the desired framerate. if ( monitors[i]->GetState() == Monitor::ALARM ) - next_delays[j] = alarm_capture_delays[j]-delta_time.delta; + next_delays[j] = alarm_capture_delays[j] - delta_time.delta; else - next_delays[j] = capture_delays[j]-delta_time.delta; + next_delays[j] = capture_delays[j] - delta_time.delta; if ( next_delays[j] < 0 ) next_delays[j] = 0; } else { From 2a3683c0721ffd9246155dd8bd1f9c759d9bce30 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 7 Dec 2017 09:27:28 -0500 Subject: [PATCH 0076/2339] add some more debug --- src/zm_videostore.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 4685bc3d8..f66cf7e1d 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -152,12 +152,21 @@ Debug(2,"Using mjpeg"); video_out_ctx->pix_fmt = AV_PIX_FMT_YUVJ422P; } else if ( monitor->OutputCodec() == "h264" ) { +Debug(2,"Using h264"); video_out_codec = avcodec_find_encoder_by_name("h264_omx"); if ( ! video_out_codec ) { Debug(1, "Didn't find omx"); video_out_codec = avcodec_find_encoder(AV_CODEC_ID_H264); } - video_out_ctx = avcodec_alloc_context3( video_out_codec ); + if ( ! video_out_codec ) { + Error("Didn't find h264 encoder"); + video_out_codec = NULL; + return false; + } + video_out_ctx = avcodec_alloc_context3(video_out_codec); + } else { + Error("No output codec selected"); + return false; } // Copy params from instream to ctx From 311e62de7a38f1d46fd45eddad52279d6e4fbd80 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 8 Dec 2017 10:36:54 -0500 Subject: [PATCH 0077/2339] change zmDbConnect to return a bool --- src/zm_db.cpp | 20 +++++++++++++------- src/zm_db.h | 2 +- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/zm_db.cpp b/src/zm_db.cpp index c2c3fc5ef..f51c84dcb 100644 --- a/src/zm_db.cpp +++ b/src/zm_db.cpp @@ -23,29 +23,34 @@ #include "zm.h" #include "zm_db.h" +// From what I read, we need one of these per thread MYSQL dbconn; bool zmDbConnected = false; -void zmDbConnect() { +bool zmDbConnect() { // For some reason having these lines causes memory corruption and crashing on newer debian/ubuntu //if ( zmDbConnected ) //return; if ( !mysql_init( &dbconn ) ) { Error( "Can't initialise database connection: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); + return false; } my_bool reconnect = 1; if ( mysql_options( &dbconn, MYSQL_OPT_RECONNECT, &reconnect ) ) - Fatal( "Can't set database auto reconnect option: %s", mysql_error( &dbconn ) ); + Error( "Can't set database auto reconnect option: %s", mysql_error( &dbconn) ); if ( !staticConfig.DB_SSL_CA_CERT.empty() ) - mysql_ssl_set( &dbconn, staticConfig.DB_SSL_CLIENT_KEY.c_str(), staticConfig.DB_SSL_CLIENT_CERT.c_str(), staticConfig.DB_SSL_CA_CERT.c_str(), NULL, NULL ); + mysql_ssl_set( &dbconn, + staticConfig.DB_SSL_CLIENT_KEY.c_str(), + staticConfig.DB_SSL_CLIENT_CERT.c_str(), + staticConfig.DB_SSL_CA_CERT.c_str(), + NULL, NULL ); std::string::size_type colonIndex = staticConfig.DB_HOST.find( ":" ); if ( colonIndex == std::string::npos ) { if ( !mysql_real_connect( &dbconn, staticConfig.DB_HOST.c_str(), staticConfig.DB_USER.c_str(), staticConfig.DB_PASS.c_str(), NULL, 0, NULL, 0 ) ) { Error( "Can't connect to server: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); + return false; } } else { std::string dbHost = staticConfig.DB_HOST.substr( 0, colonIndex ); @@ -53,12 +58,12 @@ void zmDbConnect() { if ( dbPortOrSocket[0] == '/' ) { if ( !mysql_real_connect( &dbconn, NULL, staticConfig.DB_USER.c_str(), staticConfig.DB_PASS.c_str(), NULL, 0, dbPortOrSocket.c_str(), 0 ) ) { Error( "Can't connect to server: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); + return false; } } else { if ( !mysql_real_connect( &dbconn, dbHost.c_str(), staticConfig.DB_USER.c_str(), staticConfig.DB_PASS.c_str(), NULL, atoi(dbPortOrSocket.c_str()), NULL, 0 ) ) { Error( "Can't connect to server: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); + return false; } } } @@ -67,6 +72,7 @@ void zmDbConnect() { exit( mysql_errno( &dbconn ) ); } zmDbConnected = true; + return zmDbConnected; } void zmDbClose() { diff --git a/src/zm_db.h b/src/zm_db.h index f53a8c738..616bbec25 100644 --- a/src/zm_db.h +++ b/src/zm_db.h @@ -39,7 +39,7 @@ class zmDbRow { extern MYSQL dbconn; -void zmDbConnect(); +bool zmDbConnect(); void zmDbClose(); MYSQL_RES * zmDbFetch( const char *query ); From 12350407bfdb3cdf83be4a0c58bd12836d0ad9e6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 8 Dec 2017 10:37:35 -0500 Subject: [PATCH 0078/2339] reconnet to db on error --- src/zm_event.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index f59ce4c97..94bdc852f 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -485,10 +485,16 @@ void Event::AddFrame( Image *image, struct timeval timestamp, int score, Image * Debug( 1, "Adding frame %d of type \"%s\" to DB", frames, Event::frame_type_names[frame_type] ); static char sql[ZM_SQL_MED_BUFSIZ]; - snprintf( sql, sizeof(sql), "insert into Frames ( EventId, FrameId, Type, TimeStamp, Delta, Score ) values ( %d, %d, '%s', from_unixtime( %ld ), %s%ld.%02ld, %d )", id, frames, frame_type_names[frame_type], timestamp.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, score ); - if ( mysql_query( &dbconn, sql ) ) { - Error( "Can't insert frame: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); + snprintf( sql, sizeof(sql), "INSERT INTO Frames ( EventId, FrameId, Type, TimeStamp, Delta, Score ) VALUES ( %d, %d, '%s', from_unixtime( %ld ), %s%ld.%02ld, %d )", id, frames, frame_type_names[frame_type], timestamp.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, score ); + if ( mysql_query(&dbconn, sql) ) { + Error("Can't insert frame: (%s) reason:%s", sql, mysql_error(&dbconn)); + zmDbClose(); + if ( ! zmDbConnect() ) + exit(mysql_errno(&dbconn)); + if ( mysql_query(&dbconn, sql) ) { + Error("Can't insert frame: (%s) reason:%s", sql, mysql_error(&dbconn)); + exit(mysql_errno(&dbconn)); + } } last_db_frame = frames; From d5b927c986d75666e1925af0d794f4c82975257d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 8 Dec 2017 10:38:16 -0500 Subject: [PATCH 0079/2339] use xh264rgb is available --- src/zm_videostore.cpp | 81 +++++++++++++++++++++++++++++++------------ 1 file changed, 59 insertions(+), 22 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index f66cf7e1d..f463a4a70 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -68,6 +68,7 @@ monitor = p_monitor; video_next_dts = 0; audio_next_pts = 0; audio_next_dts = 0; + Debug(2,"End VIdeoStore"); } // VideoStore::VideoStore @@ -152,18 +153,55 @@ Debug(2,"Using mjpeg"); video_out_ctx->pix_fmt = AV_PIX_FMT_YUVJ422P; } else if ( monitor->OutputCodec() == "h264" ) { -Debug(2,"Using h264"); + AVPixelFormat pf = AV_PIX_FMT_YUV420P; + + // First try hardware accell video_out_codec = avcodec_find_encoder_by_name("h264_omx"); if ( ! video_out_codec ) { Debug(1, "Didn't find omx"); video_out_codec = avcodec_find_encoder(AV_CODEC_ID_H264); } + if ( ! video_out_codec ) { + if ( AV_CODEC_ID_NONE == +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + video_in_stream->codecpar->codec_id +#else + video_in_stream->codec->codec_id +#endif + ) { + Debug(1, "trying xh264rgb"); + // We will be encoding rgb images, so prefer + video_out_codec = avcodec_find_encoder_by_name("libx264rgb"); + if ( ! video_out_codec ) { + video_out_codec = avcodec_find_encoder_by_name("libx264"); + } else { + pf = +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + video_in_stream->codecpar->format; +#else + video_in_stream->codec->pix_fmt; +#endif + } + } else { + video_out_codec = avcodec_find_encoder_by_name("libx264"); + pf = AV_PIX_FMT_YUV420P; + } + } + // Need to do lookup by codec_id if ( ! video_out_codec ) { Error("Didn't find h264 encoder"); video_out_codec = NULL; return false; } + Debug(1, "Using %s for codec", video_out_codec->name); video_out_ctx = avcodec_alloc_context3(video_out_codec); + if ( AV_CODEC_ID_H264 != video_out_ctx->codec_id ) { + Warning("Have to set codec_id?"); + video_out_ctx->codec_id = AV_CODEC_ID_H264; + } + + video_out_ctx->pix_fmt = pf; + } else { Error("No output codec selected"); return false; @@ -183,7 +221,7 @@ Debug(2,"Using h264"); Debug(2, "Going to dump the outctx"); zm_dump_codec(video_out_ctx); } - video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate + video_out_ctx->time_base = (AVRational){1, 1000}; // microseconds as base frame rate // Only set orientation if doing passthrough, otherwise the frame image will be rotated Monitor::Orientation orientation = monitor->getOrientation(); if ( orientation ) { @@ -248,25 +286,17 @@ Debug(2,"Using h264"); #endif } - video_out_ctx->codec_id = AV_CODEC_ID_H264; - //video_in_ctx->sample_aspect_ratio; - video_out_ctx->pix_fmt = AV_PIX_FMT_YUV420P; /* video time_base can be set to whatever is handy and supported by encoder */ - video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate - //video_out_ctx->framerate = (AVRational){0,24}; // Unknown framerate -#if 1 + video_out_ctx->time_base = (AVRational){1, 1000}; // microseconds as base frame rate video_out_ctx->gop_size = 12; video_out_ctx->qmin = 10; video_out_ctx->qmax = 51; video_out_ctx->qcompress = 0.6; - video_out_ctx->bit_rate = 4000000; -#endif + video_out_ctx->bit_rate = 400000; video_out_ctx->max_b_frames = 1; if ( video_out_ctx->codec_id == AV_CODEC_ID_H264 ) { if ( video_out_ctx->priv_data ) { - Debug(2, "Setting preset to supoerfast"); - av_opt_set(video_out_ctx->priv_data, "preset", "superfast", 0); - Debug(2, "Setting preset to supoerfast"); + av_opt_set(video_out_ctx->priv_data, "preset", "ultrafast", 0); } else { Debug(2, "Not setting priv_data"); } @@ -319,7 +349,7 @@ Debug(2,"Using h264"); if ( !video_out_ctx->codec_tag ) { video_out_ctx->codec_tag = - av_codec_get_tag(oc->oformat->codec_tag, AV_CODEC_ID_H264 ); + av_codec_get_tag(oc->oformat->codec_tag, video_out_ctx->codec_id ); Debug(2, "No codec_tag, setting to h264 ? "); } } // end if copying or trasncoding @@ -459,7 +489,9 @@ Debug(2,"Using h264"); AVDictionary *opts = NULL; // av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0); - av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0); + //av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0); + //av_dict_set(&opts, "movflags", "empty_moov+delay_moov", 0); + av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0); // av_dict_set(&opts, "movflags", // "frag_keyframe+empty_moov+default_base_moof", 0); if ( (ret = avformat_write_header(oc, &opts)) < 0 ) { @@ -1011,13 +1043,19 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { zm_packet->out_frame->sample_aspect_ratio = (AVRational){ 0, 1 }; if ( ! video_last_pts ) { - video_last_pts = zm_packet->timestamp->tv_sec*1000000 + zm_packet->timestamp->tv_usec; + int64_t temp = zm_packet->timestamp->tv_sec*1000; + int64_t temp2 = zm_packet->timestamp->tv_usec/1000; + video_last_pts = zm_packet->timestamp->tv_sec*1000 + zm_packet->timestamp->tv_usec/1000; + Debug(2, "No video_lsat_pts, set to (%" PRId64 ") secs(%d=>%" PRId64 ") usecs(%d=>%" PRId64 ")", + video_last_pts, zm_packet->timestamp->tv_sec, temp, zm_packet->timestamp->tv_usec, temp2 ); Debug(2, "No video_lsat_pts, set to (%" PRId64 ") secs(%d) usecs(%d)", video_last_pts, zm_packet->timestamp->tv_sec, zm_packet->timestamp->tv_usec ); zm_packet->out_frame->pts = 0; + zm_packet->out_frame->pkt_duration = 0; } else { //uint64_t seconds = zm_packet->timestamp->tv_sec*1000000; - zm_packet->out_frame->pts = ( zm_packet->timestamp->tv_sec*1000000 + zm_packet->timestamp->tv_usec ) - video_last_pts; + zm_packet->out_frame->pts = ( zm_packet->timestamp->tv_sec*1000 + zm_packet->timestamp->tv_usec/1000 ) - video_last_pts; + zm_packet->out_frame->duration = zm_packet->out_frame->pts - video_last_pts; Debug(2, " Setting pts for frame(%d), set to (%" PRId64 ") from (%" PRId64 " - secs(%d) usecs(%d)", frame_count, zm_packet->out_frame->pts, video_last_pts, zm_packet->timestamp->tv_sec, zm_packet->timestamp->tv_usec ); } @@ -1070,8 +1108,6 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { return 0; } #endif - //opkt.dts = opkt.pts; - //opkt.duration = 0; } else { AVPacket *ipkt = &zm_packet->packet; @@ -1082,15 +1118,16 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { opkt.size = ipkt->size; opkt.flags = ipkt->flags; if ( ! video_last_pts ) { - video_last_pts = zm_packet->timestamp->tv_sec*1000000 + zm_packet->timestamp->tv_usec; + video_last_pts = zm_packet->timestamp->tv_sec*1000 + zm_packet->timestamp->tv_usec/1000; opkt.dts = opkt.pts = 0; } else { - opkt.dts = opkt.pts = ( zm_packet->timestamp->tv_sec*1000000 + zm_packet->timestamp->tv_usec ) - video_last_pts; + opkt.dts = opkt.pts = ( zm_packet->timestamp->tv_sec*1000 + zm_packet->timestamp->tv_usec/1000 ) - video_last_pts; } } opkt.duration = 0; - Debug(3, "dts:%" PRId64 ", pts:%" PRId64 ", duration:%" PRId64 ", keyframe:%d", opkt.dts, opkt.pts, opkt.duration, opkt.flags & AV_PKT_FLAG_KEY ); + dumpPacket(&opkt); + write_video_packet( opkt ); zm_av_packet_unref(&opkt); From 135d3803fb3bb648f36bd27016e6fc941edce282 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 8 Dec 2017 10:39:24 -0500 Subject: [PATCH 0080/2339] make sure that we don't queue a packet twice --- src/zm_packetqueue.cpp | 59 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index 15383a703..e7514e08d 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -26,6 +26,7 @@ zm_packetqueue::zm_packetqueue( int video_image_count, int p_video_stream_id ) { max_video_packet_count = video_image_count-1; video_packet_count = 0; analysis_it = pktQueue.begin(); + first_video_packet_index = -1; } zm_packetqueue::~zm_packetqueue() { @@ -33,6 +34,43 @@ zm_packetqueue::~zm_packetqueue() { } bool zm_packetqueue::queuePacket( ZMPacket* zm_packet ) { + + if ( zm_packet->image_index != -1 ) { + // If we can never queue the same packet, then they can never go past + if ( zm_packet->image_index == first_video_packet_index ) { + Debug(2, "queuing packet that is already on the queue"); + ZMPacket *p; + while ( (p = pktQueue.front()) && ( p->image_index != zm_packet->image_index ) ) { + if ( *analysis_it == p ) { + Debug(2, "Increasing analysis_it"); + analysis_it ++; + } + + pktQueue.pop_front(); + if ( p->codec_type == AVMEDIA_TYPE_VIDEO ) { + Debug(2, "Descreasing video_packet_count (%d)", video_packet_count); + video_packet_count -= 1; + } else { + delete p; + } + } // end while there are packets at the head of the queue that are not this one + + if ( p->image_index == zm_packet->image_index ) { + // it should + video_packet_count -= 1; + pktQueue.pop_front(); + first_video_packet_index += 1; + first_video_packet_index %= max_video_packet_count; + + } else { + Error("SHould have found the packet!"); + } + } else if ( first_video_packet_index == -1 ) { + // Initialize the first_video_packet indicator + first_video_packet_index = zm_packet->image_index; + } // end if + } // end if queuing a video packet + pktQueue.push_back( zm_packet ); if ( zm_packet->codec_type == AVMEDIA_TYPE_VIDEO ) { video_packet_count += 1; @@ -47,7 +85,7 @@ bool zm_packetqueue::queuePacket( ZMPacket* zm_packet ) { } return true; -} +} // end bool zm_packetqueue::queuePacket(ZMPacket* zm_packet) ZMPacket* zm_packetqueue::popPacket( ) { if ( pktQueue.empty() ) { @@ -59,8 +97,15 @@ ZMPacket* zm_packetqueue::popPacket( ) { analysis_it ++; pktQueue.pop_front(); - if ( packet->codec_type == AVMEDIA_TYPE_VIDEO ) + if ( packet->codec_type == AVMEDIA_TYPE_VIDEO ) { video_packet_count -= 1; + if ( video_packet_count ) { + first_video_packet_index += 1; + first_video_packet_index %= max_video_packet_count; + } else { + first_video_packet_index = -1; + } + } return packet; } @@ -128,11 +173,19 @@ unsigned int zm_packetqueue::clearQueue( unsigned int frames_to_keep, int stream delete_count += 1; } // while our iterator is not the first packet + if ( pktQueue.size() ) { + packet = pktQueue.front(); + first_video_packet_index = packet->image_index; + } else { + first_video_packet_index = -1; + } + Debug(3, "Deleted (%d) packets", delete_count ); return delete_count; } // end unsigned int zm_packetqueue::clearQueue( unsigned int frames_to_keep, int stream_id ) void zm_packetqueue::clearQueue() { + mutex.lock(); ZMPacket *packet = NULL; while(!pktQueue.empty()) { packet = pktQueue.front(); @@ -141,7 +194,9 @@ void zm_packetqueue::clearQueue() { delete packet; } video_packet_count = 0; + first_video_packet_index = -1; analysis_it = pktQueue.begin(); + mutex.unlock(); } unsigned int zm_packetqueue::size() { From 533b370a81bc19c3d0876c6299dbc967eaed139a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 8 Dec 2017 10:39:57 -0500 Subject: [PATCH 0081/2339] add a mutex to the packetqueue --- src/zm_packetqueue.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/zm_packetqueue.h b/src/zm_packetqueue.h index a3a4a5ee0..de333e36d 100644 --- a/src/zm_packetqueue.h +++ b/src/zm_packetqueue.h @@ -25,6 +25,7 @@ //#include #include #include "zm_packet.h" +#include "zm_thread.h" extern "C" { #include @@ -37,11 +38,15 @@ class zm_packetqueue { int video_stream_id; int video_packet_count; // keep track of how many video packets we have, because we shouldn't have more than image_buffer_count + int first_video_packet_index; int max_video_packet_count; // allow a negative value to someday mean unlimited + Mutex mutex; + public: zm_packetqueue( int p_max_video_packet_count, int p_video_stream_id ); virtual ~zm_packetqueue(); + bool queuePacket( ZMPacket* packet ); ZMPacket * popPacket( ); unsigned int clearQueue( unsigned int video_frames_to_keep, int stream_id ); From aff08358f49aa3333c1a9d0bfdd6afee77c8e6f8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 8 Dec 2017 13:46:02 -0500 Subject: [PATCH 0082/2339] more debug --- src/zm_ffmpeg.cpp | 6 ++-- src/zm_monitor.cpp | 10 ++++--- src/zm_packetqueue.cpp | 31 ++++++++++++++----- src/zm_videostore.cpp | 68 ++++++++++++++++++++++-------------------- 4 files changed, 68 insertions(+), 47 deletions(-) diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index 9f94c274e..d433bcd45 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -230,12 +230,14 @@ static void zm_log_fps(double d, const char *postfix) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) void zm_dump_codecpar ( const AVCodecParameters *par ) { - Debug(1, "Dumping codecpar codec_type(%d) codec_id(%d) codec_tag(%d) width(%d) height(%d)", + Debug(1, "Dumping codecpar codec_type(%d) codec_id(%d) codec_tag(%d) width(%d) height(%d) bit_rate(%d) foramt(%d)", par->codec_type, par->codec_id, par->codec_tag, par->width, - par->height + par->height, + par->bit_rate, + par->format ); } #endif diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 37cd48567..f94f8a94e 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1245,11 +1245,12 @@ bool Monitor::Analyse() { return false; } - // if have event, sent frames until we find a video packet, at which point do analysis. Adaptive skip should only affect which frames we do analysis on. + // if have event, send frames until we find a video packet, at which point do analysis. Adaptive skip should only affect which frames we do analysis on. int packets_processed = 0; ZMPacket *snap; + // Is it possible for snap->score to be ! -1? while ( ( snap = packetqueue->get_analysis_packet() ) && ( snap->score == -1 ) ) { snap->lock(); unsigned int index = snap->image_index; @@ -1522,14 +1523,15 @@ Error("Already ahve evnet!"); // We can't just loop here forever, because we may be capturing just as fast, and never leave the loop. // Only loop until we hit the analysis index while ( ( queued_packet = packetqueue->popPacket() ) ) { - Debug(2,"adding packet (%d) qp lwindex(%d), written(%d)", queued_packet->image_index, last_write, written ); + Debug(2,"adding packet (%d) qp last_write_index(%d), written(%d)", queued_packet->image_index, last_write, written ); if ( snap == queued_packet ) { event->AddPacket( queued_packet ); - packetqueue->increment_analysis_it(); + // Pop may have already incrememented it + //packetqueue->increment_analysis_it(); break; } else { queued_packet->lock(); - Debug(2,"adding packet (%d) qp lwindex(%d), written(%d)", queued_packet->image_index, last_write, written ); + Debug(2,"adding packet (%d) qp last_write_index(%d), written(%d)", queued_packet->image_index, last_write, written ); event->AddPacket( queued_packet ); queued_packet->unlock(); } diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index e7514e08d..bb0840956 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -38,12 +38,12 @@ bool zm_packetqueue::queuePacket( ZMPacket* zm_packet ) { if ( zm_packet->image_index != -1 ) { // If we can never queue the same packet, then they can never go past if ( zm_packet->image_index == first_video_packet_index ) { - Debug(2, "queuing packet that is already on the queue"); + Debug(2, "queuing packet that is already on the queue(%d)", zm_packet->image_index ); ZMPacket *p; - while ( (p = pktQueue.front()) && ( p->image_index != zm_packet->image_index ) ) { - if ( *analysis_it == p ) { + while ( pktQueue.size() && (p = pktQueue.front()) && ( p->image_index != zm_packet->image_index ) ) { + if ( ( analysis_it != pktQueue.end() ) && ( *analysis_it == p ) ) { Debug(2, "Increasing analysis_it"); - analysis_it ++; + ++analysis_it; } pktQueue.pop_front(); @@ -51,11 +51,14 @@ bool zm_packetqueue::queuePacket( ZMPacket* zm_packet ) { Debug(2, "Descreasing video_packet_count (%d)", video_packet_count); video_packet_count -= 1; } else { + Debug(2, "Deleteing audio frame(%d)", p->image_index); delete p; + p = NULL; } + Debug(2,"pktQueue.size(%d)", pktQueue.size() ); } // end while there are packets at the head of the queue that are not this one - if ( p->image_index == zm_packet->image_index ) { + if ( p && ( p->image_index == zm_packet->image_index ) ) { // it should video_packet_count -= 1; pktQueue.pop_front(); @@ -100,6 +103,7 @@ ZMPacket* zm_packetqueue::popPacket( ) { if ( packet->codec_type == AVMEDIA_TYPE_VIDEO ) { video_packet_count -= 1; if ( video_packet_count ) { + // There is another video packet, so it must be the next one first_video_packet_index += 1; first_video_packet_index %= max_video_packet_count; } else { @@ -165,20 +169,31 @@ unsigned int zm_packetqueue::clearQueue( unsigned int frames_to_keep, int stream packet = pktQueue.front(); if ( *analysis_it == packet ) analysis_it ++; - if ( packet->codec_type == AVMEDIA_TYPE_VIDEO ) + if ( packet->codec_type == AVMEDIA_TYPE_VIDEO ) { video_packet_count -= 1; + if ( video_packet_count ) { + // There is another video packet, so it must be the next one + first_video_packet_index += 1; + first_video_packet_index %= max_video_packet_count; + } else { + first_video_packet_index = -1; + } + } pktQueue.pop_front(); if ( packet->image_index == -1 ) delete packet; delete_count += 1; } // while our iterator is not the first packet + +#if 0 if ( pktQueue.size() ) { packet = pktQueue.front(); first_video_packet_index = packet->image_index; } else { first_video_packet_index = -1; } +#endif Debug(3, "Deleted (%d) packets", delete_count ); return delete_count; @@ -215,8 +230,8 @@ ZMPacket *zm_packetqueue::get_analysis_packet() { if ( analysis_it == pktQueue.end() ) return NULL; - Debug(2, "Distance from head: (%d)", std::distance( pktQueue.begin(), analysis_it ) ); - Debug(2, "Distance from end: (%d)", std::distance( analysis_it, pktQueue.end() ) ); +//Debug(2, "Distance from head: (%d)", std::distance( pktQueue.begin(), analysis_it ) ); + //Debug(2, "Distance from end: (%d)", std::distance( analysis_it, pktQueue.end() ) ); return *analysis_it; } // end ZMPacket *zm_packetqueue::get_analysis_packet() diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index f463a4a70..aeb6c2f93 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -177,7 +177,7 @@ Debug(2,"Using mjpeg"); } else { pf = #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - video_in_stream->codecpar->format; + (AVPixelFormat)video_in_stream->codecpar->format; #else video_in_stream->codec->pix_fmt; #endif @@ -289,8 +289,8 @@ Debug(2,"Using mjpeg"); /* video time_base can be set to whatever is handy and supported by encoder */ video_out_ctx->time_base = (AVRational){1, 1000}; // microseconds as base frame rate video_out_ctx->gop_size = 12; - video_out_ctx->qmin = 10; - video_out_ctx->qmax = 51; + video_out_ctx->qmin = 2; + video_out_ctx->qmax = 31; video_out_ctx->qcompress = 0.6; video_out_ctx->bit_rate = 400000; video_out_ctx->max_b_frames = 1; @@ -339,7 +339,7 @@ Debug(2,"Using mjpeg"); return false; } - } + } // end if can't open codec Debug(2,"Sucess opening codec"); AVDictionaryEntry *e = NULL; while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { @@ -714,6 +714,7 @@ VideoStore::~VideoStore() { } bool VideoStore::setup_resampler() { + //I think this is unneccessary, we should be able to just pass in the decoder from the input. #ifdef HAVE_LIBAVRESAMPLE // Newer ffmpeg wants to keep everything separate... so have to lookup our own // decoder, can't reuse the one from the camera. @@ -740,7 +741,6 @@ bool VideoStore::setup_resampler() { audio_out_stream = avformat_new_stream(oc, audio_out_codec); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - // audio_out_ctx = audio_out_stream->codec; audio_out_ctx = avcodec_alloc_context3(audio_out_codec); if ( !audio_out_ctx ) { Error("could not allocate codec ctx for AAC\n"); @@ -754,10 +754,9 @@ bool VideoStore::setup_resampler() { /* put sample parameters */ audio_out_ctx->bit_rate = audio_in_ctx->bit_rate; audio_out_ctx->sample_rate = audio_in_ctx->sample_rate; + audio_out_ctx->sample_fmt = audio_in_ctx->sample_fmt; audio_out_ctx->channels = audio_in_ctx->channels; audio_out_ctx->channel_layout = audio_in_ctx->channel_layout; - audio_out_ctx->sample_fmt = audio_in_ctx->sample_fmt; - //audio_out_ctx->refcounted_frames = 1; if ( audio_out_codec->supported_samplerates ) { int found = 0; @@ -785,21 +784,10 @@ bool VideoStore::setup_resampler() { audio_out_ctx->sample_fmt = AV_SAMPLE_FMT_FLTP; } - audio_out_ctx->time_base = (AVRational){1, audio_out_ctx->sample_rate}; + // Example code doesn't set the codec tb. I think it just uses whatever defaults + //audio_out_ctx->time_base = (AVRational){1, audio_out_ctx->sample_rate}; -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - if ( (ret = avcodec_parameters_from_context(audio_out_stream->codecpar, - audio_out_ctx)) < 0 ) { - Error("Could not initialize stream parameteres"); - return false; - } - audio_out_stream->codecpar->frame_size = audio_out_ctx->frame_size; -#else - avcodec_copy_context( audio_out_stream->codec, audio_out_ctx ); -#endif - audio_out_stream->time_base = (AVRational){1, audio_out_ctx->sample_rate}; - AVDictionary *opts = NULL; av_dict_set(&opts, "strict", "experimental", 0); // Needed to allow AAC ret = avcodec_open2(audio_out_ctx, audio_out_codec, &opts); @@ -812,8 +800,22 @@ bool VideoStore::setup_resampler() { return false; } + audio_out_stream->time_base = (AVRational){1, audio_out_ctx->sample_rate}; +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + if ( (ret = avcodec_parameters_from_context( + audio_out_stream->codecpar, + audio_out_ctx)) < 0 ) { + Error("Could not initialize stream parameteres"); + return false; + } + //audio_out_stream->codecpar->frame_size = audio_out_ctx->frame_size; + //audio_out_stream->codecpar->bit_rate = audio_out_ctx->bit_rate; +#else + avcodec_copy_context( audio_out_stream->codec, audio_out_ctx ); +#endif + Debug(1, - "Audio out bit_rate (%d) sample_rate(%d) channels(%d) fmt(%d) " + "Audio out context bit_rate (%d) sample_rate(%d) channels(%d) fmt(%d) " "layout(%d) frame_size(%d)", audio_out_ctx->bit_rate, audio_out_ctx->sample_rate, audio_out_ctx->channels, audio_out_ctx->sample_fmt, @@ -821,7 +823,7 @@ bool VideoStore::setup_resampler() { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) Debug(1, - "Audio out bit_rate (%d) sample_rate(%d) channels(%d) fmt(%d) " + "Audio out stream bit_rate (%d) sample_rate(%d) channels(%d) fmt(%d) " "layout(%d) frame_size(%d)", audio_out_stream->codecpar->bit_rate, audio_out_stream->codecpar->sample_rate, audio_out_stream->codecpar->channels, audio_out_stream->codecpar->format, @@ -849,6 +851,7 @@ bool VideoStore::setup_resampler() { av_frame_free(&in_frame); return false; } + out_frame->sample_rate = audio_out_ctx->sample_rate; // Setup the audio resampler resample_ctx = avresample_alloc_context(); @@ -857,13 +860,13 @@ bool VideoStore::setup_resampler() { return false; } + uint64_t mono_layout = av_get_channel_layout("mono"); // Some formats (i.e. WAV) do not produce the proper channel layout if ( audio_in_ctx->channel_layout == 0 ) { - uint64_t layout = av_get_channel_layout("mono"); - av_opt_set_int(resample_ctx, "in_channel_layout", - av_get_channel_layout("mono"), 0); - Debug(1, "Bad channel layout. Need to set it to mono (%d).", layout); + av_opt_set_int(resample_ctx, "in_channel_layout", mono_layout, 0); + Debug(1, "Bad channel layout. Need to set it to mono (%d).", mono_layout); } else { + Debug(1, "channel layout. set it to mono (%d).", audio_in_ctx->channel_layout); av_opt_set_int(resample_ctx, "in_channel_layout", audio_in_ctx->channel_layout, 0); } @@ -873,8 +876,7 @@ bool VideoStore::setup_resampler() { av_opt_set_int(resample_ctx, "in_channels", audio_in_ctx->channels, 0); // av_opt_set_int( resample_ctx, "out_channel_layout", // audio_out_ctx->channel_layout, 0); - av_opt_set_int(resample_ctx, "out_channel_layout", - av_get_channel_layout("mono"), 0); + av_opt_set_int(resample_ctx, "out_channel_layout", mono_layout, 0); av_opt_set_int(resample_ctx, "out_sample_fmt", audio_out_ctx->sample_fmt, 0); av_opt_set_int(resample_ctx, "out_sample_rate", @@ -926,7 +928,7 @@ void VideoStore::dumpPacket(AVPacket *pkt) { snprintf(b, sizeof(b), " pts: %" PRId64 ", dts: %" PRId64 - ", data: %p, size: %d, sindex: %d, dflags: %04x, s-pos: %" PRId64 + ", data: %p, size: %d, stream_index: %d, dflags: %04x, pos: %" PRId64 ", duration: %" #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) PRId64 @@ -1041,6 +1043,7 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { zm_packet->out_frame->coded_picture_number = frame_count; zm_packet->out_frame->display_picture_number = frame_count; zm_packet->out_frame->sample_aspect_ratio = (AVRational){ 0, 1 }; + zm_packet->out_frame->pkt_duration = 0; if ( ! video_last_pts ) { int64_t temp = zm_packet->timestamp->tv_sec*1000; @@ -1051,11 +1054,10 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { Debug(2, "No video_lsat_pts, set to (%" PRId64 ") secs(%d) usecs(%d)", video_last_pts, zm_packet->timestamp->tv_sec, zm_packet->timestamp->tv_usec ); zm_packet->out_frame->pts = 0; - zm_packet->out_frame->pkt_duration = 0; } else { //uint64_t seconds = zm_packet->timestamp->tv_sec*1000000; zm_packet->out_frame->pts = ( zm_packet->timestamp->tv_sec*1000 + zm_packet->timestamp->tv_usec/1000 ) - video_last_pts; - zm_packet->out_frame->duration = zm_packet->out_frame->pts - video_last_pts; + zm_packet->out_frame->pkt_duration = zm_packet->out_frame->pts - video_last_pts; Debug(2, " Setting pts for frame(%d), set to (%" PRId64 ") from (%" PRId64 " - secs(%d) usecs(%d)", frame_count, zm_packet->out_frame->pts, video_last_pts, zm_packet->timestamp->tv_sec, zm_packet->timestamp->tv_usec ); } @@ -1124,8 +1126,8 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { opkt.dts = opkt.pts = ( zm_packet->timestamp->tv_sec*1000 + zm_packet->timestamp->tv_usec/1000 ) - video_last_pts; } } - opkt.duration = 0; + opkt.duration = 0; dumpPacket(&opkt); write_video_packet( opkt ); @@ -1245,7 +1247,7 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { // Resample the in into the audioSampleBuffer until we proceed the whole // decoded data if ((ret = avresample_convert(resample_ctx, NULL, 0, 0, in_frame->data, - 0, frame_size)) < 0) { + 0, in_frame->nb_samples)) < 0) { Error("Could not resample frame (error '%s')\n", av_make_error_string(ret).c_str()); av_frame_unref(in_frame); From 011c7e15408565eb54ba77b2beb37131eb42e05c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 8 Dec 2017 14:22:38 -0500 Subject: [PATCH 0083/2339] revert to /1000000 tb --- src/zm_videostore.cpp | 75 +++++++++++++++++----------------------- web/includes/actions.php | 5 ++- web/index.php | 2 +- 3 files changed, 35 insertions(+), 47 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index aeb6c2f93..d2d59b8d7 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -208,6 +208,7 @@ Debug(2,"Using mjpeg"); } // Copy params from instream to ctx + // // FIXME SHould check that we are set to passthrough if ( video_in_stream && ( video_in_ctx->codec_id == AV_CODEC_ID_H264 ) ) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) ret = avcodec_parameters_to_context(video_out_ctx, video_in_stream->codecpar); @@ -221,25 +222,7 @@ Debug(2,"Using mjpeg"); Debug(2, "Going to dump the outctx"); zm_dump_codec(video_out_ctx); } - video_out_ctx->time_base = (AVRational){1, 1000}; // microseconds as base frame rate - // Only set orientation if doing passthrough, otherwise the frame image will be rotated - Monitor::Orientation orientation = monitor->getOrientation(); - if ( orientation ) { - Debug(3, "Have orientation"); - if ( orientation == Monitor::ROTATE_0 ) { - } else if ( orientation == Monitor::ROTATE_90 ) { - ret = av_dict_set(&video_out_stream->metadata, "rotate", "90", 0); - if ( ret < 0 ) Warning("%s:%d: title set failed", __FILE__, __LINE__); - } else if ( orientation == Monitor::ROTATE_180 ) { - ret = av_dict_set(&video_out_stream->metadata, "rotate", "180", 0); - if ( ret < 0 ) Warning("%s:%d: title set failed", __FILE__, __LINE__); - } else if ( orientation == Monitor::ROTATE_270 ) { - ret = av_dict_set(&video_out_stream->metadata, "rotate", "270", 0); - if ( ret < 0 ) Warning("%s:%d: title set failed", __FILE__, __LINE__); - } else { - Warning("Unsupported Orientation(%d)", orientation); - } - } + video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate if ( oc->oformat->flags & AVFMT_GLOBALHEADER ) { #if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) video_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; @@ -287,7 +270,7 @@ Debug(2,"Using mjpeg"); } /* video time_base can be set to whatever is handy and supported by encoder */ - video_out_ctx->time_base = (AVRational){1, 1000}; // microseconds as base frame rate + video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate video_out_ctx->gop_size = 12; video_out_ctx->qmin = 2; video_out_ctx->qmax = 31; @@ -375,18 +358,32 @@ Debug(2,"Using mjpeg"); zm_dump_codec(video_out_stream->codec); #endif -#if 1 +#if 0 + // No point apparently. They may change when opening the file. video_out_stream->time_base.num = video_out_ctx->time_base.num; video_out_stream->time_base.den = video_out_ctx->time_base.den; #endif - Debug(3, - "Time bases: VIDEO out stream: (%d/%d) out codec (%d/%d)", - video_out_stream->time_base.num, - video_out_stream->time_base.den, - video_out_ctx->time_base.num, - video_out_ctx->time_base.den); - + if ( video_in_stream && ( video_in_ctx->codec_id == AV_CODEC_ID_H264 ) ) { + // Only set orientation if doing passthrough, otherwise the frame image will be rotated + Monitor::Orientation orientation = monitor->getOrientation(); + if ( orientation ) { + Debug(3, "Have orientation"); + if ( orientation == Monitor::ROTATE_0 ) { + } else if ( orientation == Monitor::ROTATE_90 ) { + ret = av_dict_set(&video_out_stream->metadata, "rotate", "90", 0); + if ( ret < 0 ) Warning("%s:%d: title set failed", __FILE__, __LINE__); + } else if ( orientation == Monitor::ROTATE_180 ) { + ret = av_dict_set(&video_out_stream->metadata, "rotate", "180", 0); + if ( ret < 0 ) Warning("%s:%d: title set failed", __FILE__, __LINE__); + } else if ( orientation == Monitor::ROTATE_270 ) { + ret = av_dict_set(&video_out_stream->metadata, "rotate", "270", 0); + if ( ret < 0 ) Warning("%s:%d: title set failed", __FILE__, __LINE__); + } else { + Warning("Unsupported Orientation(%d)", orientation); + } + } + } if ( audio_in_stream ) { Debug(3, "Have audio stream"); @@ -488,12 +485,7 @@ Debug(2,"Using mjpeg"); if (audio_out_stream) zm_dump_stream_format(oc, 1, 0, 1); AVDictionary *opts = NULL; - // av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0); - //av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0); - //av_dict_set(&opts, "movflags", "empty_moov+delay_moov", 0); av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0); - // av_dict_set(&opts, "movflags", - // "frag_keyframe+empty_moov+default_base_moof", 0); if ( (ret = avformat_write_header(oc, &opts)) < 0 ) { // if ((ret = avformat_write_header(oc, &opts)) < 0) { Warning("Unable to set movflags to frag_custom+dash+delay_moov"); @@ -1046,9 +1038,9 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { zm_packet->out_frame->pkt_duration = 0; if ( ! video_last_pts ) { - int64_t temp = zm_packet->timestamp->tv_sec*1000; - int64_t temp2 = zm_packet->timestamp->tv_usec/1000; - video_last_pts = zm_packet->timestamp->tv_sec*1000 + zm_packet->timestamp->tv_usec/1000; + int64_t temp = zm_packet->timestamp->tv_sec*1000000; + int64_t temp2 = zm_packet->timestamp->tv_usec; + video_last_pts = zm_packet->timestamp->tv_sec*1000000 + zm_packet->timestamp->tv_usec; Debug(2, "No video_lsat_pts, set to (%" PRId64 ") secs(%d=>%" PRId64 ") usecs(%d=>%" PRId64 ")", video_last_pts, zm_packet->timestamp->tv_sec, temp, zm_packet->timestamp->tv_usec, temp2 ); Debug(2, "No video_lsat_pts, set to (%" PRId64 ") secs(%d) usecs(%d)", @@ -1056,7 +1048,7 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { zm_packet->out_frame->pts = 0; } else { //uint64_t seconds = zm_packet->timestamp->tv_sec*1000000; - zm_packet->out_frame->pts = ( zm_packet->timestamp->tv_sec*1000 + zm_packet->timestamp->tv_usec/1000 ) - video_last_pts; + zm_packet->out_frame->pts = ( zm_packet->timestamp->tv_sec*1000000 + zm_packet->timestamp->tv_usec ) - video_last_pts; zm_packet->out_frame->pkt_duration = zm_packet->out_frame->pts - video_last_pts; Debug(2, " Setting pts for frame(%d), set to (%" PRId64 ") from (%" PRId64 " - secs(%d) usecs(%d)", frame_count, zm_packet->out_frame->pts, video_last_pts, zm_packet->timestamp->tv_sec, zm_packet->timestamp->tv_usec ); @@ -1120,10 +1112,10 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { opkt.size = ipkt->size; opkt.flags = ipkt->flags; if ( ! video_last_pts ) { - video_last_pts = zm_packet->timestamp->tv_sec*1000 + zm_packet->timestamp->tv_usec/1000; + video_last_pts = zm_packet->timestamp->tv_sec*1000000 + zm_packet->timestamp->tv_usec; opkt.dts = opkt.pts = 0; } else { - opkt.dts = opkt.pts = ( zm_packet->timestamp->tv_sec*1000 + zm_packet->timestamp->tv_usec/1000 ) - video_last_pts; + opkt.dts = opkt.pts = ( zm_packet->timestamp->tv_sec*1000000 + zm_packet->timestamp->tv_usec ) - video_last_pts; } } @@ -1146,15 +1138,12 @@ void VideoStore::write_video_packet( AVPacket &opkt ) { opkt.dts = opkt.pts; } - //opkt.pos = -1; opkt.stream_index = video_out_stream->index; //video_next_dts += opkt.duration; //video_next_pts += opkt.duration; - //AVPacket safepkt; - //memcpy(&safepkt, &opkt, sizeof(AVPacket)); - //av_packet_rescale_ts( &opkt, video_out_ctx->time_base, video_out_stream->time_base ); + av_packet_rescale_ts( &opkt, video_out_ctx->time_base, video_out_stream->time_base ); Debug(1, "writing video packet pts(%" PRId64 ") dts(%" PRId64 ") duration(%" PRId64 ") packet_count(%u)", diff --git a/web/includes/actions.php b/web/includes/actions.php index 8f73dc4b8..36f3fcf75 100644 --- a/web/includes/actions.php +++ b/web/includes/actions.php @@ -857,13 +857,12 @@ if ( canEdit( 'System' ) ) { if ( $value['Type'] == 'boolean' && empty($_REQUEST['newConfig'][$name]) ) $newValue = 0; elseif ( isset($_REQUEST['newConfig'][$name]) ) - $newValue = preg_replace( "/\r\n/', '\n", stripslashes( $_REQUEST['newConfig'][$name] ) ); - + $newValue = preg_replace( "/\r\n/", "\n", stripslashes( $_REQUEST['newConfig'][$name] ) ); if ( isset($newValue) && ($newValue != $value['Value']) ) { dbQuery( 'UPDATE Config SET Value=? WHERE Name=?', array( $newValue, $name ) ); $changed = true; } - } + } // end foreach config entry if ( $changed ) { switch( $_REQUEST['tab'] ) { case 'system' : diff --git a/web/index.php b/web/index.php index eb406ceb3..bc5e9c228 100644 --- a/web/index.php +++ b/web/index.php @@ -34,7 +34,7 @@ if ( version_compare( phpversion(), '4.1.0', '<') ) { } // Useful debugging lines for mobile devices -if ( false ) { +if ( true ) { ob_start(); phpinfo( INFO_VARIABLES ); $fp = fopen( '/tmp/env.html', 'w' ); From af37eeeeed77d7a4ab494a995f51aa997d07e512 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 8 Dec 2017 15:17:45 -0500 Subject: [PATCH 0084/2339] fix int64 = int*int multiply --- src/zm_analysis_thread.cpp | 1 + src/zm_monitor.cpp | 2 ++ src/zm_videostore.cpp | 42 ++++++++++++++++---------------------- src/zm_videostore.h | 7 ++----- 4 files changed, 23 insertions(+), 29 deletions(-) diff --git a/src/zm_analysis_thread.cpp b/src/zm_analysis_thread.cpp index 1fe0cc4d1..400bc8612 100644 --- a/src/zm_analysis_thread.cpp +++ b/src/zm_analysis_thread.cpp @@ -24,6 +24,7 @@ int AnalysisThread::run() { Debug(2, "THREAD: Getting ref image"); monitor->get_ref_image(); + Debug(2, "THREAD: after Getting ref image"); while( !terminate ) { // Process the next image diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index f94f8a94e..1576eedeb 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -3260,5 +3260,7 @@ void Monitor::get_ref_image() { Warning( "Waiting for capture daemon" ); usleep( 100000 ); } + image_buffer[shared_data->last_write_index].mutex.lock(); ref_image.Assign( width, height, camera->Colours(), camera->SubpixelOrder(), image_buffer[shared_data->last_write_index].image->Buffer(), camera->ImageSize()); + image_buffer[shared_data->last_write_index].mutex.unlock(); } diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index d2d59b8d7..b6c7fdb09 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -60,12 +60,7 @@ monitor = p_monitor; #endif FFMPEGInit(); - video_last_pts = 0; - video_last_dts = 0; - audio_last_pts = 0; - audio_last_dts = 0; - video_next_pts = 0; - video_next_dts = 0; + video_start_pts = 0; audio_next_pts = 0; audio_next_dts = 0; @@ -272,10 +267,10 @@ Debug(2,"Using mjpeg"); /* video time_base can be set to whatever is handy and supported by encoder */ video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate video_out_ctx->gop_size = 12; - video_out_ctx->qmin = 2; - video_out_ctx->qmax = 31; + video_out_ctx->qmin = 10; + video_out_ctx->qmax = 51; video_out_ctx->qcompress = 0.6; - video_out_ctx->bit_rate = 400000; + video_out_ctx->bit_rate = 4000000; video_out_ctx->max_b_frames = 1; if ( video_out_ctx->codec_id == AV_CODEC_ID_H264 ) { if ( video_out_ctx->priv_data ) { @@ -1037,21 +1032,20 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { zm_packet->out_frame->sample_aspect_ratio = (AVRational){ 0, 1 }; zm_packet->out_frame->pkt_duration = 0; - if ( ! video_last_pts ) { - int64_t temp = zm_packet->timestamp->tv_sec*1000000; - int64_t temp2 = zm_packet->timestamp->tv_usec; - video_last_pts = zm_packet->timestamp->tv_sec*1000000 + zm_packet->timestamp->tv_usec; - Debug(2, "No video_lsat_pts, set to (%" PRId64 ") secs(%d=>%" PRId64 ") usecs(%d=>%" PRId64 ")", - video_last_pts, zm_packet->timestamp->tv_sec, temp, zm_packet->timestamp->tv_usec, temp2 ); + if ( ! video_start_pts ) { + uint64_t temp = zm_packet->timestamp->tv_sec*(uint64_t)1000000; + video_start_pts = temp + zm_packet->timestamp->tv_usec; + Debug(2, "No video_lsat_pts, set to (%" PRId64 ") secs(%d=>%" PRId64 ") usecs(%d)", + video_start_pts, zm_packet->timestamp->tv_sec, temp, zm_packet->timestamp->tv_usec ); Debug(2, "No video_lsat_pts, set to (%" PRId64 ") secs(%d) usecs(%d)", - video_last_pts, zm_packet->timestamp->tv_sec, zm_packet->timestamp->tv_usec ); + video_start_pts, zm_packet->timestamp->tv_sec, zm_packet->timestamp->tv_usec ); zm_packet->out_frame->pts = 0; } else { - //uint64_t seconds = zm_packet->timestamp->tv_sec*1000000; - zm_packet->out_frame->pts = ( zm_packet->timestamp->tv_sec*1000000 + zm_packet->timestamp->tv_usec ) - video_last_pts; - zm_packet->out_frame->pkt_duration = zm_packet->out_frame->pts - video_last_pts; - Debug(2, " Setting pts for frame(%d), set to (%" PRId64 ") from (%" PRId64 " - secs(%d) usecs(%d)", - frame_count, zm_packet->out_frame->pts, video_last_pts, zm_packet->timestamp->tv_sec, zm_packet->timestamp->tv_usec ); + uint64_t seconds = zm_packet->timestamp->tv_sec*(uint64_t)1000000; + zm_packet->out_frame->pts = ( seconds + zm_packet->timestamp->tv_usec ) - video_start_pts; + //zm_packet->out_frame->pkt_duration = zm_packet->out_frame->pts - video_start_pts; + Debug(2, " Setting pts for frame(%d), set to (%" PRId64 ") from (start %" PRIu64 " - %" PRIu64 " - secs(%d) usecs(%d)", + frame_count, zm_packet->out_frame->pts, video_start_pts, seconds, zm_packet->timestamp->tv_sec, zm_packet->timestamp->tv_usec ); } if ( zm_packet->keyframe ) { //Debug(2, "Setting keyframe was (%d)", zm_packet->out_frame->key_frame ); @@ -1111,11 +1105,11 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { opkt.data = ipkt->data; opkt.size = ipkt->size; opkt.flags = ipkt->flags; - if ( ! video_last_pts ) { - video_last_pts = zm_packet->timestamp->tv_sec*1000000 + zm_packet->timestamp->tv_usec; + if ( ! video_start_pts ) { + video_start_pts = zm_packet->timestamp->tv_sec*(uint64_t)1000000 + zm_packet->timestamp->tv_usec; opkt.dts = opkt.pts = 0; } else { - opkt.dts = opkt.pts = ( zm_packet->timestamp->tv_sec*1000000 + zm_packet->timestamp->tv_usec ) - video_last_pts; + opkt.dts = opkt.pts = ( zm_packet->timestamp->tv_sec*(uint64_t)1000000 + zm_packet->timestamp->tv_usec ) - video_start_pts; } } diff --git a/src/zm_videostore.h b/src/zm_videostore.h index 55a99e0ee..8c8178e14 100644 --- a/src/zm_videostore.h +++ b/src/zm_videostore.h @@ -61,15 +61,12 @@ AVAudioResampleContext* resample_ctx; const char *format; // These are for in - int64_t video_last_pts; - int64_t video_last_dts; - int64_t video_last_duration; + uint64_t video_start_pts; + int64_t audio_last_pts; int64_t audio_last_dts; // These are for out, should start at zero. We assume they do not wrap because we just aren't going to save files that big. - int64_t video_next_pts; - int64_t video_next_dts; ; int64_t audio_next_pts; int64_t audio_next_dts; From 2f23f81ff3bfeb2627066ef5a015ac08ce01637f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 8 Dec 2017 21:28:30 -0500 Subject: [PATCH 0085/2339] store a snaphost when we don't storae anything else as opposed to when specifically storing a snpashot --- src/zm_event.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 94bdc852f..8cedced4a 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -390,7 +390,7 @@ void Event::AddFramesInternal( int n_frames, int start_frame, Image **images, st static char event_file[PATH_MAX]; snprintf( event_file, sizeof(event_file), staticConfig.capture_file_format, path, frames ); - if ( monitor->GetOptSaveJPEGs() & 4 ) { + if ( ! ( monitor->GetOptSaveJPEGs() & 3 ) ) { //If this is the first frame, we should add a thumbnail to the event directory // ICON: We are working through the pre-event frames so this snapshot won't // neccessarily be of the motion. But some events are less than 10 frames, @@ -457,7 +457,8 @@ void Event::AddFrame( Image *image, struct timeval timestamp, int score, Image * static char event_file[PATH_MAX]; snprintf( event_file, sizeof(event_file), staticConfig.capture_file_format, path, frames ); - if ( monitor->GetOptSaveJPEGs() & 4 ) { + if ( ! ( monitor->GetOptSaveJPEGs() & 3 ) ) { + //if ( monitor->GetOptSaveJPEGs() & 4 ) { // Only snapshots //If this is the first frame, we should add a thumbnail to the event directory if ( frames == 10 || frames == 1 ) { From 9a5371c3717cac86b4b2a9eae02b0bda7b4730ab Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 8 Dec 2017 21:28:47 -0500 Subject: [PATCH 0086/2339] don't exit on capture fail --- src/zmc.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/zmc.cpp b/src/zmc.cpp index 5110827bf..c8274ef2e 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -254,7 +254,7 @@ int main(int argc, char *argv[]) { last_capture_times[i].tv_sec = last_capture_times[i].tv_usec = 0; capture_delays[i] = monitors[i]->GetCaptureDelay(); alarm_capture_delays[i] = monitors[i]->GetAlarmCaptureDelay(); - Debug(2, "capture delay(%l) alarm delay(%l)", capture_delays[i], alarm_capture_delays[i] ); + Debug(2, "capture delay(%u) alarm delay(%u)", capture_delays[i], alarm_capture_delays[i] ); Monitor::Function function = monitors[0]->GetFunction(); if ( function == Monitor::MODECT || function == Monitor::MOCORD || function == Monitor::RECORD) { @@ -305,7 +305,6 @@ int main(int argc, char *argv[]) { } if ( monitors[i]->Capture() < 0 ) { Error("Failed to capture image from monitor %d %s (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors); - zm_terminate = true; result = -1; break; } From dd384e9e6d7694e05e5b7dee61013d3ada4e90ec Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 8 Dec 2017 21:29:05 -0500 Subject: [PATCH 0087/2339] reduce wait time when waiting for first frame --- src/zm_monitor.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 1576eedeb..57c8cc880 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -3258,9 +3258,12 @@ void Monitor::get_ref_image() { && ! zm_terminate ) { Warning( "Waiting for capture daemon" ); - usleep( 100000 ); + usleep( 50000 ); } - image_buffer[shared_data->last_write_index].mutex.lock(); - ref_image.Assign( width, height, camera->Colours(), camera->SubpixelOrder(), image_buffer[shared_data->last_write_index].image->Buffer(), camera->ImageSize()); - image_buffer[shared_data->last_write_index].mutex.unlock(); + int last_write_index = shared_data->last_write_index ; + + Warning( "Waiting for capture daemon unlock" ); + image_buffer[last_write_index].mutex.lock(); + ref_image.Assign( width, height, camera->Colours(), camera->SubpixelOrder(), image_buffer[last_write_index].image->Buffer(), camera->ImageSize()); + image_buffer[last_write_index].mutex.unlock(); } From a0532cd84ac0966ee9f18c88175b78b26b52606e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 12 Dec 2017 15:30:47 -0500 Subject: [PATCH 0088/2339] fix merge --- src/zm_videostore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 7846b5ece..1492f023a 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -88,7 +88,7 @@ bool VideoStore::open() { "Could not create video storage stream %s as no out ctx" " could not be assigned based on filename or format %s", filename, format); - return; + return false; } else { Debug(4, "Success alocating out ctx"); } From 4e32a002e6b402819af4af2dd5377f8001f2acf6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 14 Dec 2017 15:56:22 -0500 Subject: [PATCH 0089/2339] Fix timestamps on passthrough video. --- src/zm_ffmpeg.cpp | 10 +++++---- src/zm_videostore.cpp | 52 +++++++++++++++++++++---------------------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index 289fdda09..ebe178ac4 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -230,26 +230,28 @@ static void zm_log_fps(double d, const char *postfix) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) void zm_dump_codecpar ( const AVCodecParameters *par ) { - Debug(1, "Dumping codecpar codec_type(%d) codec_id(%d) codec_tag(%d) width(%d) height(%d) bit_rate(%d) foramt(%d)", + Debug(1, "Dumping codecpar codec_type(%d) codec_id(%d) codec_tag(%d) width(%d) height(%d) bit_rate(%d) format(%d = %s)", par->codec_type, par->codec_id, par->codec_tag, par->width, par->height, par->bit_rate, - par->format + par->format, + ((AVPixelFormat)par->format == AV_PIX_FMT_NONE ? "none" : av_get_pix_fmt_name((AVPixelFormat)par->format)) ); } #endif void zm_dump_codec ( const AVCodecContext *codec ) { - Debug(1, "Dumping codec_context codec_type(%d) codec_id(%d) width(%d) height(%d) timebase(%d/%d)", + Debug(1, "Dumping codec_context codec_type(%d) codec_id(%d) width(%d) height(%d) timebase(%d/%d) format(%s)", codec->codec_type, codec->codec_id, codec->width, codec->height, codec->time_base.num, - codec->time_base.den + codec->time_base.den, + (codec->pix_fmt == AV_PIX_FMT_NONE ? "none" : av_get_pix_fmt_name(codec->pix_fmt)) ); } diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 1492f023a..c7be5c221 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -63,8 +63,6 @@ monitor = p_monitor; video_start_pts = 0; audio_next_pts = 0; audio_next_dts = 0; - -Debug(2,"End VIdeoStore"); } // VideoStore::VideoStore bool VideoStore::open() { @@ -152,7 +150,7 @@ Debug(2,"Using mjpeg"); video_out_ctx->codec_id = video_out_codec->id; video_out_ctx->pix_fmt = AV_PIX_FMT_YUVJ422P; - } else if ( monitor->OutputCodec() == "h264" ) { + } else if ( monitor->OutputCodec() == "h264" || monitor->OutputCodec() == "" ) { AVPixelFormat pf = AV_PIX_FMT_YUV420P; // First try hardware accell @@ -203,7 +201,7 @@ Debug(2,"Using mjpeg"); video_out_ctx->pix_fmt = pf; } else { - Error("No output codec selected"); + Error("Unsupported output codec selected"); return false; } @@ -218,11 +216,10 @@ Debug(2,"Using mjpeg"); if ( ret < 0 ) { Error("Could not initialize ctx parameteres"); return false; - } else { - Debug(2, "Going to dump the outctx"); - zm_dump_codec(video_out_ctx); } - video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate + //video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate + video_out_ctx->time_base = video_in_ctx->time_base; + if ( oc->oformat->flags & AVFMT_GLOBALHEADER ) { #if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) video_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; @@ -232,9 +229,6 @@ Debug(2,"Using mjpeg"); } // Fix deprecated formats switch ( video_out_ctx->pix_fmt ) { - case AV_PIX_FMT_YUVJ420P : - video_out_ctx->pix_fmt = AV_PIX_FMT_YUV420P; - break; case AV_PIX_FMT_YUVJ422P : video_out_ctx->pix_fmt = AV_PIX_FMT_YUV422P; break; @@ -244,10 +238,13 @@ Debug(2,"Using mjpeg"); case AV_PIX_FMT_YUVJ440P : video_out_ctx->pix_fmt = AV_PIX_FMT_YUV440P; break; + case AV_PIX_FMT_NONE : + case AV_PIX_FMT_YUVJ420P : default: video_out_ctx->pix_fmt = AV_PIX_FMT_YUV420P; break; } + zm_dump_codec(video_out_ctx); } else { @@ -339,9 +336,8 @@ Debug(2,"Using mjpeg"); video_out_stream = avformat_new_stream(oc, video_out_codec); if ( ! video_out_stream ) { - Fatal("Unable to create video out stream"); - } else { - Debug(2, "Success creating video out stream"); + Error("Unable to create video out stream"); + return false; } #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) ret = avcodec_parameters_from_context(video_out_stream->codecpar, video_out_ctx); @@ -350,11 +346,9 @@ Debug(2,"Using mjpeg"); return false; } zm_dump_codecpar(video_out_stream->codecpar); - zm_dump_codec(video_out_ctx); #else avcodec_copy_context(video_out_stream->codec, video_out_ctx); Debug(2, "%dx%d", video_out_stream->codec->width, video_out_stream->codec->height ); - zm_dump_codec(video_out_ctx); zm_dump_codec(video_out_stream->codec); #endif @@ -386,9 +380,7 @@ Debug(2,"Using mjpeg"); } if ( audio_in_stream ) { - Debug(3, "Have audio stream"); audio_in_stream_index = audio_in_stream->index; - Debug(3, "Have audio stream"); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) audio_in_ctx = avcodec_alloc_context3(NULL); ret = avcodec_parameters_to_context(audio_in_ctx, @@ -500,6 +492,8 @@ Debug(2,"Using mjpeg"); return false; } if ( opts ) av_dict_free(&opts); + zm_dump_stream_format(oc, 0, 0, 1); + if (audio_out_stream) zm_dump_stream_format(oc, 1, 0, 1); return true; } // end bool VideoStore::open() @@ -727,7 +721,6 @@ bool VideoStore::setup_resampler() { Error("Could not find codec for AAC"); return false; } - Debug(2, "Have audio out codec"); // Now copy them to the out stream audio_out_stream = avformat_new_stream(oc, audio_out_codec); @@ -760,7 +753,7 @@ bool VideoStore::setup_resampler() { } } if ( found ) { - Debug(3, "Sample rate is good"); + Debug(4, "Sample rate is good"); } else { audio_out_ctx->sample_rate = audio_out_codec->supported_samplerates[0]; @@ -1114,15 +1107,21 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { opkt.size = ipkt->size; opkt.flags = ipkt->flags; if ( ! video_start_pts ) { - video_start_pts = zm_packet->timestamp->tv_sec*(uint64_t)1000000 + zm_packet->timestamp->tv_usec; + video_start_pts = ipkt->pts; opkt.dts = opkt.pts = 0; } else { - opkt.dts = opkt.pts = ( zm_packet->timestamp->tv_sec*(uint64_t)1000000 + zm_packet->timestamp->tv_usec ) - video_start_pts; + dumpPacket(ipkt); + opkt.dts = opkt.pts = ( ipkt->pts - video_start_pts ); + Debug(2, "out_stream_time_base(%d/%d) in_stream_time_base(%d/%d) video_start_pts(%d) pts(%d) /dts(%d) ", + video_out_stream->time_base.num, video_out_stream->time_base.den, + video_in_stream->time_base.num, video_in_stream->time_base.den, + video_start_pts, opkt.pts, opkt.dts ); + opkt.pts = av_rescale_q( opkt.pts, video_in_stream->time_base, video_out_stream->time_base); + opkt.dts = av_rescale_q( opkt.dts, video_in_stream->time_base, video_out_stream->time_base); } } opkt.duration = 0; - dumpPacket(&opkt); write_video_packet( opkt ); zm_av_packet_unref(&opkt); @@ -1145,11 +1144,10 @@ void VideoStore::write_video_packet( AVPacket &opkt ) { //video_next_dts += opkt.duration; //video_next_pts += opkt.duration; - av_packet_rescale_ts( &opkt, video_out_ctx->time_base, video_out_stream->time_base ); + //av_packet_rescale_ts( &opkt, video_out_ctx->time_base, video_out_stream->time_base ); + + dumpPacket(&opkt); - Debug(1, - "writing video packet pts(%" PRId64 ") dts(%" PRId64 ") duration(%" PRId64 ") packet_count(%u)", - opkt.pts, opkt.dts, opkt.duration, packets_written ); if ( (opkt.data == NULL) || (opkt.size < 1) ) { Warning("%s:%d: Mangled AVPacket: discarding frame", __FILE__, __LINE__); //dumpPacket(&opkt); From 212cd7e6c4808f162b1adc2417a2d12c6f92d647 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 15 Dec 2017 10:46:43 -0500 Subject: [PATCH 0090/2339] tidy ups --- src/zm_monitor.cpp | 8 ++------ src/zm_videostore.cpp | 6 ++---- src/zmc.cpp | 3 ++- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 6d52e4b9b..931dc58c7 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1414,13 +1414,9 @@ bool Monitor::Analyse() { if ( Event::PreAlarmCount() >= (alarm_frame_count-1) ) { Info( "%s: %03d - Gone into alarm state", name, analysis_image_count ); shared_data->state = state = ALARM; - if ( (function != MOCORD && state != ALERT) ) { -if ( event ) { -Error("Already ahve evnet!"); -} else { + if ( ! event ) { event = new Event( this, *timestamp, cause, noteSetMap ); shared_data->last_event_id = event->Id(); -} } } else if ( state != PREALARM ) { Info( "%s: %03d - Gone into prealarm state", name, analysis_image_count ); @@ -3260,7 +3256,7 @@ void Monitor::get_ref_image() { ( shared_data->last_write_time == 0 ) && ! zm_terminate ) { - Warning( "Waiting for capture daemon" ); + Warning( "Waiting for capture daemon lwi(%d) lwt(%d)", shared_data->last_write_index, shared_data->last_write_time ); usleep( 50000 ); } int last_write_index = shared_data->last_write_index ; diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index c7be5c221..9f20fbe99 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -348,7 +348,6 @@ Debug(2,"Using mjpeg"); zm_dump_codecpar(video_out_stream->codecpar); #else avcodec_copy_context(video_out_stream->codec, video_out_ctx); - Debug(2, "%dx%d", video_out_stream->codec->width, video_out_stream->codec->height ); zm_dump_codec(video_out_stream->codec); #endif @@ -563,10 +562,9 @@ VideoStore::~VideoStore() { break; } #endif - int keyframe = pkt.flags & AV_PKT_FLAG_KEY; - Debug(3, "dts:%I64d, pts:%I64d, keyframe:%d", pkt.dts, pkt.pts, keyframe ); + dumpPacket(&pkt); //pkt.dts = video_next_dts; - pkt.pts = pkt.dts; + //pkt.pts = pkt.dts; //pkt.duration = video_last_duration; write_video_packet(pkt); zm_av_packet_unref(&pkt); diff --git a/src/zmc.cpp b/src/zmc.cpp index c8274ef2e..588433f4e 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -254,7 +254,7 @@ int main(int argc, char *argv[]) { last_capture_times[i].tv_sec = last_capture_times[i].tv_usec = 0; capture_delays[i] = monitors[i]->GetCaptureDelay(); alarm_capture_delays[i] = monitors[i]->GetAlarmCaptureDelay(); - Debug(2, "capture delay(%u) alarm delay(%u)", capture_delays[i], alarm_capture_delays[i] ); + Debug(2, "capture delay(%u mSecs 1000/capture_fps) alarm delay(%u)", capture_delays[i], alarm_capture_delays[i] ); Monitor::Function function = monitors[0]->GetFunction(); if ( function == Monitor::MODECT || function == Monitor::MOCORD || function == Monitor::RECORD) { @@ -278,6 +278,7 @@ int main(int argc, char *argv[]) { gettimeofday(&now, NULL); for ( int j = 0; j < n_monitors; j++ ) { if ( last_capture_times[j].tv_sec ) { + // We pretty much know this is positive. DELTA_TIMEVAL(delta_time, now, last_capture_times[j], DT_PREC_3); // capture_delay is the amount of time we should sleep to achieve the desired framerate. if ( monitors[i]->GetState() == Monitor::ALARM ) From ebcd63f280e7b9d21259bec1e8570c65ad98cb71 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 15 Dec 2017 10:47:44 -0500 Subject: [PATCH 0091/2339] fixes to compile using avconv --- src/zm_ffmpeg.cpp | 4 ++++ src/zm_monitor.cpp | 1 - src/zm_videostore.cpp | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index ebe178ac4..65b6bc8d4 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -251,7 +251,11 @@ void zm_dump_codec ( const AVCodecContext *codec ) { codec->height, codec->time_base.num, codec->time_base.den, +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) (codec->pix_fmt == AV_PIX_FMT_NONE ? "none" : av_get_pix_fmt_name(codec->pix_fmt)) +#else + "unsupported on avconv" +#endif ); } diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 6d52e4b9b..1fa8b89dd 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1262,7 +1262,6 @@ bool Monitor::Analyse() { struct timeval *timestamp = snap->timestamp; Image *snap_image = snap->image; - Debug(2, "Analysing image (%d)", snap->image_index ); if ( snap->image_index == -1 ) { snap->unlock(); Debug(2, "skipping because audio"); diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index c7be5c221..d9c2f69bf 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -1031,7 +1031,9 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { zm_packet->out_frame->coded_picture_number = frame_count; zm_packet->out_frame->display_picture_number = frame_count; zm_packet->out_frame->sample_aspect_ratio = (AVRational){ 0, 1 }; +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) zm_packet->out_frame->pkt_duration = 0; +#endif if ( ! video_start_pts ) { uint64_t temp = zm_packet->timestamp->tv_sec*(uint64_t)1000000; From cae37e29b0c02f8116311c396d0c4ee4c4eb4755 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 15 Dec 2017 15:17:49 -0500 Subject: [PATCH 0092/2339] alter Events Primary Key to just the Id. This prevents a double key index on MonitorId --- db/zm_create.sql.in | 2 +- db/zm_update-1.31.17.sql | 5 +++++ version | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 db/zm_update-1.31.17.sql diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index ec035d227..993b65824 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -209,7 +209,7 @@ CREATE TABLE `Events` ( `StateId` int(10) unsigned NOT NULL, `Orientation` enum('0','90','180','270','hori','vert') NOT NULL default '0', `DiskSpace` bigint unsigned default NULL, - PRIMARY KEY (`Id`,`MonitorId`), + PRIMARY KEY (`Id`), KEY `MonitorId` (`MonitorId`), KEY `StartTime` (`StartTime`), KEY `Frames` (`Frames`), diff --git a/db/zm_update-1.31.17.sql b/db/zm_update-1.31.17.sql new file mode 100644 index 000000000..d0b55f334 --- /dev/null +++ b/db/zm_update-1.31.17.sql @@ -0,0 +1,5 @@ +alter table Events modify Id int(10) unsigned; +alter table Events DROP Primary key; +alter table Events Add Primary key(Id); +alter table Events modify Id int(10) unsigned auto_incremement; + diff --git a/version b/version index d1a8f5341..874058d96 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.31.16 +1.31.17 From 14eedf4927ccf36e6b227cf2636f239f8f3405ba Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 16 Dec 2017 17:07:53 -0500 Subject: [PATCH 0093/2339] rework state machine --- src/zm_monitor.cpp | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index e4b9bd755..09a548ca6 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1409,21 +1409,22 @@ bool Monitor::Analyse() { if ( score ) { Debug(9, "Score: (%d)", score ); - if ( (state == IDLE || state == TAPE || state == PREALARM ) ) { - if ( Event::PreAlarmCount() >= (alarm_frame_count-1) ) { - Info( "%s: %03d - Gone into alarm state", name, analysis_image_count ); - shared_data->state = state = ALARM; - if ( ! event ) { - event = new Event( this, *timestamp, cause, noteSetMap ); - shared_data->last_event_id = event->Id(); + if ( (state == IDLE || state == TAPE || state == PREALARM ) ) { + if ( Event::PreAlarmCount() >= (alarm_frame_count-1) ) { + Info( "%s: %03d - Gone into alarm state", name, analysis_image_count ); + shared_data->state = state = ALARM; + if ( ! event ) { + event = new Event( this, *timestamp, cause, noteSetMap ); + shared_data->last_event_id = event->Id(); + } + } else if ( state != PREALARM ) { + Info( "%s: %03d - Gone into prealarm state", name, analysis_image_count ); + shared_data->state = state = PREALARM; } - } else if ( state != PREALARM ) { - Info( "%s: %03d - Gone into prealarm state", name, analysis_image_count ); - shared_data->state = state = PREALARM; + } else if ( state == ALERT ) { + Info( "%s: %03d - Gone back into alarm state", name, analysis_image_count ); + shared_data->state = state = ALARM; } - } else if ( state == ALERT ) { - Info( "%s: %03d - Gone back into alarm state", name, analysis_image_count ); - shared_data->state = state = ALARM; } last_alarm_count = analysis_image_count; } else { // no score? @@ -1434,7 +1435,7 @@ bool Monitor::Analyse() { if ( analysis_image_count-last_alarm_count > post_event_count ) { Info( "%s: %03d - Left alarm state (%d) - %d(%d) images", name, analysis_image_count, event->Id(), event->Frames(), event->AlarmFrames() ); //if ( function != MOCORD || event_close_mode == CLOSE_ALARM || event->Cause() == SIGNAL_CAUSE ) - if ( function != MOCORD || event_close_mode == CLOSE_ALARM ) { + if ( (function != RECORD && function != MOCORD ) || event_close_mode == CLOSE_ALARM ) { shared_data->state = state = IDLE; Info( "%s: %03d - Closing event %d, alarm end%s", name, analysis_image_count, event->Id(), (function==MOCORD)?", section truncated":"" ); closeEvent(); From 7e9d740343c4cef66085c1295ca89a61a634d8e7 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 16 Dec 2017 17:08:21 -0500 Subject: [PATCH 0094/2339] add npeg1 & 2 support and fix the first keyframe being ignored thing --- src/zm_videostore.cpp | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 5f1fe0425..f216418ec 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -100,6 +100,7 @@ bool VideoStore::open() { oc->metadata = pmetadata; out_format = oc->oformat; + if ( video_in_stream ) { video_in_stream_index = video_in_stream->index; #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) @@ -272,15 +273,23 @@ Debug(2,"Using mjpeg"); video_out_ctx->qmin = 10; video_out_ctx->qmax = 51; video_out_ctx->qcompress = 0.6; - video_out_ctx->bit_rate = 4000000; - video_out_ctx->max_b_frames = 1; + //video_out_ctx->bit_rate = 4000000; if ( video_out_ctx->codec_id == AV_CODEC_ID_H264 ) { + video_out_ctx->max_b_frames = 1; if ( video_out_ctx->priv_data ) { av_opt_set(video_out_ctx->priv_data, "preset", "ultrafast", 0); } else { Debug(2, "Not setting priv_data"); } - } + } else if (video_out_ctx->codec_id == AV_CODEC_ID_MPEG2VIDEO) { + /* just for testing, we also add B frames */ + video_out_ctx->max_b_frames = 2; + } else if (video_out_ctx->codec_id == AV_CODEC_ID_MPEG1VIDEO) { + /* Needed to avoid using macroblocks in which some coeffs overflow. + * This does not happen with normal video, it just happens here as + * the motion of the chroma plane does not match the luma plane. */ + video_out_ctx->mb_decision = 2; + } AVDictionary *opts = 0; std::string Options = monitor->GetEncoderOptions(); @@ -345,16 +354,8 @@ Debug(2,"Using mjpeg"); Error("Could not initialize stream parameteres"); return false; } - zm_dump_codecpar(video_out_stream->codecpar); #else avcodec_copy_context(video_out_stream->codec, video_out_ctx); - zm_dump_codec(video_out_stream->codec); -#endif - -#if 0 - // No point apparently. They may change when opening the file. - video_out_stream->time_base.num = video_out_ctx->time_base.num; - video_out_stream->time_base.den = video_out_ctx->time_base.den; #endif if ( video_in_stream && ( video_in_ctx->codec_id == AV_CODEC_ID_H264 ) ) { @@ -491,6 +492,7 @@ Debug(2,"Using mjpeg"); return false; } if ( opts ) av_dict_free(&opts); + zm_dump_stream_format(oc, 0, 0, 1); if (audio_out_stream) zm_dump_stream_format(oc, 1, 0, 1); return true; @@ -562,10 +564,6 @@ VideoStore::~VideoStore() { break; } #endif - dumpPacket(&pkt); - //pkt.dts = video_next_dts; - //pkt.pts = pkt.dts; - //pkt.duration = video_last_duration; write_video_packet(pkt); zm_av_packet_unref(&pkt); } // while have buffered frames @@ -914,7 +912,7 @@ void VideoStore::dumpPacket(AVPacket *pkt) { snprintf(b, sizeof(b), " pts: %" PRId64 ", dts: %" PRId64 - ", data: %p, size: %d, stream_index: %d, dflags: %04x, pos: %" PRId64 + ", data: %p, size: %d, stream_index: %d, flags: %04x, keyframe(%d) pos: %" PRId64 ", duration: %" #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) PRId64 @@ -928,6 +926,7 @@ void VideoStore::dumpPacket(AVPacket *pkt) { pkt->size, pkt->stream_index, pkt->flags, + pkt->flags & AV_PKT_FLAG_KEY, pkt->pos, pkt->duration); Debug(1, "%s:%d:DEBUG: %s", __FILE__, __LINE__, b); @@ -1041,6 +1040,7 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { Debug(2, "No video_lsat_pts, set to (%" PRId64 ") secs(%d) usecs(%d)", video_start_pts, zm_packet->timestamp->tv_sec, zm_packet->timestamp->tv_usec ); zm_packet->out_frame->pts = 0; + zm_packet->out_frame->coded_picture_number = 0; } else { uint64_t seconds = zm_packet->timestamp->tv_sec*(uint64_t)1000000; zm_packet->out_frame->pts = ( seconds + zm_packet->timestamp->tv_usec ) - video_start_pts; @@ -1083,6 +1083,8 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { //Debug(2, "Got packet using receive_packet, dts:%" PRId64 ", pts:%" PRId64 ", keyframe:%d", opkt.dts, opkt.pts, opkt.flags & AV_PKT_FLAG_KEY ); #else av_init_packet(&opkt); + opkt.data = NULL; + opkt.size = 0; int data_present; if ( (ret = avcodec_encode_video2( video_out_ctx, &opkt, zm_packet->out_frame, &data_present)) < 0) { @@ -1118,10 +1120,11 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { video_start_pts, opkt.pts, opkt.dts ); opkt.pts = av_rescale_q( opkt.pts, video_in_stream->time_base, video_out_stream->time_base); opkt.dts = av_rescale_q( opkt.dts, video_in_stream->time_base, video_out_stream->time_base); + opkt.duration = av_rescale_q( opkt.duration, video_in_stream->time_base, video_out_stream->time_base); } } - opkt.duration = 0; + //opkt.duration = 0; write_video_packet( opkt ); zm_av_packet_unref(&opkt); From 887235c7467514b3eaf9ad933beaa10ecfe7a35e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 19 Dec 2017 09:59:04 -0500 Subject: [PATCH 0095/2339] move dumpPacket to zm_ffmpeg --- src/zm_ffmpeg.cpp | 24 ++++++++++++++++++++++ src/zm_ffmpeg.h | 1 + src/zm_packet.cpp | 1 + src/zm_videostore.cpp | 46 ++++++++++--------------------------------- src/zm_videostore.h | 1 - 5 files changed, 36 insertions(+), 37 deletions(-) diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index 65b6bc8d4..7e2e99733 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -434,3 +434,27 @@ int zm_receive_frame( AVCodecContext *context, AVFrame *frame, AVPacket &packet #endif return 1; } // end int zm_receive_frame( AVCodecContext *context, AVFrame *frame, AVPacket &packet ) +void dumpPacket(AVPacket *pkt) { + char b[10240]; + + snprintf(b, sizeof(b), + " pts: %" PRId64 ", dts: %" PRId64 + ", data: %p, size: %d, stream_index: %d, flags: %04x, keyframe(%d) pos: %" PRId64 + ", duration: %" +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + PRId64 +#else + "d" +#endif + "\n", + pkt->pts, + pkt->dts, + pkt->data, + pkt->size, + pkt->stream_index, + pkt->flags, + pkt->flags & AV_PKT_FLAG_KEY, + pkt->pos, + pkt->duration); + Debug(1, "%s:%d:DEBUG: %s", __FILE__, __LINE__, b); +} diff --git a/src/zm_ffmpeg.h b/src/zm_ffmpeg.h index ff896e0ae..6d5eb8d9e 100644 --- a/src/zm_ffmpeg.h +++ b/src/zm_ffmpeg.h @@ -327,4 +327,5 @@ int check_sample_fmt(AVCodec *codec, enum AVSampleFormat sample_fmt); bool is_video_stream( AVStream * stream ); bool is_audio_stream( AVStream * stream ); int zm_receive_frame( AVCodecContext *context, AVFrame *frame, AVPacket &packet ); +void dumpPacket(AVPacket *); #endif // ZM_FFMPEG_H diff --git a/src/zm_packet.cpp b/src/zm_packet.cpp index 5c09e5fe9..78a645083 100644 --- a/src/zm_packet.cpp +++ b/src/zm_packet.cpp @@ -195,6 +195,7 @@ AVPacket *ZMPacket::set_packet( AVPacket *p ) { if ( zm_av_packet_ref( &packet, p ) < 0 ) { Error("error refing packet"); } + dumpPacket(&packet); gettimeofday( timestamp, NULL ); keyframe = p->flags & AV_PKT_FLAG_KEY; return &packet; diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index f216418ec..0aa87c00c 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -907,30 +907,6 @@ bool VideoStore::setup_resampler() { #endif } // end bool VideoStore::setup_resampler() -void VideoStore::dumpPacket(AVPacket *pkt) { - char b[10240]; - - snprintf(b, sizeof(b), - " pts: %" PRId64 ", dts: %" PRId64 - ", data: %p, size: %d, stream_index: %d, flags: %04x, keyframe(%d) pos: %" PRId64 - ", duration: %" -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - PRId64 -#else - "d" -#endif - "\n", - pkt->pts, - pkt->dts, - pkt->data, - pkt->size, - pkt->stream_index, - pkt->flags, - pkt->flags & AV_PKT_FLAG_KEY, - pkt->pos, - pkt->duration); - Debug(1, "%s:%d:DEBUG: %s", __FILE__, __LINE__, b); -} int VideoStore::writePacket( ZMPacket *ipkt ) { if ( ipkt->packet.stream_index == video_in_stream_index ) { @@ -1110,16 +1086,19 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { opkt.flags = ipkt->flags; if ( ! video_start_pts ) { video_start_pts = ipkt->pts; + Debug(2, "No video_lsat_pts, set to (%" PRId64 ")", video_start_pts ); opkt.dts = opkt.pts = 0; } else { - dumpPacket(ipkt); - opkt.dts = opkt.pts = ( ipkt->pts - video_start_pts ); - Debug(2, "out_stream_time_base(%d/%d) in_stream_time_base(%d/%d) video_start_pts(%d) pts(%d) /dts(%d) ", + dumpPacket(ipkt); + opkt.dts = opkt.pts = av_rescale_q( ipkt->pts - video_start_pts, video_in_stream->time_base, video_out_stream->time_base ); + Debug(2, "out_stream_time_base(%d/%d) in_stream_time_base(%d/%d) video_start_pts(%" PRId64 ")", video_out_stream->time_base.num, video_out_stream->time_base.den, video_in_stream->time_base.num, video_in_stream->time_base.den, - video_start_pts, opkt.pts, opkt.dts ); - opkt.pts = av_rescale_q( opkt.pts, video_in_stream->time_base, video_out_stream->time_base); - opkt.dts = av_rescale_q( opkt.dts, video_in_stream->time_base, video_out_stream->time_base); + video_start_pts + ); + + dumpPacket(&opkt); + opkt.duration = av_rescale_q( opkt.duration, video_in_stream->time_base, video_out_stream->time_base); } } @@ -1143,10 +1122,6 @@ void VideoStore::write_video_packet( AVPacket &opkt ) { } opkt.stream_index = video_out_stream->index; - - //video_next_dts += opkt.duration; - //video_next_pts += opkt.duration; - //av_packet_rescale_ts( &opkt, video_out_ctx->time_base, video_out_stream->time_base ); dumpPacket(&opkt); @@ -1381,8 +1356,7 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { //opkt.duration = out_frame ? out_frame->nb_samples : ipkt->duration; // opkt.duration = av_rescale_q(ipkt->duration, audio_in_stream->time_base, // audio_out_stream->time_base); - Debug(2, "opkt.pts (%" PRId64 "), opkt.dts(%" PRId64 ") opkt.duration = (%" PRId64 ")", - opkt.pts, opkt.dts, opkt.duration); + dumpPacket(&opkt); // pkt.pos: byte position in stream, -1 if unknown opkt.pos = -1; diff --git a/src/zm_videostore.h b/src/zm_videostore.h index 902d01a38..d2b14ae2e 100644 --- a/src/zm_videostore.h +++ b/src/zm_videostore.h @@ -89,7 +89,6 @@ public: int writeVideoFramePacket( ZMPacket *pkt ); int writeAudioFramePacket( ZMPacket *pkt ); int writePacket( ZMPacket *pkt ); - void dumpPacket( AVPacket *pkt ); int write_packets( zm_packetqueue &queue ); }; From 8a85694b1cd16b03f8598b9859e29b5ecc86e450 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 10 Jan 2018 14:19:47 -0500 Subject: [PATCH 0096/2339] spacing --- src/zm_videostore.cpp | 48 ++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 003058cb3..6e272ec7b 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -521,7 +521,7 @@ void VideoStore::write_audio_packet( AVPacket &pkt ) { VideoStore::~VideoStore() { if ( oc->pb ) { - if ( video_out_ctx->codec_id != video_in_ctx->codec_id || audio_out_codec ) { + if ( ( video_out_ctx->codec_id != video_in_ctx->codec_id ) || audio_out_codec ) { Debug(2,"Different codecs between in and out"); // The codec queues data. We need to send a flush command and out // whatever we get. Failures are not fatal. @@ -553,26 +553,25 @@ VideoStore::~VideoStore() { break; } #else - while (1) { - // WIthout these we seg fault I don't know why. - pkt.data = NULL; - pkt.size = 0; - av_init_packet(&pkt); - int got_packet = 0; - ret = avcodec_encode_video2(video_out_ctx, &pkt, NULL, &got_packet); - if ( ret < 0 ) { - Error("ERror encoding video while flushing (%d) (%s)", ret, av_err2str(ret)); - break; - } - if (!got_packet) { - break; - } + while (1) { + // WIthout these we seg fault I don't know why. + pkt.data = NULL; + pkt.size = 0; + av_init_packet(&pkt); + int got_packet = 0; + ret = avcodec_encode_video2(video_out_ctx, &pkt, NULL, &got_packet); + if ( ret < 0 ) { + Error("ERror encoding video while flushing (%d) (%s)", ret, av_err2str(ret)); + break; + } + if (!got_packet) { + break; + } #endif - write_video_packet(pkt); - zm_av_packet_unref(&pkt); - } // while have buffered frames - } // end if have delay capability - } // end if have buffered video + write_video_packet(pkt); + zm_av_packet_unref(&pkt); + } // while have buffered frames + } // end if have delay capability if ( audio_out_codec ) { // The codec queues data. We need to send a flush command and out @@ -588,9 +587,11 @@ VideoStore::~VideoStore() { avcodec_send_frame(audio_out_ctx, NULL); while (1) { if ( (ret = avcodec_receive_packet(audio_out_ctx, &pkt) ) < 0 ) { - if (AVERROR_EOF != ret) { + if ( AVERROR_EOF != ret ) { Error("ERror encoding audio while flushing (%d) (%s)", ret, av_err2str(ret)); } + break; + } #else while (1) { pkt.data = NULL; @@ -622,7 +623,7 @@ VideoStore::~VideoStore() { Debug(3, "Sucess Writing trailer"); } - // WHen will be not using a file ? + // WHen will be not using a file ? if ( !(out_format->flags & AVFMT_NOFILE) ) { /* Close the out file. */ Debug(2, "Closing"); @@ -640,7 +641,8 @@ VideoStore::~VideoStore() { // allocation/de-allocation constantly, or whether we can just re-use it. // Just do a file open/close/writeheader/etc. // What if we were only doing audio recording? - if (video_out_stream) { + + if ( video_out_stream ) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) // We allocate and copy in newer ffmpeg, so need to free it avcodec_free_context(&video_in_ctx); From 6883159ad03121cae10e98ee432c58304ad116dc Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 24 Jan 2018 12:15:35 -0500 Subject: [PATCH 0097/2339] Use a LEFT JOIN on Storage WHEN Running Filters --- scripts/ZoneMinder/lib/ZoneMinder/Filter.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm index ed5779b2b..cd8b76a62 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm @@ -140,7 +140,7 @@ sub Sql { M.DefaultScale FROM Events as E INNER JOIN Monitors as M on M.Id = E.MonitorId - INNER JOIN Storage as S on S.Id = E.StorageId + LEFT JOIN Storage as S on S.Id = E.StorageId '; $self->{Sql} = ''; From 6a42dab4e8940333fcdff19c97fe3c492bdee8f5 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 24 Jan 2018 12:18:39 -0500 Subject: [PATCH 0098/2339] Fix --- src/zm_monitor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 617fc112e..0ded6f78a 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1229,7 +1229,7 @@ void Monitor::UpdateAnalysisFPS() { analysis_fps = double(fps_report_interval)/(now.tv_sec - last_analysis_fps_time); Info( "%s: %d - Analysing at %.2f fps", name, image_count, analysis_fps ); static char sql[ZM_SQL_SML_BUFSIZ]; - snprintf( sql, sizeof(sql), "INSERT INTO Monitor_Status (Id,AnalysisFPS) VALUES (%d, %.2lf) ON DUPLICATE KEY UPDATE AnalysisFPS = %.2lf", id, fps, fps ); + snprintf( sql, sizeof(sql), "INSERT INTO Monitor_Status (Id,AnalysisFPS) VALUES (%d, %.2lf) ON DUPLICATE KEY UPDATE AnalysisFPS = %.2lf", id, analysis_fps, analysis_fps ); if ( mysql_query( &dbconn, sql ) ) { Error( "Can't run query: %s", mysql_error( &dbconn ) ); } @@ -2941,7 +2941,7 @@ int Monitor::Capture() { Info( "%s: %d - Capturing at %.2lf fps", name, image_count, capture_fps ); last_fps_time = now; static char sql[ZM_SQL_SML_BUFSIZ]; - snprintf( sql, sizeof(sql), "INSERT INTO Monitor_Status (Id,CaptureFPS) VALUES (%d, %.2lf) ON DUPLICATE KEY UPDATE CaptureFPS = %.2lf", id, fps, fps ); + snprintf( sql, sizeof(sql), "INSERT INTO Monitor_Status (Id,CaptureFPS) VALUES (%d, %.2lf) ON DUPLICATE KEY UPDATE CaptureFPS = %.2lf", id, capture_fps, capture_fps ); if ( mysql_query( &dbconn, sql ) ) { Error( "Can't run query: %s", mysql_error( &dbconn ) ); } From 5b238f713d885815954355c5e9b3773cb99bc453 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 29 Jan 2018 11:52:17 -0500 Subject: [PATCH 0099/2339] fix comma --- src/zm_event.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 59f4c8442..25fa3faf0 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -47,7 +47,7 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string &p_cause, - const StringSetMap &p_noteSetMap, + const StringSetMap &p_noteSetMap ) : monitor( p_monitor ), start_time( p_start_time ), From 4a0b3f6c40ae2ec7bf0bab358e89b3ea316808e3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 13 Feb 2018 05:26:08 -0500 Subject: [PATCH 0100/2339] Include id in the user object --- src/zm_user.cpp | 19 +++++++++++-------- src/zm_user.h | 2 ++ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/zm_user.cpp b/src/zm_user.cpp index 3bf22fadd..283e37932 100644 --- a/src/zm_user.cpp +++ b/src/zm_user.cpp @@ -30,6 +30,7 @@ #include "zm_utils.h" User::User() { + id = 0; username[0] = password[0] = 0; enabled = false; stream = events = control = monitors = system = PERM_NONE; @@ -37,6 +38,7 @@ User::User() { User::User( MYSQL_ROW &dbrow ) { int index = 0; + id = atoi( dbrow[index++] ); strncpy( username, dbrow[index++], sizeof(username)-1 ); strncpy( password, dbrow[index++], sizeof(password)-1 ); enabled = (bool)atoi( dbrow[index++] ); @@ -59,6 +61,7 @@ User::~User() { } void User::Copy( const User &u ) { + id=u.id; strncpy( username, u.username, sizeof(username)-1 ); strncpy( password, u.password, sizeof(password)-1 ); enabled = u.enabled; @@ -94,9 +97,9 @@ User *zmLoadUser( const char *username, const char *password ) { if ( password ) { char safer_password[129]; // current db password size is 64 mysql_real_escape_string(&dbconn, safer_password, password, strlen( password ) ); - snprintf( sql, sizeof(sql), "select Username, Password, Enabled, Stream+0, Events+0, Control+0, Monitors+0, System+0, MonitorIds from Users where Username = '%s' and Password = password('%s') and Enabled = 1", safer_username, safer_password ); + snprintf( sql, sizeof(sql), "select Id, Username, Password, Enabled, Stream+0, Events+0, Control+0, Monitors+0, System+0, MonitorIds from Users where Username = '%s' and Password = password('%s') and Enabled = 1", safer_username, safer_password ); } else { - snprintf( sql, sizeof(sql), "select Username, Password, Enabled, Stream+0, Events+0, Control+0, Monitors+0, System+0, MonitorIds from Users where Username = '%s' and Enabled = 1", safer_username ); + snprintf( sql, sizeof(sql), "select Id, Username, Password, Enabled, Stream+0, Events+0, Control+0, Monitors+0, System+0, MonitorIds from Users where Username = '%s' and Enabled = 1", safer_username ); } if ( mysql_query( &dbconn, sql ) ) { @@ -124,7 +127,7 @@ User *zmLoadUser( const char *username, const char *password ) { mysql_free_result( result ); - return( user ); + return user; } // Function to validate an authentication string @@ -150,7 +153,7 @@ User *zmLoadAuthUser( const char *auth, bool use_remote_addr ) { Debug( 1, "Attempting to authenticate user from auth string '%s', remote addr(%s)", auth, remote_addr ); char sql[ZM_SQL_SML_BUFSIZ] = ""; - snprintf( sql, sizeof(sql), "SELECT Username, Password, Enabled, Stream+0, Events+0, Control+0, Monitors+0, System+0, MonitorIds FROM Users WHERE Enabled = 1" ); + snprintf( sql, sizeof(sql), "SELECT Id, Username, Password, Enabled, Stream+0, Events+0, Control+0, Monitors+0, System+0, MonitorIds FROM Users WHERE Enabled = 1" ); if ( mysql_query( &dbconn, sql ) ) { Error( "Can't run query: %s", mysql_error( &dbconn ) ); @@ -182,8 +185,8 @@ User *zmLoadAuthUser( const char *auth, bool use_remote_addr ) { } while( MYSQL_ROW dbrow = mysql_fetch_row( result ) ) { - const char *user = dbrow[0]; - const char *pass = dbrow[1]; + const char *user = dbrow[1]; + const char *pass = dbrow[2]; char auth_key[512] = ""; char auth_md5[32+1] = ""; @@ -222,7 +225,7 @@ User *zmLoadAuthUser( const char *auth, bool use_remote_addr ) { User *user = new User( dbrow ); Debug(1, "Authenticated user '%s'", user->getUsername() ); mysql_free_result( result ); - return( user ); + return user; } } // end foreach hours } // end foreach user @@ -232,5 +235,5 @@ User *zmLoadAuthUser( const char *auth, bool use_remote_addr ) { Error( "You need to build with gnutls or openssl installed to use hash based authentication" ); #endif // HAVE_DECL_MD5 Debug(1, "No user found for auth_key %s", auth ); - return( 0 ); + return 0; } diff --git a/src/zm_user.h b/src/zm_user.h index 725acbfa2..2c932dd74 100644 --- a/src/zm_user.h +++ b/src/zm_user.h @@ -42,6 +42,7 @@ public: typedef enum { PERM_NONE=1, PERM_VIEW, PERM_EDIT } Permission; protected: + int id; char username[32+1]; char password[64+1]; bool enabled; @@ -62,6 +63,7 @@ public: Copy(u); return *this; } + const int Id() const { return id; } const char *getUsername() const { return( username ); } const char *getPassword() const { return( password ); } bool isEnabled() const { return( enabled ); } From 657fda818bc90bd24299c33daea85960bea4051d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 13 Feb 2018 05:26:30 -0500 Subject: [PATCH 0101/2339] code docs --- src/zm_monitor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index fb6f5b76d..ea1e03f9d 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -823,6 +823,7 @@ double Monitor::GetFPS() const { return curr_fps; } +/* I think this returns the # of micro seconds that we should sleep in order to maintain the desired analysis rate */ useconds_t Monitor::GetAnalysisRate() { capture_fps = GetFPS(); if ( !analysis_fps_limit ) { From e7ec1086ea8b8ec97fd6aeea0a9edc03231d8a7c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 15 Feb 2018 14:07:05 -0500 Subject: [PATCH 0102/2339] rework zmc delay code to be more readable and use few gettimeofday calls and be more efficient --- src/zmc.cpp | 88 ++++++++++++++++++++++------------------------------- 1 file changed, 36 insertions(+), 52 deletions(-) diff --git a/src/zmc.cpp b/src/zmc.cpp index bb67a7bdd..8feb5ddc2 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -260,7 +260,6 @@ int main(int argc, char *argv[]) { AnalysisThread **analysis_threads = new AnalysisThread *[n_monitors]; long *capture_delays = new long[n_monitors]; long *alarm_capture_delays = new long[n_monitors]; - long *next_delays = new long[n_monitors]; struct timeval * last_capture_times = new struct timeval[n_monitors]; for ( int i = 0; i < n_monitors; i++ ) { last_capture_times[i].tv_sec = last_capture_times[i].tv_usec = 0; @@ -280,64 +279,50 @@ int main(int argc, char *argv[]) { struct timeval now; struct DeltaTimeval delta_time; + while ( !zm_terminate ) { - //Debug(2,"blocking"); sigprocmask(SIG_BLOCK, &block_set, 0); for ( int i = 0; i < n_monitors; i++ ) { - long min_delay = MAXINT; - - gettimeofday(&now, NULL); - for ( int j = 0; j < n_monitors; j++ ) { - if ( last_capture_times[j].tv_sec ) { - // We pretty much know this is positive. - DELTA_TIMEVAL(delta_time, now, last_capture_times[j], DT_PREC_3); - // capture_delay is the amount of time we should sleep to achieve the desired framerate. - if ( monitors[i]->GetState() == Monitor::ALARM ) - next_delays[j] = alarm_capture_delays[j] - delta_time.delta; - else - next_delays[j] = capture_delays[j] - delta_time.delta; - if ( next_delays[j] < 0 ) - next_delays[j] = 0; - } - if ( next_delays[j] <= min_delay ) { - min_delay = next_delays[j]; - } - } // end foreach monitor monitors[i]->CheckAction(); - if ( next_delays[i] <= min_delay || next_delays[i] <= 0 ) { - if ( monitors[i]->PreCapture() < 0 ) { - Error("Failed to pre-capture monitor %d %d (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors); - result = -1; - break; - } - if ( monitors[i]->Capture() < 0 ) { - Error("Failed to capture image from monitor %d %s (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors); - result = -1; - break; - } - if ( monitors[i]->PostCapture() < 0 ) { - Error("Failed to post-capture monitor %d %s (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors); - result = -1; - break; - } + if ( monitors[i]->PreCapture() < 0 ) { + Error("Failed to pre-capture monitor %d %d (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors); + result = -1; + break; + } + if ( monitors[i]->Capture() < 0 ) { + Error("Failed to capture image from monitor %d %s (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors); + result = -1; + break; + } + if ( monitors[i]->PostCapture() < 0 ) { + Error("Failed to post-capture monitor %d %s (%d/%d)", monitors[i]->Id(), monitors[i]->Name(), i+1, n_monitors); + result = -1; + break; + } - if ( next_delays[i] > 0 ) { - gettimeofday(&now, NULL); - DELTA_TIMEVAL(delta_time, now, last_capture_times[i], DT_PREC_3); - long sleep_time = next_delays[i] - delta_time.delta; - if ( sleep_time > 0 ) { - Debug(2,"usleeping (%d)", sleep_time*(DT_MAXGRAN/DT_PREC_3) ); - usleep(sleep_time*(DT_MAXGRAN/DT_PREC_3)); - } - last_capture_times[i] = now; - } else { - gettimeofday(&(last_capture_times[i]), NULL); - } - } // end if next_delay <= min_delay || next_delays[i] <= 0 ) + gettimeofday(&now, NULL); + // capture_delay is the amount of time we should sleep to achieve the desired framerate. + if ( last_capture_times[i].tv_sec ) { + long sleep_time; + DELTA_TIMEVAL(delta_time, now, last_capture_times[i], DT_PREC_3); + long delay = monitors[i]->GetState() == Monitor::ALARM ? alarm_capture_delays[i] : capture_delays[i]; - } // end foreach n_monitors + sleep_time = delay - delta_time.delta; + Debug(3, "Sleep time is %d from now:%d.%d last:%d.%d delay: %d", sleep_time, now.tv_sec, now.tv_usec, last_capture_times[i].tv_sec, last_capture_times[i].tv_usec, delay ); + + if ( sleep_time < 0 ) + sleep_time = 0; + + if ( sleep_time > 0 ) { + Debug(2,"usleeping (%d)", sleep_time*(DT_MAXGRAN/DT_PREC_3) ); + usleep(sleep_time*(DT_MAXGRAN/DT_PREC_3)); + } + } // end if has a last_capture time + last_capture_times[i] = now; + + } // end foreach n_monitors //Debug(2,"unblocking"); sigprocmask(SIG_UNBLOCK, &block_set, 0); if ( zm_reload ) { @@ -356,7 +341,6 @@ int main(int argc, char *argv[]) { delete [] alarm_capture_delays; delete [] capture_delays; - delete [] next_delays; delete [] last_capture_times; // Killoff the analysis threads. Don't need them spinning while we try to reconnect From 399b5159a4778045661e956d994497744bfbb454 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 15 Feb 2018 14:07:40 -0500 Subject: [PATCH 0103/2339] spacing and comment out some debug. Also maybe fix build when v4l1 is not present --- src/zm_local_camera.cpp | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/src/zm_local_camera.cpp b/src/zm_local_camera.cpp index a5e9d9a43..c8a653b14 100644 --- a/src/zm_local_camera.cpp +++ b/src/zm_local_camera.cpp @@ -1915,8 +1915,7 @@ mVideoStreamId = 0; } int LocalCamera::PreCapture() { - Debug( 4, "Pre-capturing" ); - return( 0 ); + return 0; } int LocalCamera::Capture( ZMPacket &zm_packet ) { @@ -1947,8 +1946,8 @@ int LocalCamera::Capture( ZMPacket &zm_packet ) { vid_buf.memory = v4l2_data.reqbufs.memory; while ( captures_per_frame ) { - Debug( 3, "Capturing %d frames", captures_per_frame ); - if ( vidioctl( vid_fd, VIDIOC_DQBUF, &vid_buf ) < 0 ) { + //Debug( 3, "Capturing %d frames", captures_per_frame ); + if ( vidioctl(vid_fd, VIDIOC_DQBUF, &vid_buf) < 0 ) { if ( errno == EIO ) { Warning( "Capture failure, possible signal loss?: %s", strerror(errno) ); } else { @@ -1976,7 +1975,10 @@ int LocalCamera::Capture( ZMPacket &zm_packet ) { if ( (v4l2_data.fmt.fmt.pix.width * v4l2_data.fmt.fmt.pix.height) != (width * height) ) { Fatal("Captured image dimensions differ: V4L2: %dx%d monitor: %dx%d",v4l2_data.fmt.fmt.pix.width,v4l2_data.fmt.fmt.pix.height,width,height); } - } else // end if v4l2 + } // end if v4l2 +#if ZM_HAS_V4L1 + else +#endif // ZM_HAS_V4L1 #endif // ZM_HAS_V4L2 #if ZM_HAS_V4L1 if ( v4l_version == 1 ) { @@ -2002,6 +2004,7 @@ int LocalCamera::Capture( ZMPacket &zm_packet ) { buffer = v4l1_data.bufptr+v4l1_data.frames.offsets[capture_frame]; } #endif // ZM_HAS_V4L1 + } /* prime capture */ if ( conversion_type != 0 ) { @@ -2069,27 +2072,30 @@ int LocalCamera::PostCapture() { if ( channel_count > 1 ) { int next_channel = (channel_index+1)%channel_count; Debug( 3, "Switching video source to %d", channels[next_channel] ); - if ( vidioctl( vid_fd, VIDIOC_S_INPUT, &channels[next_channel] ) < 0 ) { + if ( vidioctl(vid_fd, VIDIOC_S_INPUT, &channels[next_channel] ) < 0) { Error( "Failed to set camera source %d: %s", channels[next_channel], strerror(errno) ); - return( -1 ); + return -1; } v4l2_std_id stdId = standards[next_channel]; - if ( vidioctl( vid_fd, VIDIOC_S_STD, &stdId ) < 0 ) { - Error( "Failed to set video format %d: %s", standards[next_channel], strerror(errno) ); - return( -1 ); + if ( vidioctl(vid_fd, VIDIOC_S_STD, &stdId) < 0 ) { + Error("Failed to set video format %d: %s", standards[next_channel], strerror(errno)); + return -1; } } if ( v4l2_data.bufptr ) { - Debug( 3, "Requeueing buffer %d", v4l2_data.bufptr->index ); - if ( vidioctl( vid_fd, VIDIOC_QBUF, v4l2_data.bufptr ) < 0 ) { - Error( "Unable to requeue buffer %d: %s", v4l2_data.bufptr->index, strerror(errno) ) - return( -1 ); + Debug(3, "Requeueing buffer %d", v4l2_data.bufptr->index); + if ( vidioctl(vid_fd, VIDIOC_QBUF, v4l2_data.bufptr) < 0 ) { + Error("Unable to requeue buffer %d: %s", v4l2_data.bufptr->index, strerror(errno)); + return -1; } } else { - Error( "Unable to requeue buffer due to not v4l2_data" ) + Error("Unable to requeue buffer due to not v4l2_data") } - } else + } +#if ZM_HAS_V4L1 + else +#endif // ZM_HAS_V4L1 #endif // ZM_HAS_V4L2 #if ZM_HAS_V4L1 if ( v4l_version == 1 ) { @@ -2122,7 +2128,7 @@ int LocalCamera::PostCapture() { } #endif // ZM_HAS_V4L1 } - return( 0 ); + return 0; } AVStream *LocalCamera::get_VideoStream() { if ( ! video_stream ) { From 9fd2b6be52810725836f18a9099f4992df99478d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 15 Feb 2018 14:07:55 -0500 Subject: [PATCH 0104/2339] fix fps reporting --- src/zm_monitor.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 7fb7599be..e8b0dca34 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -2942,8 +2942,9 @@ int Monitor::Capture() { double new_capture_fps = double(fps_report_interval)/(now-last_fps_time); //Info( "%d -> %d -> %d", fps_report_interval, now, last_fps_time ); //Info( "%d -> %d -> %lf -> %lf", now-last_fps_time, fps_report_interval/(now-last_fps_time), double(fps_report_interval)/(now-last_fps_time), fps ); - Info("%s: %d - Capturing at %.2lf fps", name, image_count, capture_fps); + Info("%s: %d - Capturing at %.2lf fps", name, image_count, new_capture_fps); if ( new_capture_fps != capture_fps ) { + capture_fps = new_capture_fps; last_fps_time = now; static char sql[ZM_SQL_SML_BUFSIZ]; snprintf(sql, sizeof(sql), "INSERT INTO Monitor_Status (MonitorId,CaptureFPS) VALUES (%d, %.2lf) ON DUPLICATE KEY UPDATE CaptureFPS = %.2lf", id, capture_fps, capture_fps); @@ -3264,10 +3265,10 @@ int Monitor::PrimeCapture() { return ret; } int Monitor::PreCapture() { - return( camera->PreCapture() ); + return camera->PreCapture(); } int Monitor::PostCapture() { - return( camera->PostCapture() ); + return camera->PostCapture(); } Monitor::Orientation Monitor::getOrientation() const { return orientation; } From 10a30452fb2875993d2237fc9bb2833fecb2dd7b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 15 Feb 2018 14:08:21 -0500 Subject: [PATCH 0105/2339] fix logic when clearing queue, we were deleting packets endlessly. --- src/zm_packetqueue.cpp | 56 +++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index ec40dd902..912d8cb1f 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -117,12 +117,16 @@ ZMPacket* zm_packetqueue::popPacket( ) { unsigned int zm_packetqueue::clearQueue( unsigned int frames_to_keep, int stream_id ) { Debug(3, "Clearing all but %d frames, queue has %d", frames_to_keep, pktQueue.size() ); - frames_to_keep += 1; if ( pktQueue.empty() ) { Debug(3, "Queue is empty"); return 0; } + frames_to_keep += 1; + if ( pktQueue.size() <= frames_to_keep ) { + return 0; + } + int packets_to_delete = pktQueue.size(); std::list::reverse_iterator it; ZMPacket *packet = NULL; @@ -137,6 +141,7 @@ unsigned int zm_packetqueue::clearQueue( unsigned int frames_to_keep, int stream // Want frames_to_keep video keyframes. Otherwise, we may not have enough if ( av_packet->stream_index == stream_id ) { frames_to_keep --; + packets_to_delete --; } } @@ -152,6 +157,7 @@ unsigned int zm_packetqueue::clearQueue( unsigned int frames_to_keep, int stream Debug(4, "Found keyframe at packet with stream index (%d) with keyframe (%d), frames_to_keep is (%d)", av_packet->stream_index, ( av_packet->flags & AV_PKT_FLAG_KEY ), frames_to_keep ); break; } + packets_to_delete--; } if ( frames_to_keep ) { Debug(3, "Hit end of queue, still need (%d) video frames", frames_to_keep ); @@ -159,31 +165,35 @@ unsigned int zm_packetqueue::clearQueue( unsigned int frames_to_keep, int stream if ( it != pktQueue.rend() ) { // We want to keep this packet, so advance to the next it ++; + packets_to_delete--; } - unsigned int delete_count = 0; - Debug(4, "Deleting packets from the front, count is (%d)", delete_count ); - while ( it != pktQueue.rend() ) { - Debug(4, "Deleting a packet from the front, count is (%d)", delete_count ); + int delete_count = 0; - packet = pktQueue.front(); - if ( *analysis_it == packet ) - analysis_it ++; - if ( packet->codec_type == AVMEDIA_TYPE_VIDEO ) { - video_packet_count -= 1; - if ( video_packet_count ) { - // There is another video packet, so it must be the next one - first_video_packet_index += 1; - first_video_packet_index %= max_video_packet_count; - } else { - first_video_packet_index = -1; + if ( packets_to_delete > 0 ) { + Debug(4, "Deleting packets from the front, count is (%d)", packets_to_delete ); + while ( --packets_to_delete ) { + Debug(4, "Deleting a packet from the front, count is (%d), queue size is %d", delete_count, pktQueue.size() ); + + packet = pktQueue.front(); + if ( *analysis_it == packet ) + analysis_it ++; + if ( packet->codec_type == AVMEDIA_TYPE_VIDEO ) { + video_packet_count -= 1; + if ( video_packet_count ) { + // There is another video packet, so it must be the next one + first_video_packet_index += 1; + first_video_packet_index %= max_video_packet_count; + } else { + first_video_packet_index = -1; + } } - } - pktQueue.pop_front(); - if ( packet->image_index == -1 ) - delete packet; + pktQueue.pop_front(); + if ( packet->image_index == -1 ) + delete packet; - delete_count += 1; - } // while our iterator is not the first packet + delete_count += 1; + } // while our iterator is not the first packet + } // end if have packet_delete_count #if 0 if ( pktQueue.size() ) { @@ -194,7 +204,7 @@ unsigned int zm_packetqueue::clearQueue( unsigned int frames_to_keep, int stream } #endif - Debug(3, "Deleted (%d) packets", delete_count ); + Debug(3, "Deleted packets, resulting size is %d", pktQueue.size() ); return delete_count; } // end unsigned int zm_packetqueue::clearQueue( unsigned int frames_to_keep, int stream_id ) From 84b7e852595eda5f08b919330deb18eb6ecb8fe8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 15 Feb 2018 15:54:13 -0500 Subject: [PATCH 0106/2339] Add a mutex around mysql operations --- src/zm_db.cpp | 3 +++ src/zm_db.h | 2 ++ src/zm_event.cpp | 28 +++++++++++++++++++++------- src/zm_logger.cpp | 2 ++ src/zm_monitor.cpp | 20 +++++++++++++++++--- src/zm_zone.cpp | 7 +++++-- 6 files changed, 50 insertions(+), 12 deletions(-) diff --git a/src/zm_db.cpp b/src/zm_db.cpp index f51c84dcb..fc5ee5fe0 100644 --- a/src/zm_db.cpp +++ b/src/zm_db.cpp @@ -25,6 +25,7 @@ // From what I read, we need one of these per thread MYSQL dbconn; +Mutex db_mutex; bool zmDbConnected = false; @@ -90,6 +91,7 @@ MYSQL_RES * zmDbFetch( const char * query ) { Error( "Not connected." ); return NULL; } + db_mutex.lock(); if ( mysql_query( &dbconn, query ) ) { Error( "Can't run query: %s", mysql_error( &dbconn ) ); @@ -101,6 +103,7 @@ MYSQL_RES * zmDbFetch( const char * query ) { Error( "Can't use query result: %s for query %s", mysql_error( &dbconn ), query ); return NULL; } + db_mutex.unlock(); return result; } // end MYSQL_RES * zmDbFetch( const char * query ); diff --git a/src/zm_db.h b/src/zm_db.h index 616bbec25..267995e70 100644 --- a/src/zm_db.h +++ b/src/zm_db.h @@ -21,6 +21,7 @@ #define ZM_DB_H #include +#include "zm_thread.h" class zmDbRow { private: @@ -38,6 +39,7 @@ class zmDbRow { }; extern MYSQL dbconn; +extern Mutex db_mutex; bool zmDbConnect(); void zmDbClose(); diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 09aa70a36..e275fa963 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -93,11 +93,14 @@ Event::Event( monitor->GetOptSaveJPEGs(), storage->SchemeString().c_str() ); + + db_mutex.lock(); if ( mysql_query( &dbconn, sql ) ) { Error( "Can't insert event: %s. sql was (%s)", mysql_error( &dbconn ), sql ); exit( mysql_errno( &dbconn ) ); } id = mysql_insert_id( &dbconn ); + db_mutex.unlock(); if ( untimedEvent ) { Warning( "Event %d has zero time, setting to current", id ); } @@ -224,10 +227,11 @@ Event::~Event() { snprintf( sql, sizeof(sql), "insert into Frames ( EventId, FrameId, TimeStamp, Delta ) values ( %d, %d, from_unixtime( %ld ), %s%ld.%02ld )", id, frames, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec ); + db_mutex.lock(); if ( mysql_query( &dbconn, sql ) ) { Error( "Can't insert frame: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); } + db_mutex.unlock(); } /* Close the video file */ @@ -237,10 +241,11 @@ Event::~Event() { } snprintf( sql, sizeof(sql), "UPDATE Events SET Name='%s%d', EndTime = from_unixtime( %ld ), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, DefaultVideo = '%s' where Id = %d", monitor->EventPrefix(), id, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, frames, alarm_frames, tot_score, (int)(alarm_frames?(tot_score/alarm_frames):0), max_score, video_name, id ); + db_mutex.lock(); if ( mysql_query( &dbconn, sql ) ) { Error( "Can't update event: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); } + db_mutex.unlock(); } // ~Event void Event::createNotes( std::string ¬es ) { @@ -365,7 +370,7 @@ void Event::updateNotes( const StringSetMap &newNoteSetMap ) { if ( mysql_stmt_bind_param( stmt, bind ) ) { Fatal( "Unable to bind sql '%s': %s", sql, mysql_stmt_error(stmt) ); } - } + } // end if ! stmt strncpy( notesStr, notes.c_str(), sizeof(notesStr) ); @@ -377,10 +382,12 @@ void Event::updateNotes( const StringSetMap &newNoteSetMap ) { mysql_real_escape_string( &dbconn, escapedNotes, notes.c_str(), notes.length() ); - snprintf( sql, sizeof(sql), "update Events set Notes = '%s' where Id = %d", escapedNotes, id ); + db_mutex.lock(); + snprintf( sql, sizeof(sql), "UPDATE Events SET Notes = '%s' WHERE Id = %d", escapedNotes, id ); if ( mysql_query( &dbconn, sql ) ) { Error( "Can't insert event: %s", mysql_error( &dbconn ) ); } + db_mutex.unlock(); #endif } } @@ -442,9 +449,11 @@ void Event::AddFramesInternal( int n_frames, int start_frame, Image **images, st if ( frameCount ) { Debug( 1, "Adding %d/%d frames to DB", frameCount, n_frames ); *(sql+strlen(sql)-2) = '\0'; + db_mutex.lock(); if ( mysql_query( &dbconn, sql ) ) { Error( "Can't insert frames: %s, sql was (%s)", mysql_error( &dbconn ), sql ); } + db_mutex.unlock(); last_db_frame = frames; } else { Debug( 1, "No valid pre-capture frames to add" ); @@ -508,16 +517,20 @@ void Event::AddFrame( Image *image, struct timeval timestamp, int score, Image * Debug( 1, "Adding frame %d of type \"%s\" to DB", frames, Event::frame_type_names[frame_type] ); static char sql[ZM_SQL_MED_BUFSIZ]; snprintf( sql, sizeof(sql), "INSERT INTO Frames ( EventId, FrameId, Type, TimeStamp, Delta, Score ) VALUES ( %d, %d, '%s', from_unixtime( %ld ), %s%ld.%02ld, %d )", id, frames, frame_type_names[frame_type], timestamp.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, score ); + db_mutex.lock(); if ( mysql_query(&dbconn, sql) ) { Error("Can't insert frame: (%s) reason:%s", sql, mysql_error(&dbconn)); zmDbClose(); - if ( ! zmDbConnect() ) + if ( ! zmDbConnect() ) { + Error("Unable to connect to db"); exit(mysql_errno(&dbconn)); + } if ( mysql_query(&dbconn, sql) ) { - Error("Can't insert frame: (%s) reason:%s", sql, mysql_error(&dbconn)); + Error("REALLY Can't insert frame: (%s) reason:%s", sql, mysql_error(&dbconn)); exit(mysql_errno(&dbconn)); } } + db_mutex.unlock(); last_db_frame = frames; // We are writing a Bulk frame @@ -532,10 +545,11 @@ void Event::AddFrame( Image *image, struct timeval timestamp, int score, Image * max_score, id ); + db_mutex.lock(); if ( mysql_query( &dbconn, sql ) ) { Error( "Can't update event: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); } + db_mutex.unlock(); } } // end if db_frame diff --git a/src/zm_logger.cpp b/src/zm_logger.cpp index 34eabb5c0..a76ee92f3 100644 --- a/src/zm_logger.cpp +++ b/src/zm_logger.cpp @@ -537,6 +537,7 @@ void Logger::logPrint( bool hex, const char * const filepath, const int line, co char sql[ZM_SQL_MED_BUFSIZ]; char escapedString[(strlen(syslogStart)*2)+1]; + db_mutex.lock(); mysql_real_escape_string( &dbconn, escapedString, syslogStart, strlen(syslogStart) ); snprintf( sql, sizeof(sql), "insert into Logs ( TimeKey, Component, ServerId, Pid, Level, Code, Message, File, Line ) values ( %ld.%06ld, '%s', %d, %d, %d, '%s', '%s', '%s', %d )", timeVal.tv_sec, timeVal.tv_usec, mId.c_str(), staticConfig.SERVER_ID, tid, level, classString, escapedString, file, line ); @@ -546,6 +547,7 @@ void Logger::logPrint( bool hex, const char * const filepath, const int line, co Error( "Can't insert log entry: sql(%s) error(%s)", sql, mysql_error( &dbconn ) ); databaseLevel(tempDatabaseLevel); } + db_mutex.unlock(); } if ( level <= mSyslogLevel ) { int priority = smSyslogPriorities[level]; diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index e8b0dca34..daaa5cdb3 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -874,10 +874,11 @@ void Monitor::actionEnable() { static char sql[ZM_SQL_SML_BUFSIZ]; snprintf( sql, sizeof(sql), "update Monitors set Enabled = 1 where Id='%d'", id ); + db_mutex.lock(); if ( mysql_query( &dbconn, sql ) ) { Error( "Can't run query: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); } + db_mutex.unlock(); } void Monitor::actionDisable() { @@ -885,10 +886,11 @@ void Monitor::actionDisable() { static char sql[ZM_SQL_SML_BUFSIZ]; snprintf( sql, sizeof(sql), "update Monitors set Enabled = 0 where Id='%d'", id ); + db_mutex.lock(); if ( mysql_query( &dbconn, sql ) ) { Error( "Can't run query: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); } + db_mutex.unlock(); } void Monitor::actionSuspend() { @@ -1233,9 +1235,11 @@ void Monitor::UpdateAnalysisFPS() { static char sql[ZM_SQL_SML_BUFSIZ]; snprintf( sql, sizeof(sql), "INSERT INTO Monitor_Status (MonitorId,AnalysisFPS) VALUES (%d, %.2lf) ON DUPLICATE KEY UPDATE AnalysisFPS = %.2lf", id, analysis_fps, analysis_fps ); + db_mutex.lock(); if ( mysql_query( &dbconn, sql ) ) { Error("Can't run query: %s", mysql_error(&dbconn)); } + db_mutex.unlock(); } last_analysis_fps_time = now.tv_sec; } @@ -1575,12 +1579,15 @@ void Monitor::Reload() { // This seems to have fallen out of date. snprintf( sql, sizeof(sql), "select Function+0, Enabled, LinkedMonitors, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, WarmupCount, PreEventCount, PostEventCount, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour from Monitors where Id = '%d'", id ); + db_mutex.lock(); if ( mysql_query( &dbconn, sql ) ) { Error( "Can't run query: %s", mysql_error( &dbconn ) ); + db_mutex.unlock(); exit( mysql_errno( &dbconn ) ); } MYSQL_RES *result = mysql_store_result( &dbconn ); + db_mutex.unlock(); if ( !result ) { Error( "Can't use query result: %s", mysql_error( &dbconn ) ); exit( mysql_errno( &dbconn ) ); @@ -1723,12 +1730,15 @@ void Monitor::ReloadLinkedMonitors( const char *p_linked_monitors ) { static char sql[ZM_SQL_SML_BUFSIZ]; snprintf( sql, sizeof(sql), "select Id, Name from Monitors where Id = %d and Function != 'None' and Function != 'Monitor' and Enabled = 1", link_ids[i] ); + db_mutex.lock(); if ( mysql_query( &dbconn, sql ) ) { Error( "Can't run query: %s", mysql_error( &dbconn ) ); + db_mutex.unlock(); exit( mysql_errno( &dbconn ) ); } MYSQL_RES *result = mysql_store_result( &dbconn ); + db_mutex.unlock(); if ( !result ) { Error( "Can't use query result: %s", mysql_error( &dbconn ) ); exit( mysql_errno( &dbconn ) ); @@ -2948,9 +2958,11 @@ int Monitor::Capture() { last_fps_time = now; static char sql[ZM_SQL_SML_BUFSIZ]; snprintf(sql, sizeof(sql), "INSERT INTO Monitor_Status (MonitorId,CaptureFPS) VALUES (%d, %.2lf) ON DUPLICATE KEY UPDATE CaptureFPS = %.2lf", id, capture_fps, capture_fps); + db_mutex.lock(); if ( mysql_query(&dbconn, sql) ) { Error("Can't run query: %s", mysql_error(&dbconn)); } + db_mutex.unlock(); } // end if fps has changed } } // end if report fps @@ -3283,9 +3295,11 @@ void Monitor::get_ref_image() { Warning( "Waiting for capture daemon lastwriteindex(%d) lastwritetime(%d)", shared_data->last_write_index, shared_data->last_write_time ); usleep( 50000 ); } + if ( zm_terminate ) + return; int last_write_index = shared_data->last_write_index ; - Warning( "Waiting for capture daemon unlock" ); + Warning( "Waiting for capture daemon unlock" ); image_buffer[last_write_index].mutex.lock(); ref_image.Assign( width, height, camera->Colours(), camera->SubpixelOrder(), image_buffer[last_write_index].image->Buffer(), camera->ImageSize()); image_buffer[last_write_index].mutex.unlock(); diff --git a/src/zm_zone.cpp b/src/zm_zone.cpp index d84af6036..ae0d82108 100644 --- a/src/zm_zone.cpp +++ b/src/zm_zone.cpp @@ -128,10 +128,11 @@ Zone::~Zone() { void Zone::RecordStats( const Event *event ) { static char sql[ZM_SQL_MED_BUFSIZ]; snprintf( sql, sizeof(sql), "insert into Stats set MonitorId=%d, ZoneId=%d, EventId=%d, FrameId=%d, PixelDiff=%d, AlarmPixels=%d, FilterPixels=%d, BlobPixels=%d, Blobs=%d, MinBlobSize=%d, MaxBlobSize=%d, MinX=%d, MinY=%d, MaxX=%d, MaxY=%d, Score=%d", monitor->Id(), id, event->Id(), event->Frames()+1, pixel_diff, alarm_pixels, alarm_filter_pixels, alarm_blob_pixels, alarm_blobs, min_blob_size, max_blob_size, alarm_box.LoX(), alarm_box.LoY(), alarm_box.HiX(), alarm_box.HiY(), score ); + db_mutex.lock(); if ( mysql_query( &dbconn, sql ) ) { Error( "Can't insert event stats: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); } + db_mutex.unlock(); } // end void Zone::RecordStats( const Event *event ) bool Zone::CheckOverloadCount() { @@ -825,15 +826,17 @@ bool Zone::ParseZoneString( const char *zone_string, int &zone_id, int &colour, int Zone::Load( Monitor *monitor, Zone **&zones ) { static char sql[ZM_SQL_MED_BUFSIZ]; snprintf( sql, sizeof(sql), "select Id,Name,Type+0,Units,Coords,AlarmRGB,CheckMethod+0,MinPixelThreshold,MaxPixelThreshold,MinAlarmPixels,MaxAlarmPixels,FilterX,FilterY,MinFilterPixels,MaxFilterPixels,MinBlobPixels,MaxBlobPixels,MinBlobs,MaxBlobs,OverloadFrames,ExtendAlarmFrames from Zones where MonitorId = %d order by Type, Id", monitor->Id() ); + db_mutex.lock(); 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 ); + db_mutex.unlock(); if ( !result ) { Error( "Can't use query result: %s", mysql_error( &dbconn ) ); - exit( mysql_errno( &dbconn ) ); + return 0; } int n_zones = mysql_num_rows( result ); Debug( 1, "Got %d zones for monitor %s", n_zones, monitor->Name() ); From 7702e09ec2787b966255e3ea8147a2e028c053b1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 16 Feb 2018 16:05:30 -0500 Subject: [PATCH 0107/2339] merge fixes --- src/zm_ffmpeg_camera.cpp | 7 +------ web/skins/classic/views/console.php | 8 -------- web/skins/classic/views/events.php | 10 ---------- 3 files changed, 1 insertion(+), 24 deletions(-) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index e24c20ac4..9c0f6a9c9 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -131,12 +131,7 @@ int FfmpegCamera::PrimeCapture() { } int FfmpegCamera::PreCapture() { - Debug(1, "PreCapture"); - // If Reopen was called, then ffmpeg is closed and we need to reopen it. - if ( ! mCanCapture ) - return OpenFfmpeg(); - // Nothing to do here - return( 0 ); + return 0; } int FfmpegCamera::Capture( ZMPacket &zm_packet ) { diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index 2dea894a4..7f4624ab2 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -186,13 +186,6 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { if ( (!$monitor['Status']) or ($monitor['Status'] == 'NotRunning') ) { $source_class = 'errorText'; } else { -<<<<<<< HEAD - // https://github.com/ZoneMinder/ZoneMinder/issues/1082 - //if ( a'] && $monitor['Function']!='Monitor' ) - //$dclass = 'warnText'; - //else - $dclass = 'infoText'; -======= if ( (!$monitor['CaptureFPS']) ) { $source_class = 'errorText'; } else if ( (!$monitor['AnalysisFPS']) && ($monitor['Function']!='Monitor') && ($monitor['Function'] != 'Nodect') ) { @@ -200,7 +193,6 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { } else { $source_class = 'infoText'; } ->>>>>>> storageareas } if ( $monitor['Function'] == 'None' ) $fclass = 'errorText'; diff --git a/web/skins/classic/views/events.php b/web/skins/classic/views/events.php index 9ad61f363..d9e9d423f 100644 --- a/web/skins/classic/views/events.php +++ b/web/skins/classic/views/events.php @@ -213,17 +213,7 @@ while ( $event_row = dbFetchNext( $results ) ) { $streamSrc = $event->getStreamSrc( array( 'mode'=>'jpeg', 'scale'=>$scale, 'maxfps'=>ZM_WEB_VIDEO_MAXFPS, 'replay'=>'single') ); $imgHtml = ''. validHtmlStr('Event '.$event->Id()) .''; -<<<<<<< HEAD - - echo makePopupLink( - '?view=frame&eid='.$event->Id().'&fid='.( isset($thumbData['FrameId']) ? $thumbData['FrameId'] : 'snapshot' ), - 'zmImage', - array( 'image', reScale( $event->Width(), $scale ), reScale( $event->Height(), $scale ) ), - $imgHtml - ); -======= echo ''.$imgHtml.''; ->>>>>>> storageareas ?> Date: Sat, 17 Feb 2018 10:54:53 -0500 Subject: [PATCH 0108/2339] add back AnalysisFPS reporting and move the gettimeofday in after it is actually needed --- src/zm_monitor.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index daaa5cdb3..c8e75b5ce 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1225,9 +1225,9 @@ void Monitor::CheckAction() { } void Monitor::UpdateAnalysisFPS() { - struct timeval now; - gettimeofday( &now, NULL ); if ( analysis_image_count && fps_report_interval && !(analysis_image_count%fps_report_interval) ) { + struct timeval now; + gettimeofday(&now, NULL); double new_analysis_fps = double(fps_report_interval)/(now.tv_sec - last_analysis_fps_time); Info("%s: %d - Analysing at %.2f fps", name, image_count, new_analysis_fps); if ( new_analysis_fps != analysis_fps ) { @@ -1562,6 +1562,7 @@ bool Monitor::Analyse() { analysis_image_count++; snap->unlock(); } // end while not at end of packetqueue + UpdateAnalysisFPS(); if ( packets_processed > 0 ) return true; return false; From e991e2a05df3fcea8843b192d3131d48f0dbd03f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 17 Feb 2018 12:57:21 -0500 Subject: [PATCH 0109/2339] fix some triggers --- db/triggers.sql | 313 +++++++++++++++++++++++++++++++++++++++ db/zm_create.sql.in | 33 +++-- db/zm_update-1.31.17.sql | 12 ++ db/zm_update-1.31.38.sql | 313 +++++++++++++++++++++++++++++++++++++++ version | 2 +- 5 files changed, 657 insertions(+), 16 deletions(-) create mode 100644 db/triggers.sql create mode 100644 db/zm_update-1.31.38.sql diff --git a/db/triggers.sql b/db/triggers.sql new file mode 100644 index 000000000..c98586640 --- /dev/null +++ b/db/triggers.sql @@ -0,0 +1,313 @@ + +delimiter // +DROP TRIGGER IF EXISTS Events_Hour_delete_trigger// +CREATE TRIGGER Events_Hour_delete_trigger BEFORE DELETE ON Events_Hour +FOR EACH ROW BEGIN + UPDATE Monitors SET + HourEvents = COALESCE(HourEvents,1)-1, + HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) + WHERE Id=OLD.MonitorId; +END; +// + +DROP TRIGGER IF EXISTS Events_Hour_update_trigger// + +CREATE TRIGGER Events_Hour_update_trigger AFTER UPDATE ON Events_Hour +FOR EACH ROW + BEGIN + declare diff BIGINT default 0; + + set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); + IF ( diff ) THEN + IF ( NEW.MonitorID != OLD.MonitorID ) THEN + UPDATE Monitors SET HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) WHERE Monitors.Id=OLD.MonitorId; + UPDATE Monitors SET HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)-COALESCE(NEW.DiskSpace,0) WHERE Monitors.Id=NEW.MonitorId; + ELSE + UPDATE Monitors SET HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)+diff WHERE Monitors.Id=NEW.MonitorId; + END IF; + END IF; + END; +// +DELIMITER ; + +DROP TABLE IF EXISTS `Events_Day`; +CREATE TABLE `Events_Day` ( + `EventId` int(10) unsigned NOT NULL, + `MonitorId` int(10) unsigned NOT NULL, + `StartTime` datetime default NULL, + `DiskSpace` bigint unsigned default NULL, + PRIMARY KEY (`EventId`), + KEY `Events_Day_MonitorId_idx` (`MonitorId`), + KEY `Events_Day_StartTime_idx` (`StartTime`) +) ENGINE=@ZM_MYSQL_ENGINE@; + +delimiter // +DROP TRIGGER IF EXISTS Events_Day_delete_trigger// +CREATE TRIGGER Events_Day_delete_trigger BEFORE DELETE ON Events_Day +FOR EACH ROW BEGIN + UPDATE Monitors SET + DayEvents = COALESCE(DayEvents,1)-1, + DayEventDiskSpace=COALESCE(DayEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) + WHERE Id=OLD.MonitorId; +END; +// + +DROP TRIGGER IF EXISTS Events_Day_update_trigger; +CREATE TRIGGER Events_Day_update_trigger AFTER UPDATE ON Events_Day +FOR EACH ROW + BEGIN + declare diff BIGINT default 0; + + set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); + IF ( diff ) THEN + IF ( NEW.MonitorID != OLD.MonitorID ) THEN + UPDATE Monitors SET DayEventDiskSpace=COALESCE(DayEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) WHERE Monitors.Id=OLD.MonitorId; + UPDATE Monitors SET DayEventDiskSpace=COALESCE(DayEventDiskSpace,0)+COALESCE(NEW.DiskSpace,0) WHERE Monitors.Id=NEW.MonitorId; + ELSE + UPDATE Monitors SET DayEventDiskSpace=COALESCE(DayEventDiskSpace,0)+diff WHERE Monitors.Id=NEW.MonitorId; + END IF; + END IF; + END; + // + + +DELIMITER ; +DROP TABLE IF EXISTS `Events_Week`; +CREATE TABLE `Events_Week` ( + `EventId` int(10) unsigned NOT NULL, + `MonitorId` int(10) unsigned NOT NULL, + `StartTime` datetime default NULL, + `DiskSpace` bigint unsigned default NULL, + PRIMARY KEY (`EventId`), + KEY `Events_Week_MonitorId_idx` (`MonitorId`), + KEY `Events_Week_StartTime_idx` (`StartTime`) +) ENGINE=@ZM_MYSQL_ENGINE@; + +delimiter // +DROP TRIGGER IF EXISTS Events_Week_delete_trigger// +CREATE TRIGGER Events_Week_delete_trigger BEFORE DELETE ON Events_Week +FOR EACH ROW BEGIN + UPDATE Monitors SET + WeekEvents = COALESCE(WeekEvents,1)-1, + WeekEventDiskSpace=COALESCE(WeekEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) + WHERE Id=OLD.MonitorId; +END; +// + +DROP TRIGGER IF EXISTS Events_Week_update_trigger; +CREATE TRIGGER Events_Week_update_trigger AFTER UPDATE ON Events_Week +FOR EACH ROW + BEGIN + declare diff BIGINT default 0; + + set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); + IF ( diff ) THEN + IF ( NEW.MonitorID != OLD.MonitorID ) THEN + UPDATE Monitors SET WeekEventDiskSpace=COALESCE(WeekEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) WHERE Monitors.Id=OLD.MonitorId; + UPDATE Monitors SET WeekEventDiskSpace=COALESCE(WeekEventDiskSpace,0)+COALESCE(NEW.DiskSpace,0) WHERE Monitors.Id=NEW.MonitorId; + ELSE + UPDATE Monitors SET WeekEventDiskSpace=COALESCE(WeekEventDiskSpace,0)+diff WHERE Monitors.Id=NEW.MonitorId; + END IF; + END IF; + END; + // + +DELIMITER ; + +DROP TABLE IF EXISTS `Events_Month`; +CREATE TABLE `Events_Month` ( + `EventId` int(10) unsigned NOT NULL, + `MonitorId` int(10) unsigned NOT NULL, + `StartTime` datetime default NULL, + `DiskSpace` bigint unsigned default NULL, + PRIMARY KEY (`EventId`), + KEY `Events_Month_MonitorId_idx` (`MonitorId`), + KEY `Events_Month_StartTime_idx` (`StartTime`) +) ENGINE=@ZM_MYSQL_ENGINE@; + +delimiter // +DROP TRIGGER IF EXISTS Events_Month_delete_trigger// +CREATE TRIGGER Events_Month_delete_trigger BEFORE DELETE ON Events_Month +FOR EACH ROW BEGIN + UPDATE Monitors SET + MonthEvents = COALESCE(MonthEvents,1)-1, + MonthEventDiskSpace=COALESCE(MonthEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) + WHERE Id=OLD.MonitorId; +END; +// + + +DROP TRIGGER IF EXISTS Events_Month_update_trigger; +CREATE TRIGGER Events_Month_update_trigger AFTER UPDATE ON Events_Month +FOR EACH ROW + BEGIN + declare diff BIGINT default 0; + + set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); + IF ( diff ) THEN + IF ( NEW.MonitorID != OLD.MonitorID ) THEN + UPDATE Monitors SET MonthEventDiskSpace=COALESCE(MonthEventDiskSpace,0)-COALESCE(OLD.DiskSpace) WHERE Monitors.Id=OLD.MonitorId; + UPDATE Monitors SET MonthEventDiskSpace=COALESCE(MonthEventDiskSpace,0)+COALESCE(NEW.DiskSpace) WHERE Monitors.Id=NEW.MonitorId; + ELSE + UPDATE Monitors SET MonthEventDiskSpace=COALESCE(MonthEventDiskSpace,0)+diff WHERE Monitors.Id=NEW.MonitorId; + END IF; + END IF; + END; + // + + +DELIMITER ; + +DROP TABLE IF EXISTS `Events_Archived`; +CREATE TABLE `Events_Archived` ( + `EventId` int(10) unsigned NOT NULL, + `MonitorId` int(10) unsigned NOT NULL, + `DiskSpace` bigint unsigned default NULL, + PRIMARY KEY (`EventId`), + KEY `Events_Archived_MonitorId_idx` (`MonitorId`) +) ENGINE=@ZM_MYSQL_ENGINE@; + + +drop procedure if exists update_storage_stats; + +delimiter // + +create procedure update_storage_stats(IN StorageId smallint(5), IN space BIGINT) + +sql security invoker + +deterministic + +begin + + update Storage set DiskSpace = COALESCE(DiskSpace,0) + COALESCE(space,0) where Id = StorageId; + +end; + +// + +drop trigger if exists event_update_trigger// + +CREATE TRIGGER event_update_trigger AFTER UPDATE ON Events +FOR EACH ROW +BEGIN + declare diff BIGINT default 0; + + set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); + IF ( NEW.StorageId = OLD.StorageID ) THEN + IF ( diff ) THEN + call update_storage_stats(OLD.StorageId, diff); + END IF; + ELSE + IF ( NEW.DiskSpace ) THEN + call update_storage_stats(NEW.StorageId, NEW.DiskSpace); + END IF; + IF ( OLD.DiskSpace ) THEN + call update_storage_stats(OLD.StorageId, -OLD.DiskSpace); + END IF; + END IF; + + UPDATE Events_Hour SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; + UPDATE Events_Day SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; + UPDATE Events_Week SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; + UPDATE Events_Month SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; + + IF ( NEW.Archived != OLD.Archived ) THEN + IF ( NEW.Archived ) THEN + INSERT INTO Events_Archived (EventId,MonitorId,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.DiskSpace); + UPDATE Monitors SET ArchivedEvents = COALESCE(ArchivedEvents,0)+1, ArchivedEventDiskSpace = COALESCE(ArchivedEventDiskSpace,0) + COALESCE(NEW.DiskSpace,0) WHERE Id=NEW.MonitorId; + ELSEIF ( OLD.Archived ) THEN + DELETE FROM Events_Archived WHERE EventId=OLD.Id; + UPDATE Monitors SET ArchivedEvents = COALESCE(ArchivedEvents,0)-1, ArchivedEventDiskSpace = COALESCE(ArchivedEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0) WHERE Id=OLD.MonitorId; + ELSE + IF ( OLD.DiskSpace != NEW.DiskSpace ) THEN + UPDATE Events_Archived SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; + UPDATE Monitors SET + ArchivedEventDiskSpace = COALESCE(ArchivedEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0) + COALESCE(NEW.DiskSpace,0) + WHERE Id=OLD.MonitorId; + END IF; + END IF; + ELSE IF ( NEW.Archived AND diff ) THEN + UPDATE Events_Archived SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; + END IF; + + IF ( diff ) THEN + UPDATE Monitors SET TotalEventDiskSpace = COALESCE(TotalEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0) + COALESCE(NEW.DiskSpace,0) WHERE Id=OLD.MonitorId; + END IF; + +END; + +// + +delimiter ; + +DROP TRIGGER IF EXISTS event_insert_trigger; + +delimiter // +/* The assumption is that when an Event is inserted, it has no size yet, so don't bother updating the DiskSpace, just the count. + * The DiskSpace will get update in the Event Update Trigger + */ +CREATE TRIGGER event_insert_trigger AFTER INSERT ON Events +FOR EACH ROW + BEGIN + + INSERT INTO Events_Hour (EventId,MonitorId,StartTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartTime,0); + INSERT INTO Events_Day (EventId,MonitorId,StartTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartTime,0); + INSERT INTO Events_Week (EventId,MonitorId,StartTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartTime,0); + INSERT INTO Events_Month (EventId,MonitorId,StartTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartTime,0); + UPDATE Monitors SET + HourEvents = COALESCE(DayEvents,0)+1, + DayEvents = COALESCE(DayEvents,0)+1, + WeekEvents = COALESCE(DayEvents,0)+1, + MonthEvents = COALESCE(DayEvents,0)+1, + TotalEvents = COALESCE(TotalEvents,0)+1 + WHERE Id=NEW.MonitorId; +END; +// + +DROP TRIGGER IF EXISTS event_delete_trigger// + +CREATE TRIGGER event_delete_trigger BEFORE DELETE ON Events +FOR EACH ROW +BEGIN + IF ( OLD.DiskSpace ) THEN + call update_storage_stats(OLD.StorageId, -OLD.DiskSpace); + END IF; + DELETE FROM Events_Hour WHERE EventId=OLD.Id; + DELETE FROM Events_Day WHERE EventId=OLD.Id; + DELETE FROM Events_Week WHERE EventId=OLD.Id; + DELETE FROM Events_Month WHERE EventId=OLD.Id; + IF ( OLD.Archived ) THEN + DELETE FROM Events_Archived WHERE EventId=OLD.Id; + UPDATE Monitors SET + ArchivedEvents = COALESCE(ArchivedEvents,1) - 1, + ArchivedEventDiskSpace = COALESCE(ArchivedEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0), + TotalEvents = COALESCE(TotalEvents,1) - 1, + TotalEventDiskSpace = COALESCE(TotalEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0) + WHERE Id=OLD.MonitorId; + ELSE + UPDATE Monitors SET + TotalEvents = COALESCE(TotalEvents,1)-1, + TotalEventDiskSpace=COALESCE(TotalEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) + WHERE Id=OLD.MonitorId; + END IF; +END; + +// + +DROP TRIGGER IF EXISTS Zone_Insert_Trigger// +CREATE TRIGGER Zone_Insert_Trigger AFTER INSERT ON Zones +FOR EACH ROW + BEGIN + UPDATE Monitors SET ZoneCount=(SELECT COUNT(*) FROM Zones WHERE MonitorId=NEW.MonitorId) WHERE Id=NEW.MonitorID; + END +// +DROP TRIGGER IF EXISTS Zone_Delete_Trigger// +CREATE TRIGGER Zone_Delete_Trigger AFTER DELETE ON Zones +FOR EACH ROW + BEGIN + UPDATE Monitors SET ZoneCount=(SELECT COUNT(*) FROM Zones WHERE MonitorId=OLD.MonitorId) WHERE Id=OLD.MonitorID; + END +// + +DELIMITER ; diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index a73bc524d..fe1523d9c 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -234,7 +234,7 @@ CREATE TRIGGER Events_Hour_delete_trigger BEFORE DELETE ON Events_Hour FOR EACH ROW BEGIN UPDATE Monitors SET HourEvents = COALESCE(HourEvents,1)-1, - HourEventDiskSpace=COALESCE(HourEventDiskSpace)-COALESCE(OLD.DiskSpace,0) + HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) WHERE Id=OLD.MonitorId; END; // @@ -249,10 +249,10 @@ FOR EACH ROW set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); IF ( diff ) THEN IF ( NEW.MonitorID != OLD.MonitorID ) THEN - UPDATE Monitors SET HourEventDiskSpace=COALESCE(DayEventDiskSpace,0)-OLD.DiskSpace WHERE Monitors.Id=OLD.MonitorId; - UPDATE Monitors SET HourEventDiskSpace=COALESCE(DayEventDiskSpace,0)+NEW.DiskSpace WHERE Monitors.Id=NEW.MonitorId; + UPDATE Monitors SET HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) WHERE Monitors.Id=OLD.MonitorId; + UPDATE Monitors SET HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)-COALESCE(NEW.DiskSpace,0) WHERE Monitors.Id=NEW.MonitorId; ELSE - UPDATE Monitors SET HourEventDiskSpace=COALESCE(DayEventDiskSpace,0)+diff WHERE Monitors.Id=NEW.MonitorId; + UPDATE Monitors SET HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)+diff WHERE Monitors.Id=NEW.MonitorId; END IF; END IF; END; @@ -290,8 +290,8 @@ FOR EACH ROW set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); IF ( diff ) THEN IF ( NEW.MonitorID != OLD.MonitorID ) THEN - UPDATE Monitors SET DayEventDiskSpace=COALESCE(DayEventDiskSpace,0)-OLD.DiskSpace WHERE Monitors.Id=OLD.MonitorId; - UPDATE Monitors SET DayEventDiskSpace=COALESCE(DayEventDiskSpace,0)+NEW.DiskSpace WHERE Monitors.Id=NEW.MonitorId; + UPDATE Monitors SET DayEventDiskSpace=COALESCE(DayEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) WHERE Monitors.Id=OLD.MonitorId; + UPDATE Monitors SET DayEventDiskSpace=COALESCE(DayEventDiskSpace,0)+COALESCE(NEW.DiskSpace,0) WHERE Monitors.Id=NEW.MonitorId; ELSE UPDATE Monitors SET DayEventDiskSpace=COALESCE(DayEventDiskSpace,0)+diff WHERE Monitors.Id=NEW.MonitorId; END IF; @@ -332,8 +332,8 @@ FOR EACH ROW set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); IF ( diff ) THEN IF ( NEW.MonitorID != OLD.MonitorID ) THEN - UPDATE Monitors SET WeekEventDiskSpace=COALESCE(WeekEventDiskSpace,0)-OLD.DiskSpace WHERE Monitors.Id=OLD.MonitorId; - UPDATE Monitors SET WeekEventDiskSpace=COALESCE(WeekEventDiskSpace,0)+NEW.DiskSpace WHERE Monitors.Id=NEW.MonitorId; + UPDATE Monitors SET WeekEventDiskSpace=COALESCE(WeekEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) WHERE Monitors.Id=OLD.MonitorId; + UPDATE Monitors SET WeekEventDiskSpace=COALESCE(WeekEventDiskSpace,0)+COALESCE(NEW.DiskSpace,0) WHERE Monitors.Id=NEW.MonitorId; ELSE UPDATE Monitors SET WeekEventDiskSpace=COALESCE(WeekEventDiskSpace,0)+diff WHERE Monitors.Id=NEW.MonitorId; END IF; @@ -375,8 +375,8 @@ FOR EACH ROW set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); IF ( diff ) THEN IF ( NEW.MonitorID != OLD.MonitorID ) THEN - UPDATE Monitors SET MonthEventDiskSpace=COALESCE(MonthEventDiskSpace,0)-OLD.DiskSpace WHERE Monitors.Id=OLD.MonitorId; - UPDATE Monitors SET MonthEventDiskSpace=COALESCE(MonthEventDiskSpace,0)+NEW.DiskSpace WHERE Monitors.Id=NEW.MonitorId; + UPDATE Monitors SET MonthEventDiskSpace=COALESCE(MonthEventDiskSpace,0)-COALESCE(OLD.DiskSpace) WHERE Monitors.Id=OLD.MonitorId; + UPDATE Monitors SET MonthEventDiskSpace=COALESCE(MonthEventDiskSpace,0)+COALESCE(NEW.DiskSpace) WHERE Monitors.Id=NEW.MonitorId; ELSE UPDATE Monitors SET MonthEventDiskSpace=COALESCE(MonthEventDiskSpace,0)+diff WHERE Monitors.Id=NEW.MonitorId; END IF; @@ -422,7 +422,7 @@ FOR EACH ROW BEGIN declare diff BIGINT default 0; - set diff = NEW.DiskSpace - OLD.DiskSpace; + set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); IF ( NEW.StorageId = OLD.StorageID ) THEN IF ( diff ) THEN call update_storage_stats(OLD.StorageId, diff); @@ -440,6 +440,7 @@ BEGIN UPDATE Events_Day SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; UPDATE Events_Week SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; UPDATE Events_Month SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; + IF ( NEW.Archived != OLD.Archived ) THEN IF ( NEW.Archived ) THEN INSERT INTO Events_Archived (EventId,MonitorId,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.DiskSpace); @@ -455,9 +456,11 @@ BEGIN WHERE Id=OLD.MonitorId; END IF; END IF; + ELSE IF ( NEW.Archived AND diff ) THEN + UPDATE Events_Archived SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; END IF; - IF ( OLD.DiskSpace != NEW.DiskSpace ) THEN + IF ( diff ) THEN UPDATE Monitors SET TotalEventDiskSpace = COALESCE(TotalEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0) + COALESCE(NEW.DiskSpace,0) WHERE Id=OLD.MonitorId; END IF; @@ -506,14 +509,14 @@ BEGIN IF ( OLD.Archived ) THEN DELETE FROM Events_Archived WHERE EventId=OLD.Id; UPDATE Monitors SET - ArchivedEvents = ArchivedEvents - 1, + ArchivedEvents = COALESCE(ArchivedEvents,1) - 1, ArchivedEventDiskSpace = COALESCE(ArchivedEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0), - TotalEvents = TotalEvents - 1, + TotalEvents = COALESCE(TotalEvents,1) - 1, TotalEventDiskSpace = COALESCE(TotalEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0) WHERE Id=OLD.MonitorId; ELSE UPDATE Monitors SET - TotalEvents = TotalEvents-1, + TotalEvents = COALESCE(TotalEvents,1)-1, TotalEventDiskSpace=COALESCE(TotalEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) WHERE Id=OLD.MonitorId; END IF; diff --git a/db/zm_update-1.31.17.sql b/db/zm_update-1.31.17.sql index 78d50d153..878fdc6d9 100644 --- a/db/zm_update-1.31.17.sql +++ b/db/zm_update-1.31.17.sql @@ -3,6 +3,18 @@ alter table Events DROP Primary key; alter table Events Add Primary key(Id); alter table Events modify Id int(10) unsigned auto_increment; +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Storage' + AND column_name = 'DiskSpace' + ) > 0, + "SELECT 'Column DiskSpace already exists in Storage'", + "ALTER TABLE Storage ADD `DiskSpace` BIGINT default null AFTER `Type`" + )); + +PREPARE stmt FROM @s; +EXECUTE stmt; + SET @s = (SELECT IF( (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() AND table_name = 'Storage' diff --git a/db/zm_update-1.31.38.sql b/db/zm_update-1.31.38.sql new file mode 100644 index 000000000..c98586640 --- /dev/null +++ b/db/zm_update-1.31.38.sql @@ -0,0 +1,313 @@ + +delimiter // +DROP TRIGGER IF EXISTS Events_Hour_delete_trigger// +CREATE TRIGGER Events_Hour_delete_trigger BEFORE DELETE ON Events_Hour +FOR EACH ROW BEGIN + UPDATE Monitors SET + HourEvents = COALESCE(HourEvents,1)-1, + HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) + WHERE Id=OLD.MonitorId; +END; +// + +DROP TRIGGER IF EXISTS Events_Hour_update_trigger// + +CREATE TRIGGER Events_Hour_update_trigger AFTER UPDATE ON Events_Hour +FOR EACH ROW + BEGIN + declare diff BIGINT default 0; + + set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); + IF ( diff ) THEN + IF ( NEW.MonitorID != OLD.MonitorID ) THEN + UPDATE Monitors SET HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) WHERE Monitors.Id=OLD.MonitorId; + UPDATE Monitors SET HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)-COALESCE(NEW.DiskSpace,0) WHERE Monitors.Id=NEW.MonitorId; + ELSE + UPDATE Monitors SET HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)+diff WHERE Monitors.Id=NEW.MonitorId; + END IF; + END IF; + END; +// +DELIMITER ; + +DROP TABLE IF EXISTS `Events_Day`; +CREATE TABLE `Events_Day` ( + `EventId` int(10) unsigned NOT NULL, + `MonitorId` int(10) unsigned NOT NULL, + `StartTime` datetime default NULL, + `DiskSpace` bigint unsigned default NULL, + PRIMARY KEY (`EventId`), + KEY `Events_Day_MonitorId_idx` (`MonitorId`), + KEY `Events_Day_StartTime_idx` (`StartTime`) +) ENGINE=@ZM_MYSQL_ENGINE@; + +delimiter // +DROP TRIGGER IF EXISTS Events_Day_delete_trigger// +CREATE TRIGGER Events_Day_delete_trigger BEFORE DELETE ON Events_Day +FOR EACH ROW BEGIN + UPDATE Monitors SET + DayEvents = COALESCE(DayEvents,1)-1, + DayEventDiskSpace=COALESCE(DayEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) + WHERE Id=OLD.MonitorId; +END; +// + +DROP TRIGGER IF EXISTS Events_Day_update_trigger; +CREATE TRIGGER Events_Day_update_trigger AFTER UPDATE ON Events_Day +FOR EACH ROW + BEGIN + declare diff BIGINT default 0; + + set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); + IF ( diff ) THEN + IF ( NEW.MonitorID != OLD.MonitorID ) THEN + UPDATE Monitors SET DayEventDiskSpace=COALESCE(DayEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) WHERE Monitors.Id=OLD.MonitorId; + UPDATE Monitors SET DayEventDiskSpace=COALESCE(DayEventDiskSpace,0)+COALESCE(NEW.DiskSpace,0) WHERE Monitors.Id=NEW.MonitorId; + ELSE + UPDATE Monitors SET DayEventDiskSpace=COALESCE(DayEventDiskSpace,0)+diff WHERE Monitors.Id=NEW.MonitorId; + END IF; + END IF; + END; + // + + +DELIMITER ; +DROP TABLE IF EXISTS `Events_Week`; +CREATE TABLE `Events_Week` ( + `EventId` int(10) unsigned NOT NULL, + `MonitorId` int(10) unsigned NOT NULL, + `StartTime` datetime default NULL, + `DiskSpace` bigint unsigned default NULL, + PRIMARY KEY (`EventId`), + KEY `Events_Week_MonitorId_idx` (`MonitorId`), + KEY `Events_Week_StartTime_idx` (`StartTime`) +) ENGINE=@ZM_MYSQL_ENGINE@; + +delimiter // +DROP TRIGGER IF EXISTS Events_Week_delete_trigger// +CREATE TRIGGER Events_Week_delete_trigger BEFORE DELETE ON Events_Week +FOR EACH ROW BEGIN + UPDATE Monitors SET + WeekEvents = COALESCE(WeekEvents,1)-1, + WeekEventDiskSpace=COALESCE(WeekEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) + WHERE Id=OLD.MonitorId; +END; +// + +DROP TRIGGER IF EXISTS Events_Week_update_trigger; +CREATE TRIGGER Events_Week_update_trigger AFTER UPDATE ON Events_Week +FOR EACH ROW + BEGIN + declare diff BIGINT default 0; + + set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); + IF ( diff ) THEN + IF ( NEW.MonitorID != OLD.MonitorID ) THEN + UPDATE Monitors SET WeekEventDiskSpace=COALESCE(WeekEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) WHERE Monitors.Id=OLD.MonitorId; + UPDATE Monitors SET WeekEventDiskSpace=COALESCE(WeekEventDiskSpace,0)+COALESCE(NEW.DiskSpace,0) WHERE Monitors.Id=NEW.MonitorId; + ELSE + UPDATE Monitors SET WeekEventDiskSpace=COALESCE(WeekEventDiskSpace,0)+diff WHERE Monitors.Id=NEW.MonitorId; + END IF; + END IF; + END; + // + +DELIMITER ; + +DROP TABLE IF EXISTS `Events_Month`; +CREATE TABLE `Events_Month` ( + `EventId` int(10) unsigned NOT NULL, + `MonitorId` int(10) unsigned NOT NULL, + `StartTime` datetime default NULL, + `DiskSpace` bigint unsigned default NULL, + PRIMARY KEY (`EventId`), + KEY `Events_Month_MonitorId_idx` (`MonitorId`), + KEY `Events_Month_StartTime_idx` (`StartTime`) +) ENGINE=@ZM_MYSQL_ENGINE@; + +delimiter // +DROP TRIGGER IF EXISTS Events_Month_delete_trigger// +CREATE TRIGGER Events_Month_delete_trigger BEFORE DELETE ON Events_Month +FOR EACH ROW BEGIN + UPDATE Monitors SET + MonthEvents = COALESCE(MonthEvents,1)-1, + MonthEventDiskSpace=COALESCE(MonthEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) + WHERE Id=OLD.MonitorId; +END; +// + + +DROP TRIGGER IF EXISTS Events_Month_update_trigger; +CREATE TRIGGER Events_Month_update_trigger AFTER UPDATE ON Events_Month +FOR EACH ROW + BEGIN + declare diff BIGINT default 0; + + set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); + IF ( diff ) THEN + IF ( NEW.MonitorID != OLD.MonitorID ) THEN + UPDATE Monitors SET MonthEventDiskSpace=COALESCE(MonthEventDiskSpace,0)-COALESCE(OLD.DiskSpace) WHERE Monitors.Id=OLD.MonitorId; + UPDATE Monitors SET MonthEventDiskSpace=COALESCE(MonthEventDiskSpace,0)+COALESCE(NEW.DiskSpace) WHERE Monitors.Id=NEW.MonitorId; + ELSE + UPDATE Monitors SET MonthEventDiskSpace=COALESCE(MonthEventDiskSpace,0)+diff WHERE Monitors.Id=NEW.MonitorId; + END IF; + END IF; + END; + // + + +DELIMITER ; + +DROP TABLE IF EXISTS `Events_Archived`; +CREATE TABLE `Events_Archived` ( + `EventId` int(10) unsigned NOT NULL, + `MonitorId` int(10) unsigned NOT NULL, + `DiskSpace` bigint unsigned default NULL, + PRIMARY KEY (`EventId`), + KEY `Events_Archived_MonitorId_idx` (`MonitorId`) +) ENGINE=@ZM_MYSQL_ENGINE@; + + +drop procedure if exists update_storage_stats; + +delimiter // + +create procedure update_storage_stats(IN StorageId smallint(5), IN space BIGINT) + +sql security invoker + +deterministic + +begin + + update Storage set DiskSpace = COALESCE(DiskSpace,0) + COALESCE(space,0) where Id = StorageId; + +end; + +// + +drop trigger if exists event_update_trigger// + +CREATE TRIGGER event_update_trigger AFTER UPDATE ON Events +FOR EACH ROW +BEGIN + declare diff BIGINT default 0; + + set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); + IF ( NEW.StorageId = OLD.StorageID ) THEN + IF ( diff ) THEN + call update_storage_stats(OLD.StorageId, diff); + END IF; + ELSE + IF ( NEW.DiskSpace ) THEN + call update_storage_stats(NEW.StorageId, NEW.DiskSpace); + END IF; + IF ( OLD.DiskSpace ) THEN + call update_storage_stats(OLD.StorageId, -OLD.DiskSpace); + END IF; + END IF; + + UPDATE Events_Hour SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; + UPDATE Events_Day SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; + UPDATE Events_Week SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; + UPDATE Events_Month SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; + + IF ( NEW.Archived != OLD.Archived ) THEN + IF ( NEW.Archived ) THEN + INSERT INTO Events_Archived (EventId,MonitorId,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.DiskSpace); + UPDATE Monitors SET ArchivedEvents = COALESCE(ArchivedEvents,0)+1, ArchivedEventDiskSpace = COALESCE(ArchivedEventDiskSpace,0) + COALESCE(NEW.DiskSpace,0) WHERE Id=NEW.MonitorId; + ELSEIF ( OLD.Archived ) THEN + DELETE FROM Events_Archived WHERE EventId=OLD.Id; + UPDATE Monitors SET ArchivedEvents = COALESCE(ArchivedEvents,0)-1, ArchivedEventDiskSpace = COALESCE(ArchivedEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0) WHERE Id=OLD.MonitorId; + ELSE + IF ( OLD.DiskSpace != NEW.DiskSpace ) THEN + UPDATE Events_Archived SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; + UPDATE Monitors SET + ArchivedEventDiskSpace = COALESCE(ArchivedEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0) + COALESCE(NEW.DiskSpace,0) + WHERE Id=OLD.MonitorId; + END IF; + END IF; + ELSE IF ( NEW.Archived AND diff ) THEN + UPDATE Events_Archived SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; + END IF; + + IF ( diff ) THEN + UPDATE Monitors SET TotalEventDiskSpace = COALESCE(TotalEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0) + COALESCE(NEW.DiskSpace,0) WHERE Id=OLD.MonitorId; + END IF; + +END; + +// + +delimiter ; + +DROP TRIGGER IF EXISTS event_insert_trigger; + +delimiter // +/* The assumption is that when an Event is inserted, it has no size yet, so don't bother updating the DiskSpace, just the count. + * The DiskSpace will get update in the Event Update Trigger + */ +CREATE TRIGGER event_insert_trigger AFTER INSERT ON Events +FOR EACH ROW + BEGIN + + INSERT INTO Events_Hour (EventId,MonitorId,StartTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartTime,0); + INSERT INTO Events_Day (EventId,MonitorId,StartTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartTime,0); + INSERT INTO Events_Week (EventId,MonitorId,StartTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartTime,0); + INSERT INTO Events_Month (EventId,MonitorId,StartTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartTime,0); + UPDATE Monitors SET + HourEvents = COALESCE(DayEvents,0)+1, + DayEvents = COALESCE(DayEvents,0)+1, + WeekEvents = COALESCE(DayEvents,0)+1, + MonthEvents = COALESCE(DayEvents,0)+1, + TotalEvents = COALESCE(TotalEvents,0)+1 + WHERE Id=NEW.MonitorId; +END; +// + +DROP TRIGGER IF EXISTS event_delete_trigger// + +CREATE TRIGGER event_delete_trigger BEFORE DELETE ON Events +FOR EACH ROW +BEGIN + IF ( OLD.DiskSpace ) THEN + call update_storage_stats(OLD.StorageId, -OLD.DiskSpace); + END IF; + DELETE FROM Events_Hour WHERE EventId=OLD.Id; + DELETE FROM Events_Day WHERE EventId=OLD.Id; + DELETE FROM Events_Week WHERE EventId=OLD.Id; + DELETE FROM Events_Month WHERE EventId=OLD.Id; + IF ( OLD.Archived ) THEN + DELETE FROM Events_Archived WHERE EventId=OLD.Id; + UPDATE Monitors SET + ArchivedEvents = COALESCE(ArchivedEvents,1) - 1, + ArchivedEventDiskSpace = COALESCE(ArchivedEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0), + TotalEvents = COALESCE(TotalEvents,1) - 1, + TotalEventDiskSpace = COALESCE(TotalEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0) + WHERE Id=OLD.MonitorId; + ELSE + UPDATE Monitors SET + TotalEvents = COALESCE(TotalEvents,1)-1, + TotalEventDiskSpace=COALESCE(TotalEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) + WHERE Id=OLD.MonitorId; + END IF; +END; + +// + +DROP TRIGGER IF EXISTS Zone_Insert_Trigger// +CREATE TRIGGER Zone_Insert_Trigger AFTER INSERT ON Zones +FOR EACH ROW + BEGIN + UPDATE Monitors SET ZoneCount=(SELECT COUNT(*) FROM Zones WHERE MonitorId=NEW.MonitorId) WHERE Id=NEW.MonitorID; + END +// +DROP TRIGGER IF EXISTS Zone_Delete_Trigger// +CREATE TRIGGER Zone_Delete_Trigger AFTER DELETE ON Zones +FOR EACH ROW + BEGIN + UPDATE Monitors SET ZoneCount=(SELECT COUNT(*) FROM Zones WHERE MonitorId=OLD.MonitorId) WHERE Id=OLD.MonitorID; + END +// + +DELIMITER ; diff --git a/version b/version index c6e42f25b..83ee230bb 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.31.37 +1.31.38 From 670a979a0e41c01f83b83f1765213d16f95a910e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 17 Feb 2018 12:59:53 -0500 Subject: [PATCH 0110/2339] source triggers.sql --- db/zm_create.sql.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index fe1523d9c..c5ae118c8 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -1154,10 +1154,11 @@ INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('3 Wide', '{ "default":{ INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('4 Wide', '{ "default":{"float":"left", "width":"24.5%","left":"0px","right":"0px","top":"0px","bottom":"0px"} }' ); INSERT INTO MontageLayouts (`Name`,`Positions`) VALUES ('5 Wide', '{ "default":{"float":"left", "width":"19%","left":"0px","right":"0px","top":"0px","bottom":"0px"} }' ); +-- We generally don't alter triggers, we drop and re-create them, so let's keep them in a separate file that we can just source in update scripts. +source triggers.sql -- -- Apply the initial configuration -- -- This section is autogenerated by zmconfgen.pl -- Do not edit this file as any changes will be overwritten -- - From 50eaa690d7ba59588de915479cb40be690e3d215 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 17 Feb 2018 13:00:24 -0500 Subject: [PATCH 0111/2339] just source the complete list of triggers --- db/zm_update-1.31.38.sql | 314 +-------------------------------------- 1 file changed, 1 insertion(+), 313 deletions(-) diff --git a/db/zm_update-1.31.38.sql b/db/zm_update-1.31.38.sql index c98586640..007b5d173 100644 --- a/db/zm_update-1.31.38.sql +++ b/db/zm_update-1.31.38.sql @@ -1,313 +1 @@ - -delimiter // -DROP TRIGGER IF EXISTS Events_Hour_delete_trigger// -CREATE TRIGGER Events_Hour_delete_trigger BEFORE DELETE ON Events_Hour -FOR EACH ROW BEGIN - UPDATE Monitors SET - HourEvents = COALESCE(HourEvents,1)-1, - HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) - WHERE Id=OLD.MonitorId; -END; -// - -DROP TRIGGER IF EXISTS Events_Hour_update_trigger// - -CREATE TRIGGER Events_Hour_update_trigger AFTER UPDATE ON Events_Hour -FOR EACH ROW - BEGIN - declare diff BIGINT default 0; - - set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); - IF ( diff ) THEN - IF ( NEW.MonitorID != OLD.MonitorID ) THEN - UPDATE Monitors SET HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) WHERE Monitors.Id=OLD.MonitorId; - UPDATE Monitors SET HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)-COALESCE(NEW.DiskSpace,0) WHERE Monitors.Id=NEW.MonitorId; - ELSE - UPDATE Monitors SET HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)+diff WHERE Monitors.Id=NEW.MonitorId; - END IF; - END IF; - END; -// -DELIMITER ; - -DROP TABLE IF EXISTS `Events_Day`; -CREATE TABLE `Events_Day` ( - `EventId` int(10) unsigned NOT NULL, - `MonitorId` int(10) unsigned NOT NULL, - `StartTime` datetime default NULL, - `DiskSpace` bigint unsigned default NULL, - PRIMARY KEY (`EventId`), - KEY `Events_Day_MonitorId_idx` (`MonitorId`), - KEY `Events_Day_StartTime_idx` (`StartTime`) -) ENGINE=@ZM_MYSQL_ENGINE@; - -delimiter // -DROP TRIGGER IF EXISTS Events_Day_delete_trigger// -CREATE TRIGGER Events_Day_delete_trigger BEFORE DELETE ON Events_Day -FOR EACH ROW BEGIN - UPDATE Monitors SET - DayEvents = COALESCE(DayEvents,1)-1, - DayEventDiskSpace=COALESCE(DayEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) - WHERE Id=OLD.MonitorId; -END; -// - -DROP TRIGGER IF EXISTS Events_Day_update_trigger; -CREATE TRIGGER Events_Day_update_trigger AFTER UPDATE ON Events_Day -FOR EACH ROW - BEGIN - declare diff BIGINT default 0; - - set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); - IF ( diff ) THEN - IF ( NEW.MonitorID != OLD.MonitorID ) THEN - UPDATE Monitors SET DayEventDiskSpace=COALESCE(DayEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) WHERE Monitors.Id=OLD.MonitorId; - UPDATE Monitors SET DayEventDiskSpace=COALESCE(DayEventDiskSpace,0)+COALESCE(NEW.DiskSpace,0) WHERE Monitors.Id=NEW.MonitorId; - ELSE - UPDATE Monitors SET DayEventDiskSpace=COALESCE(DayEventDiskSpace,0)+diff WHERE Monitors.Id=NEW.MonitorId; - END IF; - END IF; - END; - // - - -DELIMITER ; -DROP TABLE IF EXISTS `Events_Week`; -CREATE TABLE `Events_Week` ( - `EventId` int(10) unsigned NOT NULL, - `MonitorId` int(10) unsigned NOT NULL, - `StartTime` datetime default NULL, - `DiskSpace` bigint unsigned default NULL, - PRIMARY KEY (`EventId`), - KEY `Events_Week_MonitorId_idx` (`MonitorId`), - KEY `Events_Week_StartTime_idx` (`StartTime`) -) ENGINE=@ZM_MYSQL_ENGINE@; - -delimiter // -DROP TRIGGER IF EXISTS Events_Week_delete_trigger// -CREATE TRIGGER Events_Week_delete_trigger BEFORE DELETE ON Events_Week -FOR EACH ROW BEGIN - UPDATE Monitors SET - WeekEvents = COALESCE(WeekEvents,1)-1, - WeekEventDiskSpace=COALESCE(WeekEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) - WHERE Id=OLD.MonitorId; -END; -// - -DROP TRIGGER IF EXISTS Events_Week_update_trigger; -CREATE TRIGGER Events_Week_update_trigger AFTER UPDATE ON Events_Week -FOR EACH ROW - BEGIN - declare diff BIGINT default 0; - - set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); - IF ( diff ) THEN - IF ( NEW.MonitorID != OLD.MonitorID ) THEN - UPDATE Monitors SET WeekEventDiskSpace=COALESCE(WeekEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) WHERE Monitors.Id=OLD.MonitorId; - UPDATE Monitors SET WeekEventDiskSpace=COALESCE(WeekEventDiskSpace,0)+COALESCE(NEW.DiskSpace,0) WHERE Monitors.Id=NEW.MonitorId; - ELSE - UPDATE Monitors SET WeekEventDiskSpace=COALESCE(WeekEventDiskSpace,0)+diff WHERE Monitors.Id=NEW.MonitorId; - END IF; - END IF; - END; - // - -DELIMITER ; - -DROP TABLE IF EXISTS `Events_Month`; -CREATE TABLE `Events_Month` ( - `EventId` int(10) unsigned NOT NULL, - `MonitorId` int(10) unsigned NOT NULL, - `StartTime` datetime default NULL, - `DiskSpace` bigint unsigned default NULL, - PRIMARY KEY (`EventId`), - KEY `Events_Month_MonitorId_idx` (`MonitorId`), - KEY `Events_Month_StartTime_idx` (`StartTime`) -) ENGINE=@ZM_MYSQL_ENGINE@; - -delimiter // -DROP TRIGGER IF EXISTS Events_Month_delete_trigger// -CREATE TRIGGER Events_Month_delete_trigger BEFORE DELETE ON Events_Month -FOR EACH ROW BEGIN - UPDATE Monitors SET - MonthEvents = COALESCE(MonthEvents,1)-1, - MonthEventDiskSpace=COALESCE(MonthEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) - WHERE Id=OLD.MonitorId; -END; -// - - -DROP TRIGGER IF EXISTS Events_Month_update_trigger; -CREATE TRIGGER Events_Month_update_trigger AFTER UPDATE ON Events_Month -FOR EACH ROW - BEGIN - declare diff BIGINT default 0; - - set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); - IF ( diff ) THEN - IF ( NEW.MonitorID != OLD.MonitorID ) THEN - UPDATE Monitors SET MonthEventDiskSpace=COALESCE(MonthEventDiskSpace,0)-COALESCE(OLD.DiskSpace) WHERE Monitors.Id=OLD.MonitorId; - UPDATE Monitors SET MonthEventDiskSpace=COALESCE(MonthEventDiskSpace,0)+COALESCE(NEW.DiskSpace) WHERE Monitors.Id=NEW.MonitorId; - ELSE - UPDATE Monitors SET MonthEventDiskSpace=COALESCE(MonthEventDiskSpace,0)+diff WHERE Monitors.Id=NEW.MonitorId; - END IF; - END IF; - END; - // - - -DELIMITER ; - -DROP TABLE IF EXISTS `Events_Archived`; -CREATE TABLE `Events_Archived` ( - `EventId` int(10) unsigned NOT NULL, - `MonitorId` int(10) unsigned NOT NULL, - `DiskSpace` bigint unsigned default NULL, - PRIMARY KEY (`EventId`), - KEY `Events_Archived_MonitorId_idx` (`MonitorId`) -) ENGINE=@ZM_MYSQL_ENGINE@; - - -drop procedure if exists update_storage_stats; - -delimiter // - -create procedure update_storage_stats(IN StorageId smallint(5), IN space BIGINT) - -sql security invoker - -deterministic - -begin - - update Storage set DiskSpace = COALESCE(DiskSpace,0) + COALESCE(space,0) where Id = StorageId; - -end; - -// - -drop trigger if exists event_update_trigger// - -CREATE TRIGGER event_update_trigger AFTER UPDATE ON Events -FOR EACH ROW -BEGIN - declare diff BIGINT default 0; - - set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); - IF ( NEW.StorageId = OLD.StorageID ) THEN - IF ( diff ) THEN - call update_storage_stats(OLD.StorageId, diff); - END IF; - ELSE - IF ( NEW.DiskSpace ) THEN - call update_storage_stats(NEW.StorageId, NEW.DiskSpace); - END IF; - IF ( OLD.DiskSpace ) THEN - call update_storage_stats(OLD.StorageId, -OLD.DiskSpace); - END IF; - END IF; - - UPDATE Events_Hour SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; - UPDATE Events_Day SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; - UPDATE Events_Week SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; - UPDATE Events_Month SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; - - IF ( NEW.Archived != OLD.Archived ) THEN - IF ( NEW.Archived ) THEN - INSERT INTO Events_Archived (EventId,MonitorId,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.DiskSpace); - UPDATE Monitors SET ArchivedEvents = COALESCE(ArchivedEvents,0)+1, ArchivedEventDiskSpace = COALESCE(ArchivedEventDiskSpace,0) + COALESCE(NEW.DiskSpace,0) WHERE Id=NEW.MonitorId; - ELSEIF ( OLD.Archived ) THEN - DELETE FROM Events_Archived WHERE EventId=OLD.Id; - UPDATE Monitors SET ArchivedEvents = COALESCE(ArchivedEvents,0)-1, ArchivedEventDiskSpace = COALESCE(ArchivedEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0) WHERE Id=OLD.MonitorId; - ELSE - IF ( OLD.DiskSpace != NEW.DiskSpace ) THEN - UPDATE Events_Archived SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; - UPDATE Monitors SET - ArchivedEventDiskSpace = COALESCE(ArchivedEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0) + COALESCE(NEW.DiskSpace,0) - WHERE Id=OLD.MonitorId; - END IF; - END IF; - ELSE IF ( NEW.Archived AND diff ) THEN - UPDATE Events_Archived SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; - END IF; - - IF ( diff ) THEN - UPDATE Monitors SET TotalEventDiskSpace = COALESCE(TotalEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0) + COALESCE(NEW.DiskSpace,0) WHERE Id=OLD.MonitorId; - END IF; - -END; - -// - -delimiter ; - -DROP TRIGGER IF EXISTS event_insert_trigger; - -delimiter // -/* The assumption is that when an Event is inserted, it has no size yet, so don't bother updating the DiskSpace, just the count. - * The DiskSpace will get update in the Event Update Trigger - */ -CREATE TRIGGER event_insert_trigger AFTER INSERT ON Events -FOR EACH ROW - BEGIN - - INSERT INTO Events_Hour (EventId,MonitorId,StartTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartTime,0); - INSERT INTO Events_Day (EventId,MonitorId,StartTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartTime,0); - INSERT INTO Events_Week (EventId,MonitorId,StartTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartTime,0); - INSERT INTO Events_Month (EventId,MonitorId,StartTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartTime,0); - UPDATE Monitors SET - HourEvents = COALESCE(DayEvents,0)+1, - DayEvents = COALESCE(DayEvents,0)+1, - WeekEvents = COALESCE(DayEvents,0)+1, - MonthEvents = COALESCE(DayEvents,0)+1, - TotalEvents = COALESCE(TotalEvents,0)+1 - WHERE Id=NEW.MonitorId; -END; -// - -DROP TRIGGER IF EXISTS event_delete_trigger// - -CREATE TRIGGER event_delete_trigger BEFORE DELETE ON Events -FOR EACH ROW -BEGIN - IF ( OLD.DiskSpace ) THEN - call update_storage_stats(OLD.StorageId, -OLD.DiskSpace); - END IF; - DELETE FROM Events_Hour WHERE EventId=OLD.Id; - DELETE FROM Events_Day WHERE EventId=OLD.Id; - DELETE FROM Events_Week WHERE EventId=OLD.Id; - DELETE FROM Events_Month WHERE EventId=OLD.Id; - IF ( OLD.Archived ) THEN - DELETE FROM Events_Archived WHERE EventId=OLD.Id; - UPDATE Monitors SET - ArchivedEvents = COALESCE(ArchivedEvents,1) - 1, - ArchivedEventDiskSpace = COALESCE(ArchivedEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0), - TotalEvents = COALESCE(TotalEvents,1) - 1, - TotalEventDiskSpace = COALESCE(TotalEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0) - WHERE Id=OLD.MonitorId; - ELSE - UPDATE Monitors SET - TotalEvents = COALESCE(TotalEvents,1)-1, - TotalEventDiskSpace=COALESCE(TotalEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) - WHERE Id=OLD.MonitorId; - END IF; -END; - -// - -DROP TRIGGER IF EXISTS Zone_Insert_Trigger// -CREATE TRIGGER Zone_Insert_Trigger AFTER INSERT ON Zones -FOR EACH ROW - BEGIN - UPDATE Monitors SET ZoneCount=(SELECT COUNT(*) FROM Zones WHERE MonitorId=NEW.MonitorId) WHERE Id=NEW.MonitorID; - END -// -DROP TRIGGER IF EXISTS Zone_Delete_Trigger// -CREATE TRIGGER Zone_Delete_Trigger AFTER DELETE ON Zones -FOR EACH ROW - BEGIN - UPDATE Monitors SET ZoneCount=(SELECT COUNT(*) FROM Zones WHERE MonitorId=OLD.MonitorId) WHERE Id=OLD.MonitorID; - END -// - -DELIMITER ; +source triggers.sql From f3065bd8f6ba3cf7d3af8843fe3f4dad85b586a4 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 18 Feb 2018 10:59:36 -0500 Subject: [PATCH 0112/2339] Source doesn't really work --- db/zm_update-1.31.38.sql | 263 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 262 insertions(+), 1 deletion(-) diff --git a/db/zm_update-1.31.38.sql b/db/zm_update-1.31.38.sql index 007b5d173..be3f4fcee 100644 --- a/db/zm_update-1.31.38.sql +++ b/db/zm_update-1.31.38.sql @@ -1 +1,262 @@ -source triggers.sql + +delimiter // +DROP TRIGGER IF EXISTS Events_Hour_delete_trigger// +CREATE TRIGGER Events_Hour_delete_trigger BEFORE DELETE ON Events_Hour +FOR EACH ROW BEGIN + UPDATE Monitors SET + HourEvents = COALESCE(HourEvents,1)-1, + HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) + WHERE Id=OLD.MonitorId; +END; +// + +DROP TRIGGER IF EXISTS Events_Hour_update_trigger// + +CREATE TRIGGER Events_Hour_update_trigger AFTER UPDATE ON Events_Hour +FOR EACH ROW + BEGIN + declare diff BIGINT default 0; + + set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); + IF ( diff ) THEN + IF ( NEW.MonitorID != OLD.MonitorID ) THEN + UPDATE Monitors SET HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) WHERE Monitors.Id=OLD.MonitorId; + UPDATE Monitors SET HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)-COALESCE(NEW.DiskSpace,0) WHERE Monitors.Id=NEW.MonitorId; + ELSE + UPDATE Monitors SET HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)+diff WHERE Monitors.Id=NEW.MonitorId; + END IF; + END IF; + END; +// +DELIMITER ; + +delimiter // +DROP TRIGGER IF EXISTS Events_Day_delete_trigger// +CREATE TRIGGER Events_Day_delete_trigger BEFORE DELETE ON Events_Day +FOR EACH ROW BEGIN + UPDATE Monitors SET + DayEvents = COALESCE(DayEvents,1)-1, + DayEventDiskSpace=COALESCE(DayEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) + WHERE Id=OLD.MonitorId; +END; +// + +DROP TRIGGER IF EXISTS Events_Day_update_trigger; +CREATE TRIGGER Events_Day_update_trigger AFTER UPDATE ON Events_Day +FOR EACH ROW + BEGIN + declare diff BIGINT default 0; + + set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); + IF ( diff ) THEN + IF ( NEW.MonitorID != OLD.MonitorID ) THEN + UPDATE Monitors SET DayEventDiskSpace=COALESCE(DayEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) WHERE Monitors.Id=OLD.MonitorId; + UPDATE Monitors SET DayEventDiskSpace=COALESCE(DayEventDiskSpace,0)+COALESCE(NEW.DiskSpace,0) WHERE Monitors.Id=NEW.MonitorId; + ELSE + UPDATE Monitors SET DayEventDiskSpace=COALESCE(DayEventDiskSpace,0)+diff WHERE Monitors.Id=NEW.MonitorId; + END IF; + END IF; + END; + // + + +delimiter // +DROP TRIGGER IF EXISTS Events_Week_delete_trigger// +CREATE TRIGGER Events_Week_delete_trigger BEFORE DELETE ON Events_Week +FOR EACH ROW BEGIN + UPDATE Monitors SET + WeekEvents = COALESCE(WeekEvents,1)-1, + WeekEventDiskSpace=COALESCE(WeekEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) + WHERE Id=OLD.MonitorId; +END; +// + +DROP TRIGGER IF EXISTS Events_Week_update_trigger; +CREATE TRIGGER Events_Week_update_trigger AFTER UPDATE ON Events_Week +FOR EACH ROW + BEGIN + declare diff BIGINT default 0; + + set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); + IF ( diff ) THEN + IF ( NEW.MonitorID != OLD.MonitorID ) THEN + UPDATE Monitors SET WeekEventDiskSpace=COALESCE(WeekEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) WHERE Monitors.Id=OLD.MonitorId; + UPDATE Monitors SET WeekEventDiskSpace=COALESCE(WeekEventDiskSpace,0)+COALESCE(NEW.DiskSpace,0) WHERE Monitors.Id=NEW.MonitorId; + ELSE + UPDATE Monitors SET WeekEventDiskSpace=COALESCE(WeekEventDiskSpace,0)+diff WHERE Monitors.Id=NEW.MonitorId; + END IF; + END IF; + END; + // + +DELIMITER ; + +delimiter // +DROP TRIGGER IF EXISTS Events_Month_delete_trigger// +CREATE TRIGGER Events_Month_delete_trigger BEFORE DELETE ON Events_Month +FOR EACH ROW BEGIN + UPDATE Monitors SET + MonthEvents = COALESCE(MonthEvents,1)-1, + MonthEventDiskSpace=COALESCE(MonthEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) + WHERE Id=OLD.MonitorId; +END; +// + +DROP TRIGGER IF EXISTS Events_Month_update_trigger; +CREATE TRIGGER Events_Month_update_trigger AFTER UPDATE ON Events_Month +FOR EACH ROW + BEGIN + declare diff BIGINT default 0; + + set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); + IF ( diff ) THEN + IF ( NEW.MonitorID != OLD.MonitorID ) THEN + UPDATE Monitors SET MonthEventDiskSpace=COALESCE(MonthEventDiskSpace,0)-COALESCE(OLD.DiskSpace) WHERE Monitors.Id=OLD.MonitorId; + UPDATE Monitors SET MonthEventDiskSpace=COALESCE(MonthEventDiskSpace,0)+COALESCE(NEW.DiskSpace) WHERE Monitors.Id=NEW.MonitorId; + ELSE + UPDATE Monitors SET MonthEventDiskSpace=COALESCE(MonthEventDiskSpace,0)+diff WHERE Monitors.Id=NEW.MonitorId; + END IF; + END IF; + END; + // + +drop procedure if exists update_storage_stats; +create procedure update_storage_stats(IN StorageId smallint(5), IN space BIGINT) + +sql security invoker + +deterministic + +begin + + update Storage set DiskSpace = COALESCE(DiskSpace,0) + COALESCE(space,0) where Id = StorageId; + +end; + +// + +drop trigger if exists event_update_trigger// + +CREATE TRIGGER event_update_trigger AFTER UPDATE ON Events +FOR EACH ROW +BEGIN + declare diff BIGINT default 0; + + set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); + IF ( NEW.StorageId = OLD.StorageID ) THEN + IF ( diff ) THEN + call update_storage_stats(OLD.StorageId, diff); + END IF; + ELSE + IF ( NEW.DiskSpace ) THEN + call update_storage_stats(NEW.StorageId, NEW.DiskSpace); + END IF; + IF ( OLD.DiskSpace ) THEN + call update_storage_stats(OLD.StorageId, -OLD.DiskSpace); + END IF; + END IF; + + UPDATE Events_Hour SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; + UPDATE Events_Day SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; + UPDATE Events_Week SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; + UPDATE Events_Month SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; + + IF ( NEW.Archived != OLD.Archived ) THEN + IF ( NEW.Archived ) THEN + INSERT INTO Events_Archived (EventId,MonitorId,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.DiskSpace); + UPDATE Monitors SET ArchivedEvents = COALESCE(ArchivedEvents,0)+1, ArchivedEventDiskSpace = COALESCE(ArchivedEventDiskSpace,0) + COALESCE(NEW.DiskSpace,0) WHERE Id=NEW.MonitorId; + ELSEIF ( OLD.Archived ) THEN + DELETE FROM Events_Archived WHERE EventId=OLD.Id; + UPDATE Monitors SET ArchivedEvents = COALESCE(ArchivedEvents,0)-1, ArchivedEventDiskSpace = COALESCE(ArchivedEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0) WHERE Id=OLD.MonitorId; + ELSE + IF ( OLD.DiskSpace != NEW.DiskSpace ) THEN + UPDATE Events_Archived SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; + UPDATE Monitors SET + ArchivedEventDiskSpace = COALESCE(ArchivedEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0) + COALESCE(NEW.DiskSpace,0) + WHERE Id=OLD.MonitorId; + END IF; + END IF; + ELSE IF ( NEW.Archived AND diff ) THEN + UPDATE Events_Archived SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; + END IF; + + IF ( diff ) THEN + UPDATE Monitors SET TotalEventDiskSpace = COALESCE(TotalEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0) + COALESCE(NEW.DiskSpace,0) WHERE Id=OLD.MonitorId; + END IF; + +END; + +// + +delimiter ; + +DROP TRIGGER IF EXISTS event_insert_trigger; + +delimiter // +/* The assumption is that when an Event is inserted, it has no size yet, so don't bother updating the DiskSpace, just the count. + * The DiskSpace will get update in the Event Update Trigger + */ +CREATE TRIGGER event_insert_trigger AFTER INSERT ON Events +FOR EACH ROW + BEGIN + + INSERT INTO Events_Hour (EventId,MonitorId,StartTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartTime,0); + INSERT INTO Events_Day (EventId,MonitorId,StartTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartTime,0); + INSERT INTO Events_Week (EventId,MonitorId,StartTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartTime,0); + INSERT INTO Events_Month (EventId,MonitorId,StartTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartTime,0); + UPDATE Monitors SET + HourEvents = COALESCE(DayEvents,0)+1, + DayEvents = COALESCE(DayEvents,0)+1, + WeekEvents = COALESCE(DayEvents,0)+1, + MonthEvents = COALESCE(DayEvents,0)+1, + TotalEvents = COALESCE(TotalEvents,0)+1 + WHERE Id=NEW.MonitorId; +END; +// + +DROP TRIGGER IF EXISTS event_delete_trigger// + +CREATE TRIGGER event_delete_trigger BEFORE DELETE ON Events +FOR EACH ROW +BEGIN + IF ( OLD.DiskSpace ) THEN + call update_storage_stats(OLD.StorageId, -OLD.DiskSpace); + END IF; + DELETE FROM Events_Hour WHERE EventId=OLD.Id; + DELETE FROM Events_Day WHERE EventId=OLD.Id; + DELETE FROM Events_Week WHERE EventId=OLD.Id; + DELETE FROM Events_Month WHERE EventId=OLD.Id; + IF ( OLD.Archived ) THEN + DELETE FROM Events_Archived WHERE EventId=OLD.Id; + UPDATE Monitors SET + ArchivedEvents = COALESCE(ArchivedEvents,1) - 1, + ArchivedEventDiskSpace = COALESCE(ArchivedEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0), + TotalEvents = COALESCE(TotalEvents,1) - 1, + TotalEventDiskSpace = COALESCE(TotalEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0) + WHERE Id=OLD.MonitorId; + ELSE + UPDATE Monitors SET + TotalEvents = COALESCE(TotalEvents,1)-1, + TotalEventDiskSpace=COALESCE(TotalEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0) + WHERE Id=OLD.MonitorId; + END IF; +END; + +// + +DROP TRIGGER IF EXISTS Zone_Insert_Trigger// +CREATE TRIGGER Zone_Insert_Trigger AFTER INSERT ON Zones +FOR EACH ROW + BEGIN + UPDATE Monitors SET ZoneCount=(SELECT COUNT(*) FROM Zones WHERE MonitorId=NEW.MonitorId) WHERE Id=NEW.MonitorID; + END +// +DROP TRIGGER IF EXISTS Zone_Delete_Trigger// +CREATE TRIGGER Zone_Delete_Trigger AFTER DELETE ON Zones +FOR EACH ROW + BEGIN + UPDATE Monitors SET ZoneCount=(SELECT COUNT(*) FROM Zones WHERE MonitorId=OLD.MonitorId) WHERE Id=OLD.MonitorID; + END +// + +DELIMITER ; From 65f3a9b9167029dff4f26e7abab89afa1e0df17d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 22 Feb 2018 09:34:50 -0500 Subject: [PATCH 0113/2339] try crf instead of preset ultrafast --- src/zm_videostore.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 7eb434141..7943046fc 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -277,7 +277,8 @@ Debug(2,"Using mjpeg"); if ( video_out_ctx->codec_id == AV_CODEC_ID_H264 ) { video_out_ctx->max_b_frames = 1; if ( video_out_ctx->priv_data ) { - av_opt_set(video_out_ctx->priv_data, "preset", "ultrafast", 0); + av_opt_set(video_out_ctx->priv_data, "crf", "1", AV_OPT_SEARCH_CHILDREN); + //av_opt_set(video_out_ctx->priv_data, "preset", "ultrafast", 0); } else { Debug(2, "Not setting priv_data"); } From 84b42ef4d7ecfb262c620dc13dc66b8dd82d0ad5 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 22 Feb 2018 11:43:04 -0500 Subject: [PATCH 0114/2339] workarouns for omx --- src/zm_event.cpp | 1 + src/zm_local_camera.cpp | 1 + src/zm_videostore.cpp | 25 ++++++++++++++++--------- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index e275fa963..da23288ad 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -465,6 +465,7 @@ void Event::AddPacket( ZMPacket *packet, int score, Image *alarm_image ) { have_video_keyframe = have_video_keyframe || ( ( packet->codec_type == AVMEDIA_TYPE_VIDEO ) && packet->keyframe ); if ( videoStore ) { if ( have_video_keyframe ) { + Debug(2,"Have video keyframe, writing packet to videostore"); videoStore->writePacket( packet ); } else { Debug(2, "No video keyframe yet, not writing"); diff --git a/src/zm_local_camera.cpp b/src/zm_local_camera.cpp index c8a653b14..d75c9b854 100644 --- a/src/zm_local_camera.cpp +++ b/src/zm_local_camera.cpp @@ -2135,6 +2135,7 @@ AVStream *LocalCamera::get_VideoStream() { AVFormatContext *oc = avformat_alloc_context(); video_stream = avformat_new_stream( oc, NULL ); if ( video_stream ) { + video_stream->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) video_stream->codecpar->width = width; video_stream->codecpar->height = height; diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 7943046fc..253eb500a 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -200,6 +200,7 @@ Debug(2,"Using mjpeg"); } video_out_ctx->pix_fmt = pf; + video_out_ctx->level = 32; } else { Error("Unsupported output codec selected"); @@ -268,16 +269,20 @@ Debug(2,"Using mjpeg"); } /* video time_base can be set to whatever is handy and supported by encoder */ - video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate - video_out_ctx->gop_size = 12; - video_out_ctx->qmin = 10; - video_out_ctx->qmax = 51; - video_out_ctx->qcompress = 0.6; - //video_out_ctx->bit_rate = 4000000; + //video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate + video_out_ctx->time_base = (AVRational){1, 30}; // microseconds as base frame rate + video_out_ctx->framerate = (AVRational){30,1}; + //video_out_ctx->gop_size = 12; + //video_out_ctx->qmin = 10; + //video_out_ctx->qmax = 51; + //video_out_ctx->qcompress = 0.6; + video_out_ctx->bit_rate = 400*1024; + video_out_ctx->thread_count = 0; + if ( video_out_ctx->codec_id == AV_CODEC_ID_H264 ) { video_out_ctx->max_b_frames = 1; if ( video_out_ctx->priv_data ) { - av_opt_set(video_out_ctx->priv_data, "crf", "1", AV_OPT_SEARCH_CHILDREN); + av_opt_set(video_out_ctx->priv_data, "crf", "1", AV_OPT_SEARCH_CHILDREN); //av_opt_set(video_out_ctx->priv_data, "preset", "ultrafast", 0); } else { Debug(2, "Not setting priv_data"); @@ -1027,8 +1032,9 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { zm_packet->out_frame->pts = 0; zm_packet->out_frame->coded_picture_number = 0; } else { - uint64_t seconds = zm_packet->timestamp->tv_sec*(uint64_t)1000000; - zm_packet->out_frame->pts = ( seconds + zm_packet->timestamp->tv_usec ) - video_start_pts; + uint64_t seconds = ( zm_packet->timestamp->tv_sec*(uint64_t)1000000 + zm_packet->timestamp->tv_usec ) - video_start_pts; + zm_packet->out_frame->pts = av_rescale_q( seconds, video_in_stream->time_base, video_out_ctx->time_base); + //zm_packet->out_frame->pkt_duration = zm_packet->out_frame->pts - video_start_pts; Debug(2, " Setting pts for frame(%d), set to (%" PRId64 ") from (start %" PRIu64 " - %" PRIu64 " - secs(%d) usecs(%d)", frame_count, zm_packet->out_frame->pts, video_start_pts, seconds, zm_packet->timestamp->tv_sec, zm_packet->timestamp->tv_usec ); @@ -1044,6 +1050,7 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) // Do this to allow the encoder to choose whether to use I/P/B frame zm_packet->out_frame->pict_type = AV_PICTURE_TYPE_NONE; + Debug(4, "Sending frame"); if ( (ret = avcodec_send_frame(video_out_ctx, zm_packet->out_frame)) < 0 ) { Error("Could not send frame (error '%s')", av_make_error_string(ret).c_str()); return -1; From 90a668325ef2fe4d2e9267c5c1cedced066e5440 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 22 Feb 2018 11:56:37 -0500 Subject: [PATCH 0115/2339] add mmal decoding --- src/zm_ffmpeg_camera.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 052f35b4c..6f4ba9f94 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -346,6 +346,13 @@ int FfmpegCamera::OpenFfmpeg() { } } // end if h264 #endif + if ( mVideoCodecContext->codec_id == AV_CODEC_ID_H264 ) { + if ( (mVideoCodec = avcodec_find_decoder_by_name("h264_mmal")) == NULL ) { + Debug(1, "Failed to find decoder (h264_mmal)" ); + } else { + Debug(1, "Success finding decoder (h264_mmal)" ); + } + } if ( (!mVideoCodec) and ( (mVideoCodec = avcodec_find_decoder(mVideoCodecContext->codec_id)) == NULL ) ) { // Try and get the codec from the codec context From f00983b450a8b7f8667f75f65bcf6316a3f39e72 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 27 Feb 2018 20:19:39 -0500 Subject: [PATCH 0116/2339] Don't setup snap and timestamp if it's an audio packet --- src/zm_monitor.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index e6519acd4..5ce02bbd7 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1273,17 +1273,19 @@ bool Monitor::Analyse() { Debug(2, "Analysis index (%d), last_Write(%d)", index, shared_data->last_write_index); packets_processed += 1; - struct timeval *timestamp = snap->timestamp; - Image *snap_image = snap->image; if ( snap->image_index == -1 ) { snap->unlock(); Debug(2, "skipping because audio"); + // We want to skip, but if we return, we may sleep. + // if ( ! packetqueue->increment_analysis_it() ) { Debug(2, "No more packets to analyse"); return false; } continue; } + struct timeval *timestamp = snap->timestamp; + Image *snap_image = snap->image; // signal is set by capture bool signal = shared_data->signal; @@ -2831,6 +2833,7 @@ int Monitor::Capture() { return 0; } } else { + Debug(4, "Capturing"); captureResult = camera->Capture(*packet); gettimeofday( packet->timestamp, NULL ); if ( captureResult < 0 ) { From c443168389467f2cec636a6b3fe190c025e6483b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 28 Feb 2018 07:17:16 -0800 Subject: [PATCH 0117/2339] split out codec and encoder, allowing one to specify which encoder to use --- db/zm_create.sql.in | 3 +- db/zm_update-1.31.38.sql | 7 +- src/zm_event.cpp | 2 +- src/zm_monitor.cpp | 32 +- src/zm_monitor.h | 9 +- src/zm_videostore.cpp | 2006 +++++++++++++-------------- src/zm_videostore.h | 9 + version | 2 +- web/includes/Monitor.php | 3 +- web/skins/classic/views/monitor.php | 14 +- 10 files changed, 1036 insertions(+), 1051 deletions(-) diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index b50c5934b..0431456ea 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -710,7 +710,8 @@ CREATE TABLE `Monitors` ( `Deinterlacing` int(10) unsigned NOT NULL default '0', `SaveJPEGs` TINYINT NOT NULL DEFAULT '3' , `VideoWriter` TINYINT NOT NULL DEFAULT '0', - `OutputCodec` enum('h264','mjpeg','mpeg1','mpeg2'), + `OutputCodec` int(10) unsigned NOT NULL default 0, + `Encoder` enum('auto','h264','h264_omx','mjpeg','mpeg1','mpeg2'), `OutputContainer` enum('auto','mp4','mkv'), `EncoderParameters` TEXT, `RecordAudio` TINYINT NOT NULL DEFAULT '0', diff --git a/db/zm_update-1.31.38.sql b/db/zm_update-1.31.38.sql index 0ca0be6ea..12fd3e96d 100644 --- a/db/zm_update-1.31.38.sql +++ b/db/zm_update-1.31.38.sql @@ -176,8 +176,10 @@ BEGIN WHERE Id=OLD.MonitorId; END IF; END IF; - ELSEIF ( NEW.Archived AND diff ) THEN - UPDATE Events_Archived SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; + ELSE + IF ( NEW.Archived AND diff ) THEN + UPDATE Events_Archived SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; + END IF; END IF; IF ( diff ) THEN @@ -185,7 +187,6 @@ BEGIN END IF; END; - // delimiter ; diff --git a/src/zm_event.cpp b/src/zm_event.cpp index da23288ad..cd7360ace 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -190,7 +190,7 @@ Event::Event( if ( monitor->GetOptVideoWriter() != 0 ) { std::string container = monitor->OutputContainer(); if ( container == "auto" || container == "" ) { - if ( monitor->OutputCodec() == "h264" ) { + if ( monitor->OutputCodec() == AV_CODEC_ID_H264 ) { container = "mp4"; } else { container = "mkv"; diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index e6519acd4..1ae4425c0 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -249,7 +249,8 @@ Monitor::Monitor( int p_colours, VideoWriter p_videowriter, std::string &p_encoderparams, - std::string &p_output_codec, + int p_output_codec, + std::string &p_encoder, std::string &p_output_container, bool p_record_audio, const char *p_event_prefix, @@ -292,6 +293,7 @@ Monitor::Monitor( videowriter( p_videowriter ), encoderparams( p_encoderparams ), output_codec( p_output_codec ), + encoder( p_encoder ), output_container( p_output_container ), record_audio( p_record_audio ), label_coord( p_label_coord ), @@ -1761,7 +1763,7 @@ void Monitor::ReloadLinkedMonitors( const char *p_linked_monitors ) { #if ZM_HAS_V4L int Monitor::LoadLocalMonitors( const char *device, Monitor **&monitors, Purpose purpose ) { - std::string sql = "select Id, Name, ServerId, StorageId, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, Method, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, OutputCodec, OutputContainer, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour, Exif from Monitors where Function != 'None' and Type = 'Local'"; + std::string sql = "select Id, Name, ServerId, StorageId, Function+0, Enabled, LinkedMonitors, Device, Channel, Format, V4LMultiBuffer, V4LCapturesPerFrame, Method, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, OutputCodec, Encoder, OutputContainer, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour, Exif from Monitors where Function != 'None' and Type = 'Local'"; ; if ( device[0] ) { sql += " AND Device='"; @@ -1826,7 +1828,8 @@ int Monitor::LoadLocalMonitors( const char *device, Monitor **&monitors, Purpose int savejpegs = atoi(dbrow[col]); col++; VideoWriter videowriter = (VideoWriter)atoi(dbrow[col]); col++; std::string encoderparams = dbrow[col] ? dbrow[col] : ""; col++; - std::string output_codec = dbrow[col] ? dbrow[col] : ""; col++; + int output_codec = dbrow[col] ? atoi(dbrow[col]) : 0; col++; + std::string encoder = dbrow[col] ? dbrow[col] : ""; col++; std::string output_container = dbrow[col] ? dbrow[col] : ""; col++; bool record_audio = (*dbrow[col] != '0'); col++; @@ -1907,6 +1910,7 @@ int Monitor::LoadLocalMonitors( const char *device, Monitor **&monitors, Purpose videowriter, encoderparams, output_codec, + encoder, output_container, record_audio, event_prefix, @@ -1955,7 +1959,7 @@ int Monitor::LoadLocalMonitors( const char *device, Monitor **&monitors, Purpose #endif // ZM_HAS_V4L int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const char *port, const char *path, Monitor **&monitors, Purpose purpose ) { - std::string sql = "select Id, Name, ServerId, StorageId, Function+0, Enabled, LinkedMonitors, Protocol, Method, Host, Port, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, RTSPDescribe, SaveJPEGs, VideoWriter, EncoderParameters, OutputCodec, OutputContainer, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'Remote'"; + std::string sql = "select Id, Name, ServerId, StorageId, Function+0, Enabled, LinkedMonitors, Protocol, Method, Host, Port, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, RTSPDescribe, SaveJPEGs, VideoWriter, EncoderParameters, OutputCodec, Encoder, OutputContainer, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'Remote'"; if ( staticConfig.SERVER_ID ) { sql += stringtf( " AND ServerId=%d", staticConfig.SERVER_ID ); } @@ -2001,7 +2005,8 @@ int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const c int savejpegs = atoi(dbrow[col]); col++; VideoWriter videowriter = (VideoWriter)atoi(dbrow[col]); col++; std::string encoderparams = dbrow[col] ? dbrow[col] : ""; col++; - std::string output_codec = dbrow[col] ? dbrow[col] : ""; col++; + int output_codec = dbrow[col] ? atoi(dbrow[col]) : 0; col++; + std::string encoder = dbrow[col] ? dbrow[col] : ""; col++; std::string output_container = dbrow[col] ? dbrow[col] : ""; col++; bool record_audio = (*dbrow[col] != '0'); col++; @@ -2096,6 +2101,7 @@ int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const c videowriter, encoderparams, output_codec, + encoder, output_container, record_audio, event_prefix, @@ -2143,7 +2149,7 @@ int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const c } int Monitor::LoadFileMonitors( const char *file, Monitor **&monitors, Purpose purpose ) { - std::string sql = "select Id, Name, ServerId, StorageId, Function+0, Enabled, LinkedMonitors, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, OutputCodec, OutputContainer, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'File'"; + std::string sql = "select Id, Name, ServerId, StorageId, Function+0, Enabled, LinkedMonitors, Path, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, OutputCodec, Encoder, OutputContainer, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'File'"; if ( file[0] ) { sql += " AND Path='"; sql += file; @@ -2185,7 +2191,8 @@ int Monitor::LoadFileMonitors( const char *file, Monitor **&monitors, Purpose pu int savejpegs = atoi(dbrow[col]); col++; VideoWriter videowriter = (VideoWriter)atoi(dbrow[col]); col++; std::string encoderparams = dbrow[col]; col++; - std::string output_codec = dbrow[col]; col++; + int output_codec = dbrow[col] ? atoi(dbrow[col]) : 0; col++; + std::string encoder = dbrow[col]; col++; std::string output_container = dbrow[col]; col++; bool record_audio = (*dbrow[col] != '0'); col++; @@ -2250,6 +2257,7 @@ int Monitor::LoadFileMonitors( const char *file, Monitor **&monitors, Purpose pu videowriter, encoderparams, output_codec, + encoder, output_container, record_audio, event_prefix, @@ -2298,7 +2306,7 @@ int Monitor::LoadFileMonitors( const char *file, Monitor **&monitors, Purpose pu #if HAVE_LIBAVFORMAT int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose purpose ) { - std::string sql = "select Id, Name, ServerId, StorageId, Function+0, Enabled, LinkedMonitors, Path, Method, Options, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, OutputCodec, OutputContainer, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'Ffmpeg'"; + std::string sql = "select Id, Name, ServerId, StorageId, Function+0, Enabled, LinkedMonitors, Path, Method, Options, Width, Height, Colours, Palette, Orientation+0, Deinterlacing, SaveJPEGs, VideoWriter, EncoderParameters, OutputCodec, Encoder, OutputContainer, RecordAudio, Brightness, Contrast, Hue, Colour, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, ImageBufferCount, WarmupCount, PreEventCount, PostEventCount, StreamReplayBuffer, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, Exif from Monitors where Function != 'None' and Type = 'Ffmpeg'"; if ( file[0] ) { sql += " AND Path = '"; sql += file; @@ -2343,7 +2351,8 @@ int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose int savejpegs = atoi(dbrow[col]); col++; VideoWriter videowriter = (VideoWriter)atoi(dbrow[col]); col++; std::string encoderparams = dbrow[col] ? dbrow[col] : ""; col++; - std::string output_codec = dbrow[col] ? dbrow[col] : ""; col++; + int output_codec = dbrow[col] ? atoi(dbrow[col]) : 0; col++; + std::string encoder = dbrow[col] ? dbrow[col] : ""; col++; std::string output_container = dbrow[col] ? dbrow[col] : ""; col++; bool record_audio = (*dbrow[col] != '0'); col++; @@ -2414,6 +2423,7 @@ int Monitor::LoadFfmpegMonitors( const char *file, Monitor **&monitors, Purpose videowriter, encoderparams, output_codec, + encoder, output_container, record_audio, event_prefix, @@ -2524,7 +2534,8 @@ Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) { int savejpegs = atoi(dbrow[col]); col++; VideoWriter videowriter = (VideoWriter)atoi(dbrow[col]); col++; std::string encoderparams = dbrow[col] ? dbrow[col] : ""; col++; - std::string output_codec = dbrow[col] ? dbrow[col] : ""; col++; + int output_codec = dbrow[col] ? atoi(dbrow[col]) : 0; col++; + std::string encoder = dbrow[col] ? dbrow[col] : ""; col++; std::string output_container = dbrow[col] ? dbrow[col] : ""; col++; bool record_audio = (*dbrow[col] != '0'); col++; @@ -2746,6 +2757,7 @@ Monitor *Monitor::Load( unsigned int p_id, bool load_zones, Purpose purpose ) { videowriter, encoderparams, output_codec, + encoder, output_container, record_audio, event_prefix, diff --git a/src/zm_monitor.h b/src/zm_monitor.h index d35d8e30d..acb76fda9 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -239,7 +239,8 @@ protected: int colours; VideoWriter videowriter; std::string encoderparams; - std::string output_codec; + int output_codec; + std::string encoder; std::string output_container; std::vector encoderparamsvec; _AVPIXELFORMAT imagePixFormat; @@ -359,7 +360,8 @@ public: int p_colours, VideoWriter p_videowriter, std::string &p_encoderparams, - std::string &p_output_codec, + int p_output_codec, + std::string &p_encoder, std::string &p_output_container, bool p_record_audio, const char *p_event_prefix, @@ -458,7 +460,8 @@ public: VideoWriter GetOptVideoWriter() const { return( videowriter ); } const std::vector* GetOptEncoderParams() const { return( &encoderparamsvec ); } const std::string &GetEncoderOptions() const { return( encoderparams ); } - const std::string &OutputCodec() const { return output_codec; } + const std::string &Encoder() const { return encoder; } + const int OutputCodec() const { return output_codec; } const std::string &OutputContainer() const { return output_container; } uint32_t GetVideoWriterEventId() const { return video_store_data->current_event; } diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 253eb500a..8f099ae0c 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -31,6 +31,13 @@ extern "C" { #include "libavutil/time.h" } +VideoStore::CodecData VideoStore::codec_data[] = { + { AV_CODEC_ID_H264, "h264", "h264_omx", AV_PIX_FMT_YUV420P }, + { AV_CODEC_ID_H264, "h264", "h264", AV_PIX_FMT_YUV420P }, + { AV_CODEC_ID_H264, "h264", "libx264", AV_PIX_FMT_YUV420P }, + { AV_CODEC_ID_MJPEG, "mjpeg", "mjpeg", AV_PIX_FMT_YUVJ422P }, +}; + VideoStore::VideoStore( const char *filename_in, const char *format_in, @@ -140,95 +147,34 @@ bool VideoStore::open() { video_in_stream_index = 0; } - if ( monitor->OutputCodec() == "mjpeg" ) { -Debug(2,"Using mjpeg"); - video_out_codec = avcodec_find_encoder_by_name("mjpeg"); - if ( ! video_out_codec ) { - Debug(1, "Didn't find mjpeg encoder"); - video_out_codec = avcodec_find_encoder(AV_CODEC_ID_MJPEG); - } - video_out_ctx = avcodec_alloc_context3( video_out_codec ); - video_out_ctx->codec_id = video_out_codec->id; - video_out_ctx->pix_fmt = AV_PIX_FMT_YUVJ422P; - - } else if ( monitor->OutputCodec() == "h264" || monitor->OutputCodec() == "" ) { - AVPixelFormat pf = AV_PIX_FMT_YUV420P; - - // First try hardware accell - video_out_codec = avcodec_find_encoder_by_name("h264_omx"); - if ( ! video_out_codec ) { - Debug(1, "Didn't find omx"); - video_out_codec = avcodec_find_encoder(AV_CODEC_ID_H264); - } - if ( ! video_out_codec ) { - if ( AV_CODEC_ID_NONE == -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - video_in_stream->codecpar->codec_id -#else - video_in_stream->codec->codec_id + video_out_ctx = avcodec_alloc_context3(NULL); + if ( oc->oformat->flags & AVFMT_GLOBALHEADER ) { +#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) + video_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; +#else + video_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; #endif - ) { - Debug(1, "trying xh264rgb"); - // We will be encoding rgb images, so prefer - video_out_codec = avcodec_find_encoder_by_name("libx264rgb"); - if ( ! video_out_codec ) { - video_out_codec = avcodec_find_encoder_by_name("libx264"); - } else { - pf = -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - (AVPixelFormat)video_in_stream->codecpar->format; -#else - video_in_stream->codec->pix_fmt; -#endif - } - } else { - video_out_codec = avcodec_find_encoder_by_name("libx264"); - pf = AV_PIX_FMT_YUV420P; - } - } - // Need to do lookup by codec_id - if ( ! video_out_codec ) { - Error("Didn't find h264 encoder"); - video_out_codec = NULL; - return false; - } - Debug(1, "Using %s for codec", video_out_codec->name); - video_out_ctx = avcodec_alloc_context3(video_out_codec); - if ( AV_CODEC_ID_H264 != video_out_ctx->codec_id ) { - Warning("Have to set codec_id?"); - video_out_ctx->codec_id = AV_CODEC_ID_H264; - } - - video_out_ctx->pix_fmt = pf; - video_out_ctx->level = 32; - - } else { - Error("Unsupported output codec selected"); - return false; + } + int wanted_codec = monitor->OutputCodec(); + if ( ! wanted_codec ) { + // default to h264 + wanted_codec = AV_CODEC_ID_H264; } - // Copy params from instream to ctx // // FIXME SHould check that we are set to passthrough - if ( video_in_stream && ( video_in_ctx->codec_id == AV_CODEC_ID_H264 ) ) { + if ( video_in_stream && ( video_in_ctx->codec_id == wanted_codec ) ) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) ret = avcodec_parameters_to_context(video_out_ctx, video_in_stream->codecpar); #else ret = avcodec_copy_context( video_out_ctx, video_in_ctx ); #endif + // Copy params from instream to ctx if ( ret < 0 ) { Error("Could not initialize ctx parameteres"); return false; } //video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate video_out_ctx->time_base = video_in_ctx->time_base; - - if ( oc->oformat->flags & AVFMT_GLOBALHEADER ) { -#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) - video_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; -#else - video_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; -#endif - } // Fix deprecated formats switch ( video_out_ctx->pix_fmt ) { case AV_PIX_FMT_YUVJ422P : @@ -243,128 +189,9 @@ Debug(2,"Using mjpeg"); case AV_PIX_FMT_NONE : case AV_PIX_FMT_YUVJ420P : default: - video_out_ctx->pix_fmt = AV_PIX_FMT_YUV420P; + video_out_ctx->pix_fmt = AV_PIX_FMT_YUV420P; break; } - zm_dump_codec(video_out_ctx); - - } else { - - /** Create a new frame to store the */ - if ( !(video_in_frame = zm_av_frame_alloc()) ) { - Error("Could not allocate video_in frame"); - return false; - } - // Don't have an input stream, so need to tell it what we are sending it, or are transcoding - video_out_ctx->width = monitor->Width(); - video_out_ctx->height = monitor->Height(); - video_out_ctx->codec_type = AVMEDIA_TYPE_VIDEO; - - if ( oc->oformat->flags & AVFMT_GLOBALHEADER ) { -#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) - video_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; -#else - video_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; -#endif - } - - /* video time_base can be set to whatever is handy and supported by encoder */ - //video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate - video_out_ctx->time_base = (AVRational){1, 30}; // microseconds as base frame rate - video_out_ctx->framerate = (AVRational){30,1}; - //video_out_ctx->gop_size = 12; - //video_out_ctx->qmin = 10; - //video_out_ctx->qmax = 51; - //video_out_ctx->qcompress = 0.6; - video_out_ctx->bit_rate = 400*1024; - video_out_ctx->thread_count = 0; - - if ( video_out_ctx->codec_id == AV_CODEC_ID_H264 ) { - video_out_ctx->max_b_frames = 1; - if ( video_out_ctx->priv_data ) { - av_opt_set(video_out_ctx->priv_data, "crf", "1", AV_OPT_SEARCH_CHILDREN); - //av_opt_set(video_out_ctx->priv_data, "preset", "ultrafast", 0); - } else { - Debug(2, "Not setting priv_data"); - } - } else if (video_out_ctx->codec_id == AV_CODEC_ID_MPEG2VIDEO) { - /* just for testing, we also add B frames */ - video_out_ctx->max_b_frames = 2; - } else if (video_out_ctx->codec_id == AV_CODEC_ID_MPEG1VIDEO) { - /* Needed to avoid using macroblocks in which some coeffs overflow. - * This does not happen with normal video, it just happens here as - * the motion of the chroma plane does not match the luma plane. */ - video_out_ctx->mb_decision = 2; - } - - AVDictionary *opts = 0; - std::string Options = monitor->GetEncoderOptions(); - ret = av_dict_parse_string(&opts, Options.c_str(), "=", ",#\n", 0); - if ( ret < 0 ) { - Warning("Could not parse ffmpeg encoder options list '%s'\n", Options.c_str()); - } else { - AVDictionaryEntry *e = NULL; - while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { - Debug( 3, "Encoder Option %s=%s", e->key, e->value ); - } - } - - if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) { - Warning("Can't open video codec (%s)! %s, trying h264", - video_out_codec->name, - av_make_error_string(ret).c_str() - ); - video_out_codec = avcodec_find_encoder_by_name("h264"); - if ( ! video_out_codec ) { - Error("Can't find h264 encoder"); - video_out_codec = avcodec_find_encoder_by_name("libx264"); - if ( ! video_out_codec ) { - Error("Can't find libx264 encoder"); - return false; - } - } - if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) { - Error("Can't open video codec (%s)! %s", video_out_codec->name, - av_make_error_string(ret).c_str() ); -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - // We allocate and copy in newer ffmpeg, so need to free it - avcodec_free_context(&video_out_ctx); -#endif - video_out_ctx=NULL; - - return false; - } - } // end if can't open codec - Debug(2,"Sucess opening codec"); - AVDictionaryEntry *e = NULL; - while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { - Warning( "Encoder Option %s not recognized by ffmpeg codec", e->key); - } - av_dict_free(&opts); - - if ( !video_out_ctx->codec_tag ) { - video_out_ctx->codec_tag = - av_codec_get_tag(oc->oformat->codec_tag, video_out_ctx->codec_id ); - Debug(2, "No codec_tag, setting to h264 ? "); - } - } // end if copying or trasncoding - - video_out_stream = avformat_new_stream(oc, video_out_codec); - if ( ! video_out_stream ) { - Error("Unable to create video out stream"); - return false; - } -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - ret = avcodec_parameters_from_context(video_out_stream->codecpar, video_out_ctx); - if ( ret < 0 ) { - Error("Could not initialize stream parameteres"); - return false; - } -#else - avcodec_copy_context(video_out_stream->codec, video_out_ctx); -#endif - - if ( video_in_stream && ( video_in_ctx->codec_id == AV_CODEC_ID_H264 ) ) { // Only set orientation if doing passthrough, otherwise the frame image will be rotated Monitor::Orientation orientation = monitor->getOrientation(); if ( orientation ) { @@ -382,15 +209,138 @@ Debug(2,"Using mjpeg"); } else { Warning("Unsupported Orientation(%d)", orientation); } + } // end if orientation + } else { + /** Create a new frame to store the */ + if ( !(video_in_frame = zm_av_frame_alloc()) ) { + Error("Could not allocate video_in frame"); + return false; } + for (int i = 0; i < sizeof(codec_data) / sizeof(*codec_data); i++ ) { + if ( codec_data[i].codec_id != monitor->OutputCodec() ) + continue; + + video_out_codec = avcodec_find_encoder_by_name(codec_data[i].codec_name); + if ( ! video_out_codec ) { + Debug(1, "Didn't find encoder for %s", codec_data[i].codec_name); + continue; + } + + Debug(1, "Using %s for codec", video_out_codec->name); + //video_out_ctx = avcodec_alloc_context3(video_out_codec); + if ( video_out_codec->id != video_out_ctx->codec_id ) { + Warning("Have to set codec_id?"); + video_out_ctx->codec_id = AV_CODEC_ID_H264; + } + + video_out_ctx->pix_fmt = codec_data[i].pix_fmt; + video_out_ctx->level = 32; + + // Don't have an input stream, so need to tell it what we are sending it, or are transcoding + video_out_ctx->width = monitor->Width(); + video_out_ctx->height = monitor->Height(); + video_out_ctx->codec_type = AVMEDIA_TYPE_VIDEO; + + /* video time_base can be set to whatever is handy and supported by encoder */ + //video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate + video_out_ctx->time_base = (AVRational){1, 30}; // microseconds as base frame rate + video_out_ctx->framerate = (AVRational){30,1}; + //video_out_ctx->gop_size = 12; + //video_out_ctx->qmin = 10; + //video_out_ctx->qmax = 51; + //video_out_ctx->qcompress = 0.6; + video_out_ctx->bit_rate = 400*1024; + video_out_ctx->thread_count = 0; + + if ( video_out_ctx->codec_id == AV_CODEC_ID_H264 ) { + video_out_ctx->max_b_frames = 1; + if ( video_out_ctx->priv_data ) { + av_opt_set(video_out_ctx->priv_data, "crf", "1", AV_OPT_SEARCH_CHILDREN); + //av_opt_set(video_out_ctx->priv_data, "preset", "ultrafast", 0); + } else { + Debug(2, "Not setting priv_data"); + } + } else if (video_out_ctx->codec_id == AV_CODEC_ID_MPEG2VIDEO) { + /* just for testing, we also add B frames */ + video_out_ctx->max_b_frames = 2; + } else if (video_out_ctx->codec_id == AV_CODEC_ID_MPEG1VIDEO) { + /* Needed to avoid using macroblocks in which some coeffs overflow. + * This does not happen with normal video, it just happens here as + * the motion of the chroma plane does not match the luma plane. */ + video_out_ctx->mb_decision = 2; + } + + AVDictionary *opts = 0; + std::string Options = monitor->GetEncoderOptions(); + ret = av_dict_parse_string(&opts, Options.c_str(), "=", ",#\n", 0); + if ( ret < 0 ) { + Warning("Could not parse ffmpeg encoder options list '%s'\n", Options.c_str()); + } else { + AVDictionaryEntry *e = NULL; + while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { + Debug( 3, "Encoder Option %s=%s", e->key, e->value ); + } + } + + if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) { + Warning("Can't open video codec (%s) %s", + video_out_codec->name, + av_make_error_string(ret).c_str() + ); + video_out_codec = NULL; + } + + AVDictionaryEntry *e = NULL; + while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { + Warning( "Encoder Option %s not recognized by ffmpeg codec", e->key); + } + av_dict_free(&opts); + if ( video_out_codec ) break; + + } // end foreach codec + + if ( ! video_out_codec ) { + Error("Can't open video codec!"); +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + // We allocate and copy in newer ffmpeg, so need to free it + avcodec_free_context(&video_out_ctx); +#endif + video_out_ctx = NULL; + + return false; + } // end if can't open codec + + Debug(2,"Sucess opening codec"); + + } // end if copying or trasncoding + + if ( !video_out_ctx->codec_tag ) { + video_out_ctx->codec_tag = + av_codec_get_tag(oc->oformat->codec_tag, video_out_ctx->codec_id ); + Debug(2, "No codec_tag, setting to h264 ? "); } + video_out_stream = avformat_new_stream(oc, video_out_codec); + if ( ! video_out_stream ) { + Error("Unable to create video out stream"); + return false; + } +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + ret = avcodec_parameters_from_context(video_out_stream->codecpar, video_out_ctx); + if ( ret < 0 ) { + Error("Could not initialize stream parameteres"); + return false; + } +#else + avcodec_copy_context(video_out_stream->codec, video_out_ctx); +#endif + if ( audio_in_stream ) { audio_in_stream_index = audio_in_stream->index; #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) audio_in_ctx = avcodec_alloc_context3(NULL); ret = avcodec_parameters_to_context(audio_in_ctx, - audio_in_stream->codecpar); + audio_in_stream->codecpar); #else audio_in_ctx = audio_in_stream->codec; #endif @@ -398,7 +348,7 @@ Debug(2,"Using mjpeg"); if ( audio_in_ctx->codec_id != AV_CODEC_ID_AAC ) { static char error_buffer[256]; avcodec_string(error_buffer, sizeof(error_buffer), audio_in_ctx, - 0); + 0); Debug(2, "Got something other than AAC (%s)", error_buffer); if ( !setup_resampler() ) { @@ -409,9 +359,9 @@ Debug(2,"Using mjpeg"); audio_out_stream = #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - avformat_new_stream(oc, (const AVCodec *)(audio_in_ctx->codec)); + avformat_new_stream(oc, (const AVCodec *)(audio_in_ctx->codec)); #else - avformat_new_stream(oc, (AVCodec *)audio_in_ctx->codec); + avformat_new_stream(oc, (AVCodec *)audio_in_ctx->codec); #endif if ( !audio_out_stream ) { Error("Unable to create audio out stream\n"); @@ -424,13 +374,13 @@ Debug(2,"Using mjpeg"); // Copy params from instream to ctx if ( (ret = avcodec_parameters_to_context(audio_out_ctx, audio_in_stream->codecpar) ) < 0 ) { Error("Unable to copy audio params to ctx %s\n", - av_make_error_string(ret).c_str()); + av_make_error_string(ret).c_str()); } // Then from ctx to out_stream ret = avcodec_parameters_from_context(audio_out_stream->codecpar, audio_out_ctx); if ( ret < 0 ) { Error("Unable to copy audio params to stream %s\n", - av_make_error_string(ret).c_str()); + av_make_error_string(ret).c_str()); } if ( !audio_out_ctx->codec_tag ) { @@ -445,7 +395,7 @@ Debug(2,"Using mjpeg"); #endif if ( ret < 0 ) { Error("Unable to copy audio ctx %s\n", - av_make_error_string(ret).c_str()); + av_make_error_string(ret).c_str()); audio_out_stream = NULL; } else { if ( audio_out_ctx->channels > 1 ) { @@ -456,26 +406,24 @@ Debug(2,"Using mjpeg"); } } } // end if audio_out_stream - } // end if is AAC + } // end if is AAC if ( audio_out_stream ) { if (oc->oformat->flags & AVFMT_GLOBALHEADER) { #if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) - audio_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; + audio_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; #else - audio_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; + audio_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; #endif } } } // end if audio_in_stream /* open the out file, if needed */ - if (!(out_format->flags & AVFMT_NOFILE)) { - ret = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE, NULL, NULL); - if (ret < 0) { + if ( !(out_format->flags & AVFMT_NOFILE) ) { + if ( (ret = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE, NULL, NULL) ) < 0 ) { Error("Could not open out file '%s': %s\n", filename, - av_make_error_string(ret).c_str()); - + av_make_error_string(ret).c_str()); return false; } } @@ -495,7 +443,7 @@ Debug(2,"Using mjpeg"); } if ( ret < 0 ) { Error("Error occurred when writing out file header to %s: %s\n", - filename, av_make_error_string(ret).c_str()); + filename, av_make_error_string(ret).c_str()); return false; } if ( opts ) av_dict_free(&opts); @@ -503,83 +451,32 @@ Debug(2,"Using mjpeg"); zm_dump_stream_format(oc, 0, 0, 1); if (audio_out_stream) zm_dump_stream_format(oc, 1, 0, 1); return true; -} // end bool VideoStore::open() + } // end bool VideoStore::open() -void VideoStore::write_audio_packet( AVPacket &pkt ) { -//Debug(2, "writing audio packet pts(%d) dts(%d) duration(%d)", pkt.pts, - //pkt.dts, pkt.duration); - pkt.pts = audio_next_pts; - pkt.dts = audio_next_dts; + void VideoStore::write_audio_packet( AVPacket &pkt ) { + //Debug(2, "writing audio packet pts(%d) dts(%d) duration(%d)", pkt.pts, + //pkt.dts, pkt.duration); + pkt.pts = audio_next_pts; + pkt.dts = audio_next_dts; - Debug(2, "writing audio packet pts(%d) dts(%d) duration(%d)", pkt.pts, pkt.dts, pkt.duration); - if ( pkt.duration > 0 ) { - pkt.duration = - av_rescale_q(pkt.duration, audio_out_ctx->time_base, - audio_out_stream->time_base); - } - audio_next_pts += pkt.duration; - audio_next_dts += pkt.duration; + Debug(2, "writing audio packet pts(%d) dts(%d) duration(%d)", pkt.pts, pkt.dts, pkt.duration); + if ( pkt.duration > 0 ) { + pkt.duration = + av_rescale_q(pkt.duration, audio_out_ctx->time_base, + audio_out_stream->time_base); + } + audio_next_pts += pkt.duration; + audio_next_dts += pkt.duration; - Debug(2, "writing audio packet pts(%d) dts(%d) duration(%d)", pkt.pts, pkt.dts, pkt.duration); - pkt.stream_index = audio_out_stream->index; - av_interleaved_write_frame(oc, &pkt); -} // end void VideoStore::Write_audio_packet( AVPacket &pkt ) + Debug(2, "writing audio packet pts(%d) dts(%d) duration(%d)", pkt.pts, pkt.dts, pkt.duration); + pkt.stream_index = audio_out_stream->index; + av_interleaved_write_frame(oc, &pkt); + } // end void VideoStore::Write_audio_packet( AVPacket &pkt ) -VideoStore::~VideoStore() { - if ( oc->pb ) { - if ( ( video_out_ctx->codec_id != video_in_ctx->codec_id ) || audio_out_codec ) { - Debug(2,"Different codecs between in and out"); - // The codec queues data. We need to send a flush command and out - // whatever we get. Failures are not fatal. - AVPacket pkt; - // WIthout these we seg fault I don't know why. - pkt.data = NULL; - pkt.size = 0; - av_init_packet(&pkt); - - // I got crashes if the codec didn't do DELAY, so let's test for it. - if ( video_out_ctx->codec && ( video_out_ctx->codec->capabilities & -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - AV_CODEC_CAP_DELAY -#else - CODEC_CAP_DELAY -#endif - ) ) { - -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - // Put encoder into flushing mode - avcodec_send_frame(video_out_ctx, NULL); - while (1) { - ret = avcodec_receive_packet(video_out_ctx, &pkt); - if (ret < 0) { - if (AVERROR_EOF != ret) { - Error("ERror encoding audio while flushing (%d) (%s)", ret, - av_err2str(ret)); - } - break; - } -#else - while (1) { - // WIthout these we seg fault I don't know why. - pkt.data = NULL; - pkt.size = 0; - av_init_packet(&pkt); - int got_packet = 0; - ret = avcodec_encode_video2(video_out_ctx, &pkt, NULL, &got_packet); - if ( ret < 0 ) { - Error("ERror encoding video while flushing (%d) (%s)", ret, av_err2str(ret)); - break; - } - if (!got_packet) { - break; - } -#endif - write_video_packet(pkt); - zm_av_packet_unref(&pkt); - } // while have buffered frames - } // end if have delay capability - - if ( audio_out_codec ) { + VideoStore::~VideoStore() { + if ( oc->pb ) { + if ( ( video_out_ctx->codec_id != video_in_ctx->codec_id ) || audio_out_codec ) { + Debug(2,"Different codecs between in and out"); // The codec queues data. We need to send a flush command and out // whatever we get. Failures are not fatal. AVPacket pkt; @@ -588,845 +485,896 @@ VideoStore::~VideoStore() { pkt.size = 0; av_init_packet(&pkt); + // I got crashes if the codec didn't do DELAY, so let's test for it. + if ( video_out_ctx->codec && ( video_out_ctx->codec->capabilities & #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - // Put encoder into flushing mode - avcodec_send_frame(audio_out_ctx, NULL); - while (1) { - if ( (ret = avcodec_receive_packet(audio_out_ctx, &pkt) ) < 0 ) { - if ( AVERROR_EOF != ret ) { - Error("ERror encoding audio while flushing (%d) (%s)", ret, av_err2str(ret)); + AV_CODEC_CAP_DELAY +#else + CODEC_CAP_DELAY +#endif + ) ) { + +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + // Put encoder into flushing mode + avcodec_send_frame(video_out_ctx, NULL); + while (1) { + ret = avcodec_receive_packet(video_out_ctx, &pkt); + if (ret < 0) { + if (AVERROR_EOF != ret) { + Error("ERror encoding audio while flushing (%d) (%s)", ret, + av_err2str(ret)); + } + break; } - break; - } #else - while (1) { - pkt.data = NULL; - pkt.size = 0; - av_init_packet(&pkt); - int got_packet = 0; - if ( (ret = avcodec_encode_audio2(audio_out_ctx, &pkt, NULL, &got_packet)) < 0 ) { - Error("ERror encoding audio while flushing (%d) (%s)", ret, av_err2str(ret)); - break; + while (1) { + // WIthout these we seg fault I don't know why. + pkt.data = NULL; + pkt.size = 0; + av_init_packet(&pkt); + int got_packet = 0; + ret = avcodec_encode_video2(video_out_ctx, &pkt, NULL, &got_packet); + if ( ret < 0 ) { + Error("ERror encoding video while flushing (%d) (%s)", ret, av_err2str(ret)); + break; + } + if (!got_packet) { + break; + } +#endif + write_video_packet(pkt); + zm_av_packet_unref(&pkt); + } // while have buffered frames + } // end if have delay capability + + if ( audio_out_codec ) { + // The codec queues data. We need to send a flush command and out + // whatever we get. Failures are not fatal. + AVPacket pkt; + // WIthout these we seg fault I don't know why. + pkt.data = NULL; + pkt.size = 0; + av_init_packet(&pkt); + +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + // Put encoder into flushing mode + avcodec_send_frame(audio_out_ctx, NULL); + while (1) { + if ( (ret = avcodec_receive_packet(audio_out_ctx, &pkt) ) < 0 ) { + if ( AVERROR_EOF != ret ) { + Error("ERror encoding audio while flushing (%d) (%s)", ret, av_err2str(ret)); + } + break; + } +#else + while (1) { + pkt.data = NULL; + pkt.size = 0; + av_init_packet(&pkt); + int got_packet = 0; + if ( (ret = avcodec_encode_audio2(audio_out_ctx, &pkt, NULL, &got_packet)) < 0 ) { + Error("ERror encoding audio while flushing (%d) (%s)", ret, av_err2str(ret)); + break; + } + Debug(1, "Have audio encoder, need to flush it's out"); + if (!got_packet) { + break; + } +#endif + write_audio_packet(pkt); + zm_av_packet_unref(&pkt); + } // while have buffered frames + } // end if audio_out_codec + } // end if buffers + + // Flush Queues + av_interleaved_write_frame(oc, NULL); + + /* Write the trailer before close */ + if ( int rc = av_write_trailer(oc) ) { + Error("Error writing trailer %s", av_err2str(rc)); + } else { + Debug(3, "Sucess Writing trailer"); } - Debug(1, "Have audio encoder, need to flush it's out"); - if (!got_packet) { - break; + + // WHen will be not using a file ? + if ( !(out_format->flags & AVFMT_NOFILE) ) { + /* Close the out file. */ + Debug(2, "Closing"); + if (int rc = avio_close(oc->pb)) { + oc->pb = NULL; + Error("Error closing avio %s", av_err2str(rc)); + } + } else { + Debug(3, "Not closing avio because we are not writing to a file."); } -#endif - write_audio_packet(pkt); - zm_av_packet_unref(&pkt); - } // while have buffered frames - } // end if audio_out_codec - } // end if buffers + } // end if oc->pb - // Flush Queues - av_interleaved_write_frame(oc, NULL); + // I wonder if we should be closing the file first. + // I also wonder if we really need to be doing all the ctx + // allocation/de-allocation constantly, or whether we can just re-use it. + // Just do a file open/close/writeheader/etc. + // What if we were only doing audio recording? - /* Write the trailer before close */ - if ( int rc = av_write_trailer(oc) ) { - Error("Error writing trailer %s", av_err2str(rc)); - } else { - Debug(3, "Sucess Writing trailer"); - } - - // WHen will be not using a file ? - if ( !(out_format->flags & AVFMT_NOFILE) ) { - /* Close the out file. */ - Debug(2, "Closing"); - if (int rc = avio_close(oc->pb)) { - oc->pb = NULL; - Error("Error closing avio %s", av_err2str(rc)); - } - } else { - Debug(3, "Not closing avio because we are not writing to a file."); - } - } // end if oc->pb - - // I wonder if we should be closing the file first. - // I also wonder if we really need to be doing all the ctx - // allocation/de-allocation constantly, or whether we can just re-use it. - // Just do a file open/close/writeheader/etc. - // What if we were only doing audio recording? - - if ( video_out_stream ) { + if ( video_out_stream ) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - // We allocate and copy in newer ffmpeg, so need to free it - avcodec_free_context(&video_in_ctx); + // We allocate and copy in newer ffmpeg, so need to free it + avcodec_free_context(&video_in_ctx); #endif - video_in_ctx=NULL; + video_in_ctx=NULL; - avcodec_close(video_out_ctx); + avcodec_close(video_out_ctx); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - avcodec_free_context(&video_out_ctx); + avcodec_free_context(&video_out_ctx); #endif - video_out_ctx = NULL; - Debug(4, "Success freeing video_out_ctx"); - } - if ( audio_out_stream ) { - if ( audio_in_codec ) { - avcodec_close(audio_in_ctx); + video_out_ctx = NULL; + Debug(4, "Success freeing video_out_ctx"); + } + if ( audio_out_stream ) { + if ( audio_in_codec ) { + avcodec_close(audio_in_ctx); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - // We allocate and copy in newer ffmpeg, so need to free it - avcodec_free_context(&audio_in_ctx); + // We allocate and copy in newer ffmpeg, so need to free it + avcodec_free_context(&audio_in_ctx); #endif - audio_in_ctx = NULL; - audio_in_codec = NULL; - } // end if audio_in_codec + audio_in_ctx = NULL; + audio_in_codec = NULL; + } // end if audio_in_codec - avcodec_close(audio_out_ctx); + avcodec_close(audio_out_ctx); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - avcodec_free_context(&audio_out_ctx); + avcodec_free_context(&audio_out_ctx); #endif - audio_out_ctx = NULL; + audio_out_ctx = NULL; #ifdef HAVE_LIBAVRESAMPLE - if ( resample_ctx ) { - avresample_close(resample_ctx); - avresample_free(&resample_ctx); - } - if ( out_frame ) { - av_frame_free(&out_frame); - out_frame = NULL; - } - if ( converted_in_samples ) { - av_free(converted_in_samples); - converted_in_samples = NULL; - } + if ( resample_ctx ) { + avresample_close(resample_ctx); + avresample_free(&resample_ctx); + } + if ( out_frame ) { + av_frame_free(&out_frame); + out_frame = NULL; + } + if ( converted_in_samples ) { + av_free(converted_in_samples); + converted_in_samples = NULL; + } #endif - } + } #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - if ( video_in_ctx ) { - avcodec_free_context(&video_in_ctx); - video_in_ctx = NULL; - } - if ( video_out_ctx ) { - avcodec_close(video_out_ctx); - avcodec_free_context(&video_out_ctx); - video_out_ctx = NULL; - } + if ( video_in_ctx ) { + avcodec_free_context(&video_in_ctx); + video_in_ctx = NULL; + } + if ( video_out_ctx ) { + avcodec_close(video_out_ctx); + avcodec_free_context(&video_out_ctx); + video_out_ctx = NULL; + } #endif - /* free the stream */ - avformat_free_context(oc); -} - -bool VideoStore::setup_resampler() { - //I think this is unneccessary, we should be able to just pass in the decoder from the input. -#ifdef HAVE_LIBAVRESAMPLE - // Newer ffmpeg wants to keep everything separate... so have to lookup our own - // decoder, can't reuse the one from the camera. - AVCodec *audio_in_codec = avcodec_find_decoder( -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - audio_in_stream->codecpar->codec_id -#else - audio_in_ctx->codec_id -#endif - ); - if ( (ret = avcodec_open2(audio_in_ctx, audio_in_codec, NULL)) < 0 ) { - Error("Can't open in codec!"); - return false; - } - - audio_out_codec = avcodec_find_encoder(AV_CODEC_ID_AAC); - if ( !audio_out_codec ) { - Error("Could not find codec for AAC"); - return false; - } - - // Now copy them to the out stream - audio_out_stream = avformat_new_stream(oc, audio_out_codec); - -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - audio_out_ctx = avcodec_alloc_context3(audio_out_codec); - if ( !audio_out_ctx ) { - Error("could not allocate codec ctx for AAC\n"); - audio_out_stream = NULL; - return false; - } -#else - audio_out_ctx = audio_out_stream->codec; -#endif - - /* put sample parameters */ - audio_out_ctx->bit_rate = audio_in_ctx->bit_rate; - audio_out_ctx->sample_rate = audio_in_ctx->sample_rate; - audio_out_ctx->sample_fmt = audio_in_ctx->sample_fmt; - audio_out_ctx->channels = audio_in_ctx->channels; - audio_out_ctx->channel_layout = audio_in_ctx->channel_layout; - - if ( audio_out_codec->supported_samplerates ) { - int found = 0; - for ( int i=0; audio_out_codec->supported_samplerates[i]; i++ ) { - if ( audio_out_ctx->sample_rate == - audio_out_codec->supported_samplerates[i]) { - found = 1; - break; + /* free the stream */ + avformat_free_context(oc); } - } - if ( found ) { - Debug(4, "Sample rate is good"); - } else { - audio_out_ctx->sample_rate = - audio_out_codec->supported_samplerates[0]; - Debug(1, "Sampel rate is no good, setting to (%d)", - audio_out_codec->supported_samplerates[0]); - } - } - /* check that the encoder supports s16 pcm in */ - if ( !check_sample_fmt(audio_out_codec, audio_out_ctx->sample_fmt) ) { - Debug(3, "Encoder does not support sample format %s, setting to FLTP", - av_get_sample_fmt_name(audio_out_ctx->sample_fmt)); - audio_out_ctx->sample_fmt = AV_SAMPLE_FMT_FLTP; - } - - // Example code doesn't set the codec tb. I think it just uses whatever defaults - //audio_out_ctx->time_base = (AVRational){1, audio_out_ctx->sample_rate}; - - - AVDictionary *opts = NULL; - // Needed to allow AAC - if ( (ret = av_dict_set(&opts, "strict", "experimental", 0)) < 0 ) { - Error("Couldn't set experimental"); - } - ret = avcodec_open2(audio_out_ctx, audio_out_codec, &opts); - av_dict_free(&opts); - if ( ret < 0 ) { - Fatal("could not open codec (%d) (%s)\n", ret, av_make_error_string(ret).c_str()); - audio_out_codec = NULL; - audio_out_ctx = NULL; - audio_out_stream = NULL; - return false; - } - - audio_out_stream->time_base = (AVRational){1, audio_out_ctx->sample_rate}; + bool VideoStore::setup_resampler() { + //I think this is unneccessary, we should be able to just pass in the decoder from the input. +#ifdef HAVE_LIBAVRESAMPLE + // Newer ffmpeg wants to keep everything separate... so have to lookup our own + // decoder, can't reuse the one from the camera. + AVCodec *audio_in_codec = avcodec_find_decoder( #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - if ( (ret = avcodec_parameters_from_context( - audio_out_stream->codecpar, - audio_out_ctx)) < 0 ) { - Error("Could not initialize stream parameteres"); - return false; - } - //audio_out_stream->codecpar->frame_size = audio_out_ctx->frame_size; - //audio_out_stream->codecpar->bit_rate = audio_out_ctx->bit_rate; + audio_in_stream->codecpar->codec_id #else - avcodec_copy_context( audio_out_stream->codec, audio_out_ctx ); + audio_in_ctx->codec_id #endif + ); + if ( (ret = avcodec_open2(audio_in_ctx, audio_in_codec, NULL)) < 0 ) { + Error("Can't open in codec!"); + return false; + } - Debug(1, - "Audio out context bit_rate (%d) sample_rate(%d) channels(%d) fmt(%d) " - "layout(%d) frame_size(%d)", - audio_out_ctx->bit_rate, audio_out_ctx->sample_rate, - audio_out_ctx->channels, audio_out_ctx->sample_fmt, - audio_out_ctx->channel_layout, audio_out_ctx->frame_size); + audio_out_codec = avcodec_find_encoder(AV_CODEC_ID_AAC); + if ( !audio_out_codec ) { + Error("Could not find codec for AAC"); + return false; + } + + // Now copy them to the out stream + audio_out_stream = avformat_new_stream(oc, audio_out_codec); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - Debug(1, - "Audio out stream bit_rate (%d) sample_rate(%d) channels(%d) fmt(%d) " - "layout(%d) frame_size(%d)", - audio_out_stream->codecpar->bit_rate, audio_out_stream->codecpar->sample_rate, - audio_out_stream->codecpar->channels, audio_out_stream->codecpar->format, - audio_out_stream->codecpar->channel_layout, audio_out_stream->codecpar->frame_size); + audio_out_ctx = avcodec_alloc_context3(audio_out_codec); + if ( !audio_out_ctx ) { + Error("could not allocate codec ctx for AAC\n"); + audio_out_stream = NULL; + return false; + } #else - Debug(1, - "Audio out bit_rate (%d) sample_rate(%d) channels(%d) fmt(%d) " - "layout(%d) frame_size(%d)", - audio_out_stream->codec->bit_rate, audio_out_stream->codec->sample_rate, - audio_out_stream->codec->channels, audio_out_stream->codec->sample_fmt, - audio_out_stream->codec->channel_layout, audio_out_stream->codec->frame_size); + audio_out_ctx = audio_out_stream->codec; #endif - /** Create a new frame to store the audio samples. */ - if ( ! in_frame ) { - if (!(in_frame = zm_av_frame_alloc())) { - Error("Could not allocate in frame"); - return false; - } - } + /* put sample parameters */ + audio_out_ctx->bit_rate = audio_in_ctx->bit_rate; + audio_out_ctx->sample_rate = audio_in_ctx->sample_rate; + audio_out_ctx->sample_fmt = audio_in_ctx->sample_fmt; + audio_out_ctx->channels = audio_in_ctx->channels; + audio_out_ctx->channel_layout = audio_in_ctx->channel_layout; - /** Create a new frame to store the audio samples. */ - if ( !(out_frame = zm_av_frame_alloc()) ) { - Error("Could not allocate out frame"); - av_frame_free(&in_frame); - return false; - } - out_frame->sample_rate = audio_out_ctx->sample_rate; + if ( audio_out_codec->supported_samplerates ) { + int found = 0; + for ( int i=0; audio_out_codec->supported_samplerates[i]; i++ ) { + if ( audio_out_ctx->sample_rate == + audio_out_codec->supported_samplerates[i]) { + found = 1; + break; + } + } + if ( found ) { + Debug(4, "Sample rate is good"); + } else { + audio_out_ctx->sample_rate = + audio_out_codec->supported_samplerates[0]; + Debug(1, "Sampel rate is no good, setting to (%d)", + audio_out_codec->supported_samplerates[0]); + } + } - // Setup the audio resampler - resample_ctx = avresample_alloc_context(); - if ( !resample_ctx ) { - Error("Could not allocate resample ctx\n"); - return false; - } + /* check that the encoder supports s16 pcm in */ + if ( !check_sample_fmt(audio_out_codec, audio_out_ctx->sample_fmt) ) { + Debug(3, "Encoder does not support sample format %s, setting to FLTP", + av_get_sample_fmt_name(audio_out_ctx->sample_fmt)); + audio_out_ctx->sample_fmt = AV_SAMPLE_FMT_FLTP; + } - uint64_t mono_layout = av_get_channel_layout("mono"); - // Some formats (i.e. WAV) do not produce the proper channel layout - if ( audio_in_ctx->channel_layout == 0 ) { - av_opt_set_int(resample_ctx, "in_channel_layout", mono_layout, 0); - Debug(1, "Bad channel layout. Need to set it to mono (%d).", mono_layout); - } else { - Debug(1, "channel layout. set it to mono (%d).", audio_in_ctx->channel_layout); - av_opt_set_int(resample_ctx, "in_channel_layout", - audio_in_ctx->channel_layout, 0); - } + // Example code doesn't set the codec tb. I think it just uses whatever defaults + //audio_out_ctx->time_base = (AVRational){1, audio_out_ctx->sample_rate}; - av_opt_set_int(resample_ctx, "in_sample_fmt", audio_in_ctx->sample_fmt, 0); - av_opt_set_int(resample_ctx, "in_sample_rate", audio_in_ctx->sample_rate, 0); - av_opt_set_int(resample_ctx, "in_channels", audio_in_ctx->channels, 0); - // av_opt_set_int( resample_ctx, "out_channel_layout", - // audio_out_ctx->channel_layout, 0); - av_opt_set_int(resample_ctx, "out_channel_layout", mono_layout, 0); - av_opt_set_int(resample_ctx, "out_sample_fmt", - audio_out_ctx->sample_fmt, 0); - av_opt_set_int(resample_ctx, "out_sample_rate", - audio_out_ctx->sample_rate, 0); - av_opt_set_int(resample_ctx, "out_channels", - audio_out_ctx->channels, 0); - if ( (ret = avresample_open(resample_ctx)) < 0 ) { - Error("Could not open resample ctx\n"); - return false; - } + AVDictionary *opts = NULL; + // Needed to allow AAC + if ( (ret = av_dict_set(&opts, "strict", "experimental", 0)) < 0 ) { + Error("Couldn't set experimental"); + } + ret = avcodec_open2(audio_out_ctx, audio_out_codec, &opts); + av_dict_free(&opts); + if ( ret < 0 ) { + Fatal("could not open codec (%d) (%s)\n", ret, av_make_error_string(ret).c_str()); + audio_out_codec = NULL; + audio_out_ctx = NULL; + audio_out_stream = NULL; + return false; + } - out_frame->nb_samples = audio_out_ctx->frame_size; - out_frame->format = audio_out_ctx->sample_fmt; - out_frame->channel_layout = audio_out_ctx->channel_layout; - - // The codec gives us the frame size, in samples, we calculate the size of the - // samples buffer in bytes - unsigned int audioSampleBuffer_size = av_samples_get_buffer_size( - NULL, audio_out_ctx->channels, audio_out_ctx->frame_size, - audio_out_ctx->sample_fmt, 0); - converted_in_samples = (uint8_t *)av_malloc(audioSampleBuffer_size); - - if ( !converted_in_samples ) { - Error("Could not allocate converted in sample pointers\n"); - return false; - } - - // Setup the data pointers in the AVFrame - if ( avcodec_fill_audio_frame(out_frame, audio_out_ctx->channels, - audio_out_ctx->sample_fmt, - (const uint8_t *)converted_in_samples, - audioSampleBuffer_size, 0) < 0 ) { - Error("Could not allocate converted in sample pointers\n"); - return false; - } - - return true; + audio_out_stream->time_base = (AVRational){1, audio_out_ctx->sample_rate}; +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + if ( (ret = avcodec_parameters_from_context( + audio_out_stream->codecpar, + audio_out_ctx)) < 0 ) { + Error("Could not initialize stream parameteres"); + return false; + } + //audio_out_stream->codecpar->frame_size = audio_out_ctx->frame_size; + //audio_out_stream->codecpar->bit_rate = audio_out_ctx->bit_rate; #else - Error( - "Not built with libavresample library. Cannot do audio conversion to " - "AAC"); - return false; + avcodec_copy_context( audio_out_stream->codec, audio_out_ctx ); #endif -} // end bool VideoStore::setup_resampler() + + Debug(1, + "Audio out context bit_rate (%d) sample_rate(%d) channels(%d) fmt(%d) " + "layout(%d) frame_size(%d)", + audio_out_ctx->bit_rate, audio_out_ctx->sample_rate, + audio_out_ctx->channels, audio_out_ctx->sample_fmt, + audio_out_ctx->channel_layout, audio_out_ctx->frame_size); + +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + Debug(1, + "Audio out stream bit_rate (%d) sample_rate(%d) channels(%d) fmt(%d) " + "layout(%d) frame_size(%d)", + audio_out_stream->codecpar->bit_rate, audio_out_stream->codecpar->sample_rate, + audio_out_stream->codecpar->channels, audio_out_stream->codecpar->format, + audio_out_stream->codecpar->channel_layout, audio_out_stream->codecpar->frame_size); +#else + Debug(1, + "Audio out bit_rate (%d) sample_rate(%d) channels(%d) fmt(%d) " + "layout(%d) frame_size(%d)", + audio_out_stream->codec->bit_rate, audio_out_stream->codec->sample_rate, + audio_out_stream->codec->channels, audio_out_stream->codec->sample_fmt, + audio_out_stream->codec->channel_layout, audio_out_stream->codec->frame_size); +#endif + + /** Create a new frame to store the audio samples. */ + if ( ! in_frame ) { + if (!(in_frame = zm_av_frame_alloc())) { + Error("Could not allocate in frame"); + return false; + } + } + + /** Create a new frame to store the audio samples. */ + if ( !(out_frame = zm_av_frame_alloc()) ) { + Error("Could not allocate out frame"); + av_frame_free(&in_frame); + return false; + } + out_frame->sample_rate = audio_out_ctx->sample_rate; + + // Setup the audio resampler + resample_ctx = avresample_alloc_context(); + if ( !resample_ctx ) { + Error("Could not allocate resample ctx\n"); + return false; + } + + uint64_t mono_layout = av_get_channel_layout("mono"); + // Some formats (i.e. WAV) do not produce the proper channel layout + if ( audio_in_ctx->channel_layout == 0 ) { + av_opt_set_int(resample_ctx, "in_channel_layout", mono_layout, 0); + Debug(1, "Bad channel layout. Need to set it to mono (%d).", mono_layout); + } else { + Debug(1, "channel layout. set it to mono (%d).", audio_in_ctx->channel_layout); + av_opt_set_int(resample_ctx, "in_channel_layout", + audio_in_ctx->channel_layout, 0); + } + + av_opt_set_int(resample_ctx, "in_sample_fmt", audio_in_ctx->sample_fmt, 0); + av_opt_set_int(resample_ctx, "in_sample_rate", audio_in_ctx->sample_rate, 0); + av_opt_set_int(resample_ctx, "in_channels", audio_in_ctx->channels, 0); + // av_opt_set_int( resample_ctx, "out_channel_layout", + // audio_out_ctx->channel_layout, 0); + av_opt_set_int(resample_ctx, "out_channel_layout", mono_layout, 0); + av_opt_set_int(resample_ctx, "out_sample_fmt", + audio_out_ctx->sample_fmt, 0); + av_opt_set_int(resample_ctx, "out_sample_rate", + audio_out_ctx->sample_rate, 0); + av_opt_set_int(resample_ctx, "out_channels", + audio_out_ctx->channels, 0); + + if ( (ret = avresample_open(resample_ctx)) < 0 ) { + Error("Could not open resample ctx\n"); + return false; + } + + out_frame->nb_samples = audio_out_ctx->frame_size; + out_frame->format = audio_out_ctx->sample_fmt; + out_frame->channel_layout = audio_out_ctx->channel_layout; + + // The codec gives us the frame size, in samples, we calculate the size of the + // samples buffer in bytes + unsigned int audioSampleBuffer_size = av_samples_get_buffer_size( + NULL, audio_out_ctx->channels, audio_out_ctx->frame_size, + audio_out_ctx->sample_fmt, 0); + converted_in_samples = (uint8_t *)av_malloc(audioSampleBuffer_size); + + if ( !converted_in_samples ) { + Error("Could not allocate converted in sample pointers\n"); + return false; + } + + // Setup the data pointers in the AVFrame + if ( avcodec_fill_audio_frame(out_frame, audio_out_ctx->channels, + audio_out_ctx->sample_fmt, + (const uint8_t *)converted_in_samples, + audioSampleBuffer_size, 0) < 0 ) { + Error("Could not allocate converted in sample pointers\n"); + return false; + } + + return true; +#else + Error( + "Not built with libavresample library. Cannot do audio conversion to " + "AAC"); + return false; +#endif + } // end bool VideoStore::setup_resampler() -int VideoStore::writePacket( ZMPacket *ipkt ) { - if ( ipkt->packet.stream_index == video_in_stream_index ) { - return writeVideoFramePacket( ipkt ); - } else if ( ipkt->packet.stream_index == audio_in_stream_index ) { - return writeAudioFramePacket( ipkt ); - } - Error("Unknown stream type in packet (%d) out input video stream is (%d) and audio is (%d)", - ipkt->packet.stream_index, video_in_stream_index, ( audio_in_stream ? audio_in_stream_index : -1 ) - ); - return 0; -} - -int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { - frame_count += 1; - - // if we have to transcode - if ( video_out_ctx->codec_id != video_in_ctx->codec_id ) { - //Debug(3, "Have encoding video frame count (%d)", frame_count); - - if ( ! zm_packet->out_frame ) { - //Debug(3, "Have no out frame"); - AVFrame *out_frame = zm_packet->out_frame = zm_av_frame_alloc(); - if ( ! out_frame ) { - Error("Unable to allocate a frame"); + int VideoStore::writePacket( ZMPacket *ipkt ) { + if ( ipkt->packet.stream_index == video_in_stream_index ) { + return writeVideoFramePacket( ipkt ); + } else if ( ipkt->packet.stream_index == audio_in_stream_index ) { + return writeAudioFramePacket( ipkt ); + } + Error("Unknown stream type in packet (%d) out input video stream is (%d) and audio is (%d)", + ipkt->packet.stream_index, video_in_stream_index, ( audio_in_stream ? audio_in_stream_index : -1 ) + ); return 0; } + + int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { + frame_count += 1; + + // if we have to transcode + if ( video_out_ctx->codec_id != video_in_ctx->codec_id ) { + //Debug(3, "Have encoding video frame count (%d)", frame_count); + + if ( ! zm_packet->out_frame ) { + //Debug(3, "Have no out frame"); + AVFrame *out_frame = zm_packet->out_frame = zm_av_frame_alloc(); + if ( ! out_frame ) { + Error("Unable to allocate a frame"); + return 0; + } #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) - int codec_imgsize = av_image_get_buffer_size( - video_out_ctx->pix_fmt, - video_out_ctx->width, - video_out_ctx->height, 1); - zm_packet->buffer = (uint8_t *)av_malloc(codec_imgsize); - av_image_fill_arrays( - out_frame->data, - out_frame->linesize, - zm_packet->buffer, - video_out_ctx->pix_fmt, - video_out_ctx->width, - video_out_ctx->height, - 1); + int codec_imgsize = av_image_get_buffer_size( + video_out_ctx->pix_fmt, + video_out_ctx->width, + video_out_ctx->height, 1); + zm_packet->buffer = (uint8_t *)av_malloc(codec_imgsize); + av_image_fill_arrays( + out_frame->data, + out_frame->linesize, + zm_packet->buffer, + video_out_ctx->pix_fmt, + video_out_ctx->width, + video_out_ctx->height, + 1); #else - int codec_imgsize = avpicture_get_size( - video_out_ctx->pix_fmt, - video_out_ctx->width, - video_out_ctx->height); - zm_packet->buffer = (uint8_t *)av_malloc(codec_imgsize); - avpicture_fill( - (AVPicture *)out_frame, - zm_packet->buffer, - video_out_ctx->pix_fmt, - video_out_ctx->width, - video_out_ctx->height - ); + int codec_imgsize = avpicture_get_size( + video_out_ctx->pix_fmt, + video_out_ctx->width, + video_out_ctx->height); + zm_packet->buffer = (uint8_t *)av_malloc(codec_imgsize); + avpicture_fill( + (AVPicture *)out_frame, + zm_packet->buffer, + video_out_ctx->pix_fmt, + video_out_ctx->width, + video_out_ctx->height + ); #endif - out_frame->width = video_out_ctx->width; - out_frame->height = video_out_ctx->height; - out_frame->format = video_out_ctx->pix_fmt; - //out_frame->pkt_duration = 0; + out_frame->width = video_out_ctx->width; + out_frame->height = video_out_ctx->height; + out_frame->format = video_out_ctx->pix_fmt; + //out_frame->pkt_duration = 0; - if ( ! zm_packet->in_frame ) { - //Debug(2,"Have no in_frame"); - if ( zm_packet->packet.size ) { - //Debug(2,"Decoding"); - if ( ! zm_packet->decode( video_in_ctx ) ) { - Debug(2, "unable to decode yet."); + if ( ! zm_packet->in_frame ) { + //Debug(2,"Have no in_frame"); + if ( zm_packet->packet.size ) { + //Debug(2,"Decoding"); + if ( ! zm_packet->decode( video_in_ctx ) ) { + Debug(2, "unable to decode yet."); + return 0; + } + //Go straight to out frame + swscale.Convert( zm_packet->in_frame, out_frame ); + } else if ( zm_packet->image ) { + //Debug(2,"Have an image, convert it"); + //Go straight to out frame + swscale.Convert( + zm_packet->image, + zm_packet->buffer, + codec_imgsize, + (AVPixelFormat)zm_packet->image->AVPixFormat(), + video_out_ctx->pix_fmt, + video_out_ctx->width, + video_out_ctx->height + ); + + } else { + Error("Have neither in_frame or image!"); + return 0; + } // end if has packet or image + } else { + // Have in_frame.... may need to convert it to out_frame + swscale.Convert(zm_packet->in_frame, zm_packet->out_frame); + } // end if no in_frame + } // end if no out_frame + + zm_packet->out_frame->coded_picture_number = frame_count; + zm_packet->out_frame->display_picture_number = frame_count; + zm_packet->out_frame->sample_aspect_ratio = (AVRational){ 0, 1 }; +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + zm_packet->out_frame->pkt_duration = 0; +#endif + + if ( ! video_start_pts ) { + uint64_t temp = zm_packet->timestamp->tv_sec*(uint64_t)1000000; + video_start_pts = temp + zm_packet->timestamp->tv_usec; + Debug(2, "No video_lsat_pts, set to (%" PRId64 ") secs(%d=>%" PRId64 ") usecs(%d)", + video_start_pts, zm_packet->timestamp->tv_sec, temp, zm_packet->timestamp->tv_usec ); + Debug(2, "No video_lsat_pts, set to (%" PRId64 ") secs(%d) usecs(%d)", + video_start_pts, zm_packet->timestamp->tv_sec, zm_packet->timestamp->tv_usec ); + zm_packet->out_frame->pts = 0; + zm_packet->out_frame->coded_picture_number = 0; + } else { + uint64_t seconds = ( zm_packet->timestamp->tv_sec*(uint64_t)1000000 + zm_packet->timestamp->tv_usec ) - video_start_pts; + zm_packet->out_frame->pts = av_rescale_q( seconds, video_in_stream->time_base, video_out_ctx->time_base); + + //zm_packet->out_frame->pkt_duration = zm_packet->out_frame->pts - video_start_pts; + Debug(2, " Setting pts for frame(%d), set to (%" PRId64 ") from (start %" PRIu64 " - %" PRIu64 " - secs(%d) usecs(%d)", + frame_count, zm_packet->out_frame->pts, video_start_pts, seconds, zm_packet->timestamp->tv_sec, zm_packet->timestamp->tv_usec ); + } + if ( zm_packet->keyframe ) { + //Debug(2, "Setting keyframe was (%d)", zm_packet->out_frame->key_frame ); + zm_packet->out_frame->key_frame = 1; + //Debug(2, "Setting keyframe (%d)", zm_packet->out_frame->key_frame ); + } else { + Debug(2, "Not Setting keyframe"); + } + +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + // Do this to allow the encoder to choose whether to use I/P/B frame + zm_packet->out_frame->pict_type = AV_PICTURE_TYPE_NONE; + Debug(4, "Sending frame"); + if ( (ret = avcodec_send_frame(video_out_ctx, zm_packet->out_frame)) < 0 ) { + Error("Could not send frame (error '%s')", av_make_error_string(ret).c_str()); + return -1; + } + + av_init_packet(&opkt); + opkt.data = NULL; + opkt.size = 0; + if ( (ret = avcodec_receive_packet(video_out_ctx, &opkt)) < 0 ) { + zm_av_packet_unref(&opkt); + if ( AVERROR(EAGAIN) == ret ) { + // THe codec may need more samples than it has, perfectly valid + Debug(3, "Could not recieve packet (error '%s')", + av_make_error_string(ret).c_str()); + return 0; + } else { + Error("Could not recieve packet (error %d = '%s')", ret, + av_make_error_string(ret).c_str()); + } + return -1; + } + //Debug(2, "Got packet using receive_packet, dts:%" PRId64 ", pts:%" PRId64 ", keyframe:%d", opkt.dts, opkt.pts, opkt.flags & AV_PKT_FLAG_KEY ); +#else + av_init_packet(&opkt); + opkt.data = NULL; + opkt.size = 0; + int data_present; + if ( (ret = avcodec_encode_video2( + video_out_ctx, &opkt, zm_packet->out_frame, &data_present)) < 0) { + Error("Could not encode frame (error '%s')", + av_make_error_string(ret).c_str()); + zm_av_packet_unref(&opkt); return 0; } - //Go straight to out frame - swscale.Convert( zm_packet->in_frame, out_frame ); - } else if ( zm_packet->image ) { - //Debug(2,"Have an image, convert it"); - //Go straight to out frame - swscale.Convert( - zm_packet->image, - zm_packet->buffer, - codec_imgsize, - (AVPixelFormat)zm_packet->image->AVPixFormat(), - video_out_ctx->pix_fmt, - video_out_ctx->width, - video_out_ctx->height - ); + if ( !data_present ) { + Debug(2, "Not ready to out a frame yet."); + zm_av_packet_unref(&opkt); + return 0; + } +#endif + // Need to adjust pts/dts values from codec time to stream time + if ( opkt.pts != AV_NOPTS_VALUE) + opkt.pts = av_rescale_q(opkt.pts, video_out_ctx->time_base, video_out_stream->time_base); + if ( opkt.dts != AV_NOPTS_VALUE) + opkt.dts = av_rescale_q(opkt.dts, video_out_ctx->time_base, video_out_stream->time_base); } else { - Error("Have neither in_frame or image!"); - return 0; - } // end if has packet or image - } else { - // Have in_frame.... may need to convert it to out_frame - swscale.Convert(zm_packet->in_frame, zm_packet->out_frame); - } // end if no in_frame - } // end if no out_frame + AVPacket *ipkt = &zm_packet->packet; + Debug(3, "Doing passthrough, just copy packet"); + // Just copy it because the codec is the same + av_init_packet(&opkt); + opkt.data = ipkt->data; + opkt.size = ipkt->size; + opkt.flags = ipkt->flags; + if ( ! video_start_pts ) { + // If video has b-frames, pts can be AV_NOPTS_VALUE so use dts intead + video_start_pts = ipkt->dts; + Debug(2, "No video_lsat_pts, set to (%" PRId64 ")", video_start_pts ); + opkt.dts = opkt.pts = 0; + } else { + dumpPacket(ipkt); + if ( ipkt->pts != AV_NOPTS_VALUE ) + opkt.pts = av_rescale_q( ipkt->pts - video_start_pts, video_in_stream->time_base, video_out_stream->time_base ); + else + opkt.pts = 0; - zm_packet->out_frame->coded_picture_number = frame_count; - zm_packet->out_frame->display_picture_number = frame_count; - zm_packet->out_frame->sample_aspect_ratio = (AVRational){ 0, 1 }; + if ( ipkt->dts != AV_NOPTS_VALUE ) + opkt.dts = av_rescale_q( ipkt->dts - video_start_pts, video_in_stream->time_base, video_out_stream->time_base ); + else + opkt.dts = 0; + Debug(2, "out_stream_time_base(%d/%d) in_stream_time_base(%d/%d) video_start_pts(%" PRId64 ")", + video_out_stream->time_base.num, video_out_stream->time_base.den, + video_in_stream->time_base.num, video_in_stream->time_base.den, + video_start_pts + ); + + dumpPacket(&opkt); + + opkt.duration = av_rescale_q( opkt.duration, video_in_stream->time_base, video_out_stream->time_base); + } + } + + //opkt.duration = 0; + + write_video_packet( opkt ); + zm_av_packet_unref(&opkt); + + return 1; + } // end int VideoStore::writeVideoFramePacket( AVPacket *ipkt ) + + void VideoStore::write_video_packet( AVPacket &opkt ) { + + if ( opkt.dts > opkt.pts ) { + Debug(1, + "opkt.dts(%" PRId64 ") must be <= opkt.pts(%" PRId64 "). Decompression must happen " + "before presentation.", + opkt.dts, opkt.pts); + opkt.dts = opkt.pts; + } + + opkt.stream_index = video_out_stream->index; + //av_packet_rescale_ts( &opkt, video_out_ctx->time_base, video_out_stream->time_base ); + + dumpPacket(&opkt, "writing video packet"); + + if ( (opkt.data == NULL) || (opkt.size < 1) ) { + Warning("%s:%d: Mangled AVPacket: discarding frame", __FILE__, __LINE__); + //dumpPacket(&opkt); + + //} else if ((video_next_dts > 0) && (video_next_dts > opkt.dts)) { + //Warning("%s:%d: DTS out of order: next:%lld \u226E opkt.dts %lld; discarding frame", + //__FILE__, __LINE__, video_next_dts, opkt.dts); + //video_next_dts = opkt.dts; + //dumpPacket(&opkt); + + } else { + if ( (ret = av_interleaved_write_frame(oc, &opkt)) < 0 ) { + // There's nothing we can really do if the frame is rejected, just drop it + // and get on with the next + Warning( + "%s:%d: Writing frame [av_interleaved_write_frame()] failed: %s(%d) " + " ", + __FILE__, __LINE__, av_make_error_string(ret).c_str(), ret); + + //dumpPacket(&safepkt); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - zm_packet->out_frame->pkt_duration = 0; + if ( video_in_stream ) + zm_dump_codecpar(video_in_stream->codecpar); + zm_dump_codecpar(video_out_stream->codecpar); #endif - - if ( ! video_start_pts ) { - uint64_t temp = zm_packet->timestamp->tv_sec*(uint64_t)1000000; - video_start_pts = temp + zm_packet->timestamp->tv_usec; - Debug(2, "No video_lsat_pts, set to (%" PRId64 ") secs(%d=>%" PRId64 ") usecs(%d)", - video_start_pts, zm_packet->timestamp->tv_sec, temp, zm_packet->timestamp->tv_usec ); - Debug(2, "No video_lsat_pts, set to (%" PRId64 ") secs(%d) usecs(%d)", - video_start_pts, zm_packet->timestamp->tv_sec, zm_packet->timestamp->tv_usec ); - zm_packet->out_frame->pts = 0; - zm_packet->out_frame->coded_picture_number = 0; - } else { - uint64_t seconds = ( zm_packet->timestamp->tv_sec*(uint64_t)1000000 + zm_packet->timestamp->tv_usec ) - video_start_pts; - zm_packet->out_frame->pts = av_rescale_q( seconds, video_in_stream->time_base, video_out_ctx->time_base); - - //zm_packet->out_frame->pkt_duration = zm_packet->out_frame->pts - video_start_pts; - Debug(2, " Setting pts for frame(%d), set to (%" PRId64 ") from (start %" PRIu64 " - %" PRIu64 " - secs(%d) usecs(%d)", - frame_count, zm_packet->out_frame->pts, video_start_pts, seconds, zm_packet->timestamp->tv_sec, zm_packet->timestamp->tv_usec ); - } - if ( zm_packet->keyframe ) { - //Debug(2, "Setting keyframe was (%d)", zm_packet->out_frame->key_frame ); - zm_packet->out_frame->key_frame = 1; - //Debug(2, "Setting keyframe (%d)", zm_packet->out_frame->key_frame ); - } else { - Debug(2, "Not Setting keyframe"); - } - -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - // Do this to allow the encoder to choose whether to use I/P/B frame - zm_packet->out_frame->pict_type = AV_PICTURE_TYPE_NONE; - Debug(4, "Sending frame"); - if ( (ret = avcodec_send_frame(video_out_ctx, zm_packet->out_frame)) < 0 ) { - Error("Could not send frame (error '%s')", av_make_error_string(ret).c_str()); - return -1; - } - - av_init_packet(&opkt); - opkt.data = NULL; - opkt.size = 0; - if ( (ret = avcodec_receive_packet(video_out_ctx, &opkt)) < 0 ) { - zm_av_packet_unref(&opkt); - if ( AVERROR(EAGAIN) == ret ) { - // THe codec may need more samples than it has, perfectly valid - Debug(3, "Could not recieve packet (error '%s')", - av_make_error_string(ret).c_str()); - return 0; - } else { - Error("Could not recieve packet (error %d = '%s')", ret, - av_make_error_string(ret).c_str()); + } else { + packets_written += 1; + } } - return -1; - } -//Debug(2, "Got packet using receive_packet, dts:%" PRId64 ", pts:%" PRId64 ", keyframe:%d", opkt.dts, opkt.pts, opkt.flags & AV_PKT_FLAG_KEY ); -#else - av_init_packet(&opkt); - opkt.data = NULL; - opkt.size = 0; - int data_present; - if ( (ret = avcodec_encode_video2( - video_out_ctx, &opkt, zm_packet->out_frame, &data_present)) < 0) { - Error("Could not encode frame (error '%s')", - av_make_error_string(ret).c_str()); - zm_av_packet_unref(&opkt); - return 0; - } - if ( !data_present ) { - Debug(2, "Not ready to out a frame yet."); - zm_av_packet_unref(&opkt); - return 0; - } -#endif - // Need to adjust pts/dts values from codec time to stream time - if ( opkt.pts != AV_NOPTS_VALUE) - opkt.pts = av_rescale_q(opkt.pts, video_out_ctx->time_base, video_out_stream->time_base); - if ( opkt.dts != AV_NOPTS_VALUE) - opkt.dts = av_rescale_q(opkt.dts, video_out_ctx->time_base, video_out_stream->time_base); - } else { - AVPacket *ipkt = &zm_packet->packet; - Debug(3, "Doing passthrough, just copy packet"); - // Just copy it because the codec is the same - av_init_packet(&opkt); - opkt.data = ipkt->data; - opkt.size = ipkt->size; - opkt.flags = ipkt->flags; - if ( ! video_start_pts ) { - // If video has b-frames, pts can be AV_NOPTS_VALUE so use dts intead - video_start_pts = ipkt->dts; - Debug(2, "No video_lsat_pts, set to (%" PRId64 ")", video_start_pts ); - opkt.dts = opkt.pts = 0; - } else { - dumpPacket(ipkt); - if ( ipkt->pts != AV_NOPTS_VALUE ) - opkt.pts = av_rescale_q( ipkt->pts - video_start_pts, video_in_stream->time_base, video_out_stream->time_base ); - else - opkt.pts = 0; + } // end void VideoStore::write_video_packet - if ( ipkt->dts != AV_NOPTS_VALUE ) - opkt.dts = av_rescale_q( ipkt->dts - video_start_pts, video_in_stream->time_base, video_out_stream->time_base ); - else - opkt.dts = 0; - Debug(2, "out_stream_time_base(%d/%d) in_stream_time_base(%d/%d) video_start_pts(%" PRId64 ")", - video_out_stream->time_base.num, video_out_stream->time_base.den, - video_in_stream->time_base.num, video_in_stream->time_base.den, - video_start_pts - ); + int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { + Debug(4, "writeAudioFrame"); - dumpPacket(&opkt); + AVPacket *ipkt = &zm_packet->packet; - opkt.duration = av_rescale_q( opkt.duration, video_in_stream->time_base, video_out_stream->time_base); - } - } + if ( !audio_out_stream ) { + Debug(1, "Called writeAudioFramePacket when no audio_out_stream"); + return 0; // FIXME -ve return codes do not free packet in ffmpeg_camera at + // the moment + } - //opkt.duration = 0; - - write_video_packet( opkt ); - zm_av_packet_unref(&opkt); - - return 1; -} // end int VideoStore::writeVideoFramePacket( AVPacket *ipkt ) - -void VideoStore::write_video_packet( AVPacket &opkt ) { - - if ( opkt.dts > opkt.pts ) { - Debug(1, - "opkt.dts(%" PRId64 ") must be <= opkt.pts(%" PRId64 "). Decompression must happen " - "before presentation.", - opkt.dts, opkt.pts); - opkt.dts = opkt.pts; - } - - opkt.stream_index = video_out_stream->index; - //av_packet_rescale_ts( &opkt, video_out_ctx->time_base, video_out_stream->time_base ); - - dumpPacket(&opkt, "writing video packet"); - - if ( (opkt.data == NULL) || (opkt.size < 1) ) { - Warning("%s:%d: Mangled AVPacket: discarding frame", __FILE__, __LINE__); - //dumpPacket(&opkt); - - //} else if ((video_next_dts > 0) && (video_next_dts > opkt.dts)) { - //Warning("%s:%d: DTS out of order: next:%lld \u226E opkt.dts %lld; discarding frame", - //__FILE__, __LINE__, video_next_dts, opkt.dts); - //video_next_dts = opkt.dts; - //dumpPacket(&opkt); - - } else { - if ( (ret = av_interleaved_write_frame(oc, &opkt)) < 0 ) { - // There's nothing we can really do if the frame is rejected, just drop it - // and get on with the next - Warning( - "%s:%d: Writing frame [av_interleaved_write_frame()] failed: %s(%d) " - " ", - __FILE__, __LINE__, av_make_error_string(ret).c_str(), ret); - - //dumpPacket(&safepkt); -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - if ( video_in_stream ) - zm_dump_codecpar(video_in_stream->codecpar); - zm_dump_codecpar(video_out_stream->codecpar); -#endif - } else { - packets_written += 1; - } - } - -} // end void VideoStore::write_video_packet - -int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { - Debug(4, "writeAudioFrame"); - - AVPacket *ipkt = &zm_packet->packet; - - if ( !audio_out_stream ) { - Debug(1, "Called writeAudioFramePacket when no audio_out_stream"); - return 0; // FIXME -ve return codes do not free packet in ffmpeg_camera at - // the moment - } - - if ( audio_out_codec ) { - Debug(3, "Have audio codec"); + if ( audio_out_codec ) { + Debug(3, "Have audio codec"); #ifdef HAVE_LIBAVRESAMPLE #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - if ( (ret = avcodec_send_packet(audio_in_ctx, ipkt)) < 0 ) { - Error("avcodec_send_packet fail %s", av_make_error_string(ret).c_str()); - return 0; - } - if ( (ret = avcodec_receive_frame(audio_in_ctx, in_frame)) < 0 ) { - Error("avcodec_receive_frame fail %s", av_make_error_string(ret).c_str()); - return 0; - } - Debug(2, - "Input Frame: samples(%d), format(%d), sample_rate(%d), channel " - "layout(%d)", - in_frame->nb_samples, in_frame->format, - in_frame->sample_rate, in_frame->channel_layout); + if ( (ret = avcodec_send_packet(audio_in_ctx, ipkt)) < 0 ) { + Error("avcodec_send_packet fail %s", av_make_error_string(ret).c_str()); + return 0; + } + if ( (ret = avcodec_receive_frame(audio_in_ctx, in_frame)) < 0 ) { + Error("avcodec_receive_frame fail %s", av_make_error_string(ret).c_str()); + return 0; + } + Debug(2, + "Input Frame: samples(%d), format(%d), sample_rate(%d), channel " + "layout(%d)", + in_frame->nb_samples, in_frame->format, + in_frame->sample_rate, in_frame->channel_layout); #else - /** - * Decode the audio frame stored in the packet. - * The in audio stream decoder is used to do this. - * If we are at the end of the file, pass an empty packet to the decoder - * to flush it. - */ - int data_present; - if ( (ret = avcodec_decode_audio4(audio_in_ctx, in_frame, - &data_present, ipkt)) < 0 ) { - Error("Could not decode frame (error '%s')\n", - av_make_error_string(ret).c_str()); - dumpPacket(ipkt); - av_frame_free(&in_frame); - return 0; - } - if ( !data_present ) { - Debug(2, "Not ready to transcode a frame yet."); - return 0; - } + /** + * Decode the audio frame stored in the packet. + * The in audio stream decoder is used to do this. + * If we are at the end of the file, pass an empty packet to the decoder + * to flush it. + */ + int data_present; + if ( (ret = avcodec_decode_audio4(audio_in_ctx, in_frame, + &data_present, ipkt)) < 0 ) { + Error("Could not decode frame (error '%s')\n", + av_make_error_string(ret).c_str()); + dumpPacket(ipkt); + av_frame_free(&in_frame); + return 0; + } + if ( !data_present ) { + Debug(2, "Not ready to transcode a frame yet."); + return 0; + } #endif - int frame_size = out_frame->nb_samples; - in_frame->pts = audio_next_pts; + int frame_size = out_frame->nb_samples; + in_frame->pts = audio_next_pts; - // Resample the in into the audioSampleBuffer until we proceed the whole - // decoded data - if ((ret = avresample_convert(resample_ctx, NULL, 0, 0, in_frame->data, - 0, in_frame->nb_samples)) < 0) { - Error("Could not resample frame (error '%s')\n", - av_make_error_string(ret).c_str()); - av_frame_unref(in_frame); - return 0; - } - av_frame_unref(in_frame); + // Resample the in into the audioSampleBuffer until we proceed the whole + // decoded data + if ((ret = avresample_convert(resample_ctx, NULL, 0, 0, in_frame->data, + 0, in_frame->nb_samples)) < 0) { + Error("Could not resample frame (error '%s')\n", + av_make_error_string(ret).c_str()); + av_frame_unref(in_frame); + return 0; + } + av_frame_unref(in_frame); - int samples_available = avresample_available(resample_ctx); - if ( samples_available < frame_size ) { - Debug(1, "Not enough samples yet (%d)", samples_available); - return 0; - } + int samples_available = avresample_available(resample_ctx); + if ( samples_available < frame_size ) { + Debug(1, "Not enough samples yet (%d)", samples_available); + return 0; + } - Debug(3, "Output_frame samples (%d)", out_frame->nb_samples); - // Read a frame audio data from the resample fifo - if ( avresample_read(resample_ctx, out_frame->data, frame_size) != frame_size) { - Warning("Error reading resampled audio: "); - return 0; - } - Debug(2, - "Frame: samples(%d), format(%d), sample_rate(%d), channel layout(%d)", - out_frame->nb_samples, out_frame->format, - out_frame->sample_rate, out_frame->channel_layout); + Debug(3, "Output_frame samples (%d)", out_frame->nb_samples); + // Read a frame audio data from the resample fifo + if ( avresample_read(resample_ctx, out_frame->data, frame_size) != frame_size) { + Warning("Error reading resampled audio: "); + return 0; + } + Debug(2, + "Frame: samples(%d), format(%d), sample_rate(%d), channel layout(%d)", + out_frame->nb_samples, out_frame->format, + out_frame->sample_rate, out_frame->channel_layout); - av_init_packet(&opkt); - Debug(5, "after init packet"); + av_init_packet(&opkt); + Debug(5, "after init packet"); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - if ((ret = avcodec_send_frame(audio_out_ctx, out_frame)) < 0) { - Error("Could not send frame (error '%s')", - av_make_error_string(ret).c_str()); - zm_av_packet_unref(&opkt); - return 0; - } + if ((ret = avcodec_send_frame(audio_out_ctx, out_frame)) < 0) { + Error("Could not send frame (error '%s')", + av_make_error_string(ret).c_str()); + zm_av_packet_unref(&opkt); + return 0; + } - // av_frame_unref( out_frame ); + // av_frame_unref( out_frame ); - if ( (ret = avcodec_receive_packet(audio_out_ctx, &opkt)) < 0 ) { - if ( AVERROR(EAGAIN) == ret ) { - // THe codec may need more samples than it has, perfectly valid - Debug(3, "Could not recieve packet (error '%s')", - av_make_error_string(ret).c_str()); - } else { - Error("Could not recieve packet (error %d = '%s')", ret, - av_make_error_string(ret).c_str()); - } - //zm_av_packet_unref(&opkt); - av_frame_unref(in_frame); - // av_frame_unref( out_frame ); - return 0; - } + if ( (ret = avcodec_receive_packet(audio_out_ctx, &opkt)) < 0 ) { + if ( AVERROR(EAGAIN) == ret ) { + // THe codec may need more samples than it has, perfectly valid + Debug(3, "Could not recieve packet (error '%s')", + av_make_error_string(ret).c_str()); + } else { + Error("Could not recieve packet (error %d = '%s')", ret, + av_make_error_string(ret).c_str()); + } + //zm_av_packet_unref(&opkt); + av_frame_unref(in_frame); + // av_frame_unref( out_frame ); + return 0; + } #else - if ( (ret = avcodec_encode_audio2(audio_out_ctx, &opkt, out_frame, - &data_present)) < 0) { - Error("Could not encode frame (error '%s')", - av_make_error_string(ret).c_str()); - zm_av_packet_unref(&opkt); - return 0; - } - if ( !data_present ) { - Debug(2, "Not ready to out a frame yet."); - zm_av_packet_unref(&opkt); - return 0; - } + if ( (ret = avcodec_encode_audio2(audio_out_ctx, &opkt, out_frame, + &data_present)) < 0) { + Error("Could not encode frame (error '%s')", + av_make_error_string(ret).c_str()); + zm_av_packet_unref(&opkt); + return 0; + } + if ( !data_present ) { + Debug(2, "Not ready to out a frame yet."); + zm_av_packet_unref(&opkt); + return 0; + } #endif #endif - opkt.duration = out_frame->nb_samples; - } else { - av_init_packet(&opkt); - Debug(5, "after init packet"); - opkt.data = ipkt->data; - opkt.size = ipkt->size; - opkt.duration = ipkt->duration; - } + opkt.duration = out_frame->nb_samples; + } else { + av_init_packet(&opkt); + Debug(5, "after init packet"); + opkt.data = ipkt->data; + opkt.size = ipkt->size; + opkt.duration = ipkt->duration; + } -// PTS is difficult, because of the buffering of the audio packets in the -// resampler. So we have to do it once we actually have a packet... -// audio_last_pts is the pts of ipkt, audio_next_pts is the last pts of the -// out + // PTS is difficult, because of the buffering of the audio packets in the + // resampler. So we have to do it once we actually have a packet... + // audio_last_pts is the pts of ipkt, audio_next_pts is the last pts of the + // out -// Scale the PTS of the outgoing packet to be the correct time base + // Scale the PTS of the outgoing packet to be the correct time base #if 0 - if ( ipkt->pts != AV_NOPTS_VALUE ) { - if ( !audio_last_pts ) { - opkt.pts = 0; - Debug(1, "No audio_last_pts"); - } else { - if ( audio_last_pts > ipkt->pts ) { - Debug(1, "Resetting audio_start_pts from (%d) to (%d)", audio_last_pts, ipkt->pts); - opkt.pts = audio_next_pts + av_rescale_q(ipkt->pts, audio_in_stream->time_base, audio_out_stream->time_base); - } else { - opkt.pts = audio_next_pts + av_rescale_q(ipkt->pts - audio_last_pts, audio_in_stream->time_base, audio_out_stream->time_base); - } - Debug(2, "audio opkt.pts = %d from ipkt->pts(%d) - last_pts(%d)", opkt.pts, ipkt->pts, audio_last_pts); - } - audio_last_pts = ipkt->pts; - } else { - Debug(2, "opkt.pts = undef"); - opkt.pts = AV_NOPTS_VALUE; - } + if ( ipkt->pts != AV_NOPTS_VALUE ) { + if ( !audio_last_pts ) { + opkt.pts = 0; + Debug(1, "No audio_last_pts"); + } else { + if ( audio_last_pts > ipkt->pts ) { + Debug(1, "Resetting audio_start_pts from (%d) to (%d)", audio_last_pts, ipkt->pts); + opkt.pts = audio_next_pts + av_rescale_q(ipkt->pts, audio_in_stream->time_base, audio_out_stream->time_base); + } else { + opkt.pts = audio_next_pts + av_rescale_q(ipkt->pts - audio_last_pts, audio_in_stream->time_base, audio_out_stream->time_base); + } + Debug(2, "audio opkt.pts = %d from ipkt->pts(%d) - last_pts(%d)", opkt.pts, ipkt->pts, audio_last_pts); + } + audio_last_pts = ipkt->pts; + } else { + Debug(2, "opkt.pts = undef"); + opkt.pts = AV_NOPTS_VALUE; + } #else - opkt.pts = audio_next_pts; - opkt.dts = audio_next_dts; + opkt.pts = audio_next_pts; + opkt.dts = audio_next_dts; #endif #if 0 - if ( ipkt->dts == AV_NOPTS_VALUE ) { - // So if the in has no dts assigned... still need an out dts... so we use cur_dts? + if ( ipkt->dts == AV_NOPTS_VALUE ) { + // So if the in has no dts assigned... still need an out dts... so we use cur_dts? - if ( audio_last_dts >= audio_in_stream->cur_dts ) { - Debug(1, "Resetting audio_last_dts from (%d) to cur_dts (%d)", audio_last_dts, audio_in_stream->cur_dts); - opkt.dts = audio_next_dts + av_rescale_q( audio_in_stream->cur_dts, AV_TIME_BASE_Q, audio_out_stream->time_base); - } else { - opkt.dts = audio_next_dts + av_rescale_q( audio_in_stream->cur_dts - audio_last_dts, AV_TIME_BASE_Q, audio_out_stream->time_base); + if ( audio_last_dts >= audio_in_stream->cur_dts ) { + Debug(1, "Resetting audio_last_dts from (%d) to cur_dts (%d)", audio_last_dts, audio_in_stream->cur_dts); + opkt.dts = audio_next_dts + av_rescale_q( audio_in_stream->cur_dts, AV_TIME_BASE_Q, audio_out_stream->time_base); + } else { + opkt.dts = audio_next_dts + av_rescale_q( audio_in_stream->cur_dts - audio_last_dts, AV_TIME_BASE_Q, audio_out_stream->time_base); + } + audio_last_dts = audio_in_stream->cur_dts; + Debug(2, "opkt.dts = %d from video_in_stream->cur_dts(%d) - last_dts(%d)", opkt.dts, audio_in_stream->cur_dts, audio_last_dts); + } else { + if ( audio_last_dts >= ipkt->dts ) { + Debug(1, "Resetting audio_last_dts from (%d) to (%d)", audio_last_dts, ipkt->dts ); + opkt.dts = audio_next_dts + av_rescale_q(ipkt->dts, audio_in_stream->time_base, audio_out_stream->time_base); + } else { + opkt.dts = audio_next_dts + av_rescale_q(ipkt->dts - audio_last_dts, audio_in_stream->time_base, audio_out_stream->time_base); + Debug(2, "opkt.dts = %d from previous(%d) + ( ipkt->dts(%d) - last_dts(%d) )", opkt.dts, audio_next_dts, ipkt->dts, audio_last_dts ); + } + } } - audio_last_dts = audio_in_stream->cur_dts; - Debug(2, "opkt.dts = %d from video_in_stream->cur_dts(%d) - last_dts(%d)", opkt.dts, audio_in_stream->cur_dts, audio_last_dts); - } else { - if ( audio_last_dts >= ipkt->dts ) { - Debug(1, "Resetting audio_last_dts from (%d) to (%d)", audio_last_dts, ipkt->dts ); - opkt.dts = audio_next_dts + av_rescale_q(ipkt->dts, audio_in_stream->time_base, audio_out_stream->time_base); - } else { - opkt.dts = audio_next_dts + av_rescale_q(ipkt->dts - audio_last_dts, audio_in_stream->time_base, audio_out_stream->time_base); - Debug(2, "opkt.dts = %d from previous(%d) + ( ipkt->dts(%d) - last_dts(%d) )", opkt.dts, audio_next_dts, ipkt->dts, audio_last_dts ); - } - } - } #endif - // audio_last_dts = ipkt->dts; - if ( opkt.dts > opkt.pts ) { - Debug(1, - "opkt.dts(%" PRId64 ") must be <= opkt.pts(%" PRId64 "). Decompression must happen " - "before presentation.", - opkt.dts, opkt.pts); - opkt.dts = opkt.pts; - } + // audio_last_dts = ipkt->dts; + if ( opkt.dts > opkt.pts ) { + Debug(1, + "opkt.dts(%" PRId64 ") must be <= opkt.pts(%" PRId64 "). Decompression must happen " + "before presentation.", + opkt.dts, opkt.pts); + opkt.dts = opkt.pts; + } - //opkt.duration = out_frame ? out_frame->nb_samples : ipkt->duration; - // opkt.duration = av_rescale_q(ipkt->duration, audio_in_stream->time_base, - // audio_out_stream->time_base); - dumpPacket(&opkt); + //opkt.duration = out_frame ? out_frame->nb_samples : ipkt->duration; + // opkt.duration = av_rescale_q(ipkt->duration, audio_in_stream->time_base, + // audio_out_stream->time_base); + dumpPacket(&opkt); - // pkt.pos: byte position in stream, -1 if unknown - opkt.pos = -1; - opkt.stream_index = audio_out_stream->index; - audio_next_dts = opkt.dts + opkt.duration; - audio_next_pts = opkt.pts + opkt.duration; + // pkt.pos: byte position in stream, -1 if unknown + opkt.pos = -1; + opkt.stream_index = audio_out_stream->index; + audio_next_dts = opkt.dts + opkt.duration; + audio_next_pts = opkt.pts + opkt.duration; - AVPacket safepkt; - memcpy(&safepkt, &opkt, sizeof(AVPacket)); - ret = av_interleaved_write_frame(oc, &opkt); - if ( ret != 0 ) { - Error("Error writing audio frame packet: %s\n", - av_make_error_string(ret).c_str()); - dumpPacket(&safepkt); - } else { - Debug(2, "Success writing audio frame"); - } - zm_av_packet_unref(&opkt); - return 1; -} // end int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) + AVPacket safepkt; + memcpy(&safepkt, &opkt, sizeof(AVPacket)); + ret = av_interleaved_write_frame(oc, &opkt); + if ( ret != 0 ) { + Error("Error writing audio frame packet: %s\n", + av_make_error_string(ret).c_str()); + dumpPacket(&safepkt); + } else { + Debug(2, "Success writing audio frame"); + } + zm_av_packet_unref(&opkt); + return 1; + } // end int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) -int VideoStore::write_packets( zm_packetqueue &queue ) { - // 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; + int VideoStore::write_packets( zm_packetqueue &queue ) { + // 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; - while ( ( queued_packet = queue.popPacket() ) ) { - AVPacket *avp = queued_packet->av_packet(); + while ( ( queued_packet = queue.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, queue.size() ); - int ret = this->writePacket( queued_packet ); - 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 ); - return packet_count; -} // end int VideoStore::write_packets( PacketQueue &queue ) { + 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, queue.size() ); + int ret = this->writePacket( queued_packet ); + 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 ); + return packet_count; + } // end int VideoStore::write_packets( PacketQueue &queue ) { diff --git a/src/zm_videostore.h b/src/zm_videostore.h index d2b14ae2e..cf8168c06 100644 --- a/src/zm_videostore.h +++ b/src/zm_videostore.h @@ -19,6 +19,15 @@ class VideoStore; class VideoStore { private: +struct CodecData { + const int codec_id; + const char *codec_codec; + const char *codec_name; + const enum AVPixelFormat pix_fmt; + +}; +static struct CodecData codec_data[]; + Monitor *monitor; AVOutputFormat *out_format; AVFormatContext *oc; diff --git a/version b/version index 6367ac8f2..0be5d1204 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.31.39 +1.31.40 diff --git a/web/includes/Monitor.php b/web/includes/Monitor.php index a4f5f03db..942f25c87 100644 --- a/web/includes/Monitor.php +++ b/web/includes/Monitor.php @@ -15,7 +15,8 @@ private $defaults = array( 'Height' => null, 'Orientation' => null, 'AnalysisFPSLimit' => null, - 'OutputCodec' => 'h264', + 'OutputCodec' => '0', + 'Encoder' => 'auto', 'OutputContainer' => 'auto', 'ZoneCount' => 0, 'Triggers' => null, diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index 50aaad267..d00496f93 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -470,13 +470,21 @@ $videowriteropts = array( 'X264 Encode' => 1, 'H264 Camera Passthrough' => 2 ); -$videowriter_codecs = array( - '' => translate('Disabled'), +$videowriter_encoders = array( + '' => translate('Auto'), + 'h264_omx' => 'h264_omx', 'h264' => 'h264', 'mjpeg' => 'mjpeg', 'mpeg1' => 'mpeg1', 'mpeg2' => 'mpeg2', ); +$videowriter_codecs = array( + '0' => translate('Disabled'), + '220' => 'h264', + '8' => 'mjpeg', + '1' => 'mpeg1', + '2' => 'mpeg2', +); $videowriter_containers = array( '' => translate('Auto'), 'mp4' => 'mp4', @@ -609,6 +617,7 @@ if ( $tab != 'storage' ) { + @@ -912,6 +921,7 @@ if ( $monitor->Type() == 'Local' ) { OutputCodec() );?> + Encoder() );?> OutputContainer() );?> RecordAudio() ) { ?> checked="checked"/> From a19e6b619c293580b0639909196f33ca5e0134fd Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 28 Feb 2018 07:17:52 -0800 Subject: [PATCH 0118/2339] add Encoder to Monitors --- db/zm_update-1.31.40.sql | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 db/zm_update-1.31.40.sql diff --git a/db/zm_update-1.31.40.sql b/db/zm_update-1.31.40.sql new file mode 100644 index 000000000..66b98eb66 --- /dev/null +++ b/db/zm_update-1.31.40.sql @@ -0,0 +1,14 @@ +ALTER TABLE `Monitors` MODIFY `OutputCodec` int(10) UNSIGNED NOT NULL default 0; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Monitors' + AND column_name = 'Encoder' + ) > 0, +"SELECT 'Column Encoder already exists in Monitors'", +"ALTER TABLE `Monitors` ADD `Encoder` enum('auto','h264','h264_omx','mjpeg','mpeg1','mpeg2') AFTER `OutputCodec`" +)); + +PREPARE stmt FROM @s; +EXECUTE stmt; + From 646f0dd65ecbd4a553cfa67aaaf10b86fdd77c44 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 3 Mar 2018 13:31:55 -0800 Subject: [PATCH 0119/2339] fix merge --- src/zm_ffmpeg_camera.cpp | 303 --------------------------------------- src/zm_ffmpeg_input.cpp | 70 +-------- 2 files changed, 6 insertions(+), 367 deletions(-) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 58fd115b1..154e6fb37 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -131,15 +131,7 @@ int FfmpegCamera::PrimeCapture() { } int FfmpegCamera::PreCapture() { -<<<<<<< HEAD return 0; -======= - // If Reopen was called, then ffmpeg is closed and we need to reopen it. - if ( ! mCanCapture ) - return OpenFfmpeg(); - // Nothing to do here - return( 0 ); ->>>>>>> storageareas } int FfmpegCamera::Capture( ZMPacket &zm_packet ) { @@ -483,301 +475,6 @@ int FfmpegCamera::CloseFfmpeg() { } return 0; -<<<<<<< HEAD } // end int FfmpegCamera::CloseFfmpeg() -======= -} // end FfmpegCamera::Close - -//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]; - - 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 ); - Error( "Unable to read packet from stream %d: error %d \"%s\".", packet.stream_index, ret, errbuf ); - return -1; - } - - int keyframe = packet.flags & AV_PKT_FLAG_KEY; - dumpPacket(&packet); - - //Video recording - if ( recording.tv_sec ) { - - uint32_t last_event_id = monitor->GetLastEventId() ; - uint32_t video_writer_event_id = monitor->GetVideoWriterEventId(); - - if ( last_event_id != video_writer_event_id ) { - Debug(2, "Have change of event. last_event(%d), our current (%d)", last_event_id, video_writer_event_id ); - - if ( videoStore ) { - 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; - have_video_keyframe = false; - - monitor->SetVideoWriterEventId( 0 ); - } // end if videoStore - } // end if end of recording - - if ( last_event_id and ! videoStore ) { - //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 { - if ( mAudioStreamId >= 0 ) { - 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 - - if ( ! videoStore->open() ) { - delete videoStore; - videoStore = NULL; - - } else { - monitor->SetVideoWriterEventId( last_event_id ); - - // 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 ); - have_video_keyframe = true; - } 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; - have_video_keyframe = false; - monitor->SetVideoWriterEventId( 0 ); - } - - // 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 ( keyframe ) { - Debug(3, "Clearing queue"); - packetqueue.clearQueue( monitor->GetPreEventCount(), mVideoStreamId ); - packetqueue.queuePacket( &packet ); - } else if ( packetqueue.size() ) { - // it's a keyframe or we already have something in the queue - packetqueue.queuePacket( &packet ); - } - } else if ( packet.stream_index == mAudioStreamId ) { - // The following lines should ensure that the queue always begins with a video keyframe -//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 ); - } - } - } // end if recording or not - - if ( packet.stream_index == mVideoStreamId ) { - // only do decode if we have had a keyframe, should save a few cycles. - if ( have_video_keyframe || keyframe ) { - - 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; - } - have_video_keyframe = true; - } - } // end if keyframe or have_video_keyframe - - Debug(4, "about to decode video" ); - -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 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; - } -#if HAVE_AVUTIL_HWCONTEXT_H - if ( hwaccel ) { - ret = avcodec_receive_frame( mVideoCodecContext, hwFrame ); - 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 = av_hwframe_transfer_data(mRawFrame, hwFrame, 0); - if (ret < 0) { - av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); - Error( "Unable to transfer frame at frame %d: %s, continuing", frameCount, errbuf ); - zm_av_packet_unref( &packet ); - continue; - } - } else { -#endif - ret = avcodec_receive_frame( mVideoCodecContext, mRawFrame ); - if ( ret < 0 ) { - av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); - Warning( "Unable to receive frame %d: %s, continuing", frameCount, errbuf ); - zm_av_packet_unref( &packet ); - continue; - } - -#if HAVE_AVUTIL_HWCONTEXT_H - } -#endif - - 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 - - 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) { - Error("Unable to convert raw format %u to target format %u at frame %d", - mVideoCodecContext->pix_fmt, imagePixFormat, frameCount); - return -1; - } - - 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 - frameComplete = 1; - if ( videoStore ) { - if ( record_audio ) { - if ( have_video_keyframe ) { - 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(3, "Not recording audio yet because we don't have a video keyframe yet"); - } - } else { - Debug(4, "Not doing recording of audio packet" ); - } - } else { - Debug(4, "Have audio packet, but not recording atm" ); - } - zm_av_packet_unref( &packet ); - return 0; - } 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 - } // end if is video or audio or something else - - // 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 - - ->>>>>>> storageareas #endif // HAVE_LIBAVFORMAT diff --git a/src/zm_ffmpeg_input.cpp b/src/zm_ffmpeg_input.cpp index ed47cbd41..063e2eb46 100644 --- a/src/zm_ffmpeg_input.cpp +++ b/src/zm_ffmpeg_input.cpp @@ -135,77 +135,21 @@ AVFrame *FFmpeg_Input::get_frame( int stream_id, int frame_number ) { // Check for Connection failure. (ret == -110) ) { - Info( "av_read_frame returned %s.", av_make_error_string(ret).c_str() ); + Info("av_read_frame returned %s.", av_make_error_string(ret).c_str()); } else { - Error( "Unable to read packet from stream %d: error %d \"%s\".", packet.stream_index, ret, - av_make_error_string(ret).c_str() ); + Error("Unable to read packet from stream %d: error %d \"%s\".", packet.stream_index, ret, + av_make_error_string(ret).c_str()); } return NULL; } -<<<<<<< HEAD if ( ( stream_id < 0 ) || ( packet.stream_index != stream_id ) ) { Warning("Packet is not for our stream (%d)", packet.stream_index); return NULL; -======= - if ( (stream_id < 0 ) || ( packet.stream_index == stream_id ) ) { - Debug(3,"Packet is for our stream (%d)", packet.stream_index ); - - AVCodecContext *context = streams[packet.stream_index].context; - -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - ret = avcodec_send_packet( context, &packet ); - if ( ret < 0 ) { - av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); - Error( "Unable to send packet at frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf ); - zm_av_packet_unref( &packet ); - continue; - } else { - Debug(1, "Success getting a packet"); } -#if HAVE_AVUTIL_HWCONTEXT_H - if ( hwaccel ) { - ret = avcodec_receive_frame( context, hwFrame ); - if ( ret < 0 ) { - av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); - Error( "Unable to receive frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf ); - zm_av_packet_unref( &packet ); - continue; - } - ret = av_hwframe_transfer_data(frame, hwFrame, 0); - if (ret < 0) { - av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); - Error( "Unable to transfer frame at frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf ); - zm_av_packet_unref( &packet ); - continue; - } - } else { -#endif - Debug(1,"Getting a frame?"); - ret = avcodec_receive_frame( context, frame ); - if ( ret < 0 ) { - av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); - Error( "Unable to send packet at frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf ); - zm_av_packet_unref( &packet ); - continue; - } - -#if HAVE_AVUTIL_HWCONTEXT_H ->>>>>>> storageareas - } - -<<<<<<< HEAD - if ( ! zm_receive_frame( streams[packet.stream_index].context, frame, packet ) ) { + if ( ! zm_receive_frame(streams[packet.stream_index].context, frame, packet) ) { Error("Unable to get frame %d, continuing", streams[packet.stream_index].frame_count); -======= - frameComplete = 1; -# else - ret = zm_avcodec_decode_video(context, frame, &frameComplete, &packet); - if ( ret < 0 ) { - av_strerror(ret, errbuf, AV_ERROR_MAX_STRING_SIZE); - Error( "Unable to decode frame at frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf ); ->>>>>>> storageareas zm_av_packet_unref( &packet ); continue; } else { @@ -213,12 +157,10 @@ AVFrame *FFmpeg_Input::get_frame( int stream_id, int frame_number ) { streams[packet.stream_index].frame_count += 1; } - zm_av_packet_unref( &packet ); + zm_av_packet_unref(&packet); if ( frame_number == -1 ) break; } // end while frame_number > streams.frame_count return frame; -} // end AVFrame *FFmpeg_Input::get_frame - - +} // end AVFrame *FFmpeg_Input::get_frame From 2291816f4e3575ad6c299fcc3d8aa4aad428bc31 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 10 Mar 2018 10:12:12 -0500 Subject: [PATCH 0120/2339] fix memleak --- src/zm_monitor.cpp | 10 +++++----- src/zm_videostore.cpp | 5 ----- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 564779a0c..e7c6cae1e 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -605,11 +605,6 @@ bool Monitor::connect() { Monitor::~Monitor() { - if ( event_delete_thread ) { - event_delete_thread->join(); - delete event_delete_thread; - event_delete_thread = NULL; - } if ( timestamps ) { @@ -634,6 +629,11 @@ Monitor::~Monitor() { Info("%s: image_count:%d - Closing event %d, shutting down", name, image_count, event->Id() ); closeEvent(); } + if ( event_delete_thread ) { + event_delete_thread->join(); + delete event_delete_thread; + event_delete_thread = NULL; + } if ( deinterlacing_value == 4 ) { delete next_buffer.image; diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index a448b1ddc..767dca962 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -214,11 +214,6 @@ bool VideoStore::open() { } } // end if orientation } else { - /** Create a new frame to store the */ - if ( !(video_in_frame = zm_av_frame_alloc()) ) { - Error("Could not allocate video_in frame"); - return false; - } for ( unsigned int i = 0; i < sizeof(codec_data) / sizeof(*codec_data); i++ ) { if ( codec_data[i].codec_id != monitor->OutputCodec() ) continue; From 3ae9993975f9696784a5d4563200ea57aee41e5c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 16 Mar 2018 11:58:50 -0400 Subject: [PATCH 0121/2339] allow errors, and add a missing fi --- distros/ubuntu1604/zoneminder.postinst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/distros/ubuntu1604/zoneminder.postinst b/distros/ubuntu1604/zoneminder.postinst index d731b8764..605bdc193 100644 --- a/distros/ubuntu1604/zoneminder.postinst +++ b/distros/ubuntu1604/zoneminder.postinst @@ -1,6 +1,6 @@ #! /bin/sh -set -e +set +e if [ "$1" = "configure" ]; then @@ -56,6 +56,7 @@ if [ "$1" = "configure" ]; then echo "grant lock tables,alter,drop,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute 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,drop,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql + fi else echo 'NOTE: MySQL/MariaDB not running; please start mysql and run dpkg-reconfigure zoneminder when it is running.' From 3bfbae21e6296af5a4808f12c961b35b5beae377 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 14 Apr 2018 17:03:26 -0400 Subject: [PATCH 0122/2339] Use unsigned 64bit printouts --- src/zm_ffmpeg.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index 0652a6ac7..f33c8f880 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -441,18 +441,17 @@ void dumpPacket(AVPacket *pkt, const char *text) { char b[10240]; snprintf(b, sizeof(b), - " pts: %" PRId64 ", dts: %" PRId64 - ", data: %p, size: %d, stream_index: %d, flags: %04x, keyframe(%d) pos: %" PRId64 + " pts: %" PRIu64 ", dts: %" PRIu64 + ", size: %d, stream_index: %d, flags: %04x, keyframe(%d) pos: %" PRId64 ", duration: %" #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - PRId64 + PRIu64 #else "d" #endif "\n", pkt->pts, pkt->dts, - pkt->data, pkt->size, pkt->stream_index, pkt->flags, @@ -470,6 +469,5 @@ void zm_free_codec( AVCodecContext **ctx ) { avcodec_free_context(ctx); #endif *ctx = NULL; - audio_in_codec = NULL; } // end if } From 73239a0dba5c908f69969612c94f4964407f83ca Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 14 Apr 2018 17:03:45 -0400 Subject: [PATCH 0123/2339] If no progress in analysis, bail --- src/zm_monitor.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 3bf1dc1ea..aee8b6ee9 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1593,9 +1593,14 @@ bool Monitor::Analyse() { ZMPacket *snap; // Is it possible for snap->score to be ! -1? while ( ( snap = packetqueue->get_analysis_packet() ) && ( snap->score == -1 ) ) { - snap->lock(); unsigned int index = snap->image_index; Debug(2, "Analysis index (%d), last_Write(%d)", index, shared_data->last_write_index); + if ( index == shared_data->last_read_index ) { + Debug(2, "Returning because we are re-analyzing"); + return 0; + } + + snap->lock(); packets_processed += 1; if ( snap->image_index == -1 ) { From 0428d8687d4a4fae53547902f444c907c0b3d5b4 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 14 Apr 2018 17:04:00 -0400 Subject: [PATCH 0124/2339] put the ++ in front instead --- src/zm_packetqueue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index 292797f1c..8f36e0cd7 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -250,7 +250,7 @@ ZMPacket *zm_packetqueue::get_analysis_packet() { bool zm_packetqueue::increment_analysis_it( ) { // We do this instead of distance becuase distance will traverse the entire list in the worst case std::list::iterator next_it = analysis_it; - next_it ++; + ++ next_it; if ( next_it == pktQueue.end() ) { return false; } From cad5696b8e67c615b1dd1952abf29f3cb9912b0b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 14 Apr 2018 17:06:02 -0400 Subject: [PATCH 0125/2339] it's flush_codecs --- src/zm_videostore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 03d5b1799..41f94643f 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -549,7 +549,7 @@ VideoStore::~VideoStore() { if ( oc->pb ) { if ( ( video_out_ctx->codec_id != video_in_ctx->codec_id ) || audio_out_codec ) { Debug(2,"Different codecs between in and out"); - flush_output(); + flush_codecs(); } // end if buffers // Flush Queues From 1e3c3643c990a7890921e665eb1efc2ebc038c5f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 14 Apr 2018 17:25:44 -0400 Subject: [PATCH 0126/2339] Fix mysql signed bug by casting to signed --- db/triggers.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/triggers.sql b/db/triggers.sql index c03905201..2f13be435 100644 --- a/db/triggers.sql +++ b/db/triggers.sql @@ -203,7 +203,7 @@ CREATE TRIGGER event_delete_trigger BEFORE DELETE ON Events FOR EACH ROW BEGIN IF ( OLD.DiskSpace ) THEN - UPDATE Storage SET DiskSpace = COALESCE(DiskSpace,0) - OLD.DiskSpace WHERE Id = OLD.StorageId; + UPDATE Storage SET DiskSpace = COALESCE(DiskSpace,0) - CAST(OLD.DiskSpace AS SIGNED) WHERE Id = OLD.StorageId; END IF; DELETE FROM Events_Hour WHERE EventId=OLD.Id; DELETE FROM Events_Day WHERE EventId=OLD.Id; From 0116a3aaca09b750fab49d688b2bb46cb2996e92 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 10 May 2018 17:46:46 -0400 Subject: [PATCH 0127/2339] ad zm_group? --- src/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index eb68265c2..2c0ffd4ab 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,7 +4,9 @@ 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, zmu, zms etc) -set(ZM_BIN_SRC_FILES zm_analysis_thread.cpp 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_eventstream.cpp zm_exception.cpp zm_file_camera.cpp zm_ffmpeg_camera.cpp zm_group.cpp zm_image.cpp zm_jpeg.cpp zm_libvlc_camera.cpp zm_local_camera.cpp zm_monitor.cpp zm_monitorstream.cpp zm_ffmpeg.cpp zm_ffmpeg_input.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_nvsocket.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_swscale.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 zm_storage.cpp) +set(ZM_BIN_SRC_FILES + zm_analysis_thread.cpp + 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_eventstream.cpp zm_exception.cpp zm_file_camera.cpp zm_ffmpeg_camera.cpp zm_group.cpp zm_image.cpp zm_jpeg.cpp zm_libvlc_camera.cpp zm_local_camera.cpp zm_monitor.cpp zm_monitorstream.cpp zm_ffmpeg.cpp zm_ffmpeg_input.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_nvsocket.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_swscale.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 zm_storage.cpp) # A fix for cmake recompiling the source files for every target. add_library(zm STATIC ${ZM_BIN_SRC_FILES}) From d3c95ea14432c6b65a49e5504b09ef4e2127b052 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 12 May 2018 19:44:20 -0400 Subject: [PATCH 0128/2339] fix merges --- src/zm_camera.cpp | 2 -- src/zm_event.cpp | 2 +- src/zmc.cpp | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/zm_camera.cpp b/src/zm_camera.cpp index cd69240c2..43e97f26a 100644 --- a/src/zm_camera.cpp +++ b/src/zm_camera.cpp @@ -20,7 +20,6 @@ #include "zm.h" #include "zm_camera.h" -<<<<<<< HEAD Camera::Camera( unsigned int p_monitor_id, SourceType p_type, @@ -52,7 +51,6 @@ Camera::Camera( mVideoCodecContext(NULL), mAudioCodecContext(NULL), video_stream(NULL), - record_audio(p_record_audio), bytes(0) { pixels = width * height; diff --git a/src/zm_event.cpp b/src/zm_event.cpp index d9ba31752..f80e0b9d9 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -203,7 +203,7 @@ Event::Event( } } - snprintf(video_name, sizeof(video_name), "%llu-%s.%s", id, "video", container.c_str()); + snprintf(video_name, sizeof(video_name), "%" PRIu64 "-%s.%s", id, "video", container.c_str()); snprintf(video_file, sizeof(video_file), staticConfig.video_file_format, path.c_str(), video_name); Debug(1,"Writing video file to %s", video_file); Camera * camera = monitor->getCamera(); diff --git a/src/zmc.cpp b/src/zmc.cpp index 22c8a809e..cf0f678b5 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -267,7 +267,6 @@ int main(int argc, char *argv[]) { AnalysisThread **analysis_threads = new AnalysisThread *[n_monitors]; int *capture_delays = new int[n_monitors]; int *alarm_capture_delays = new int[n_monitors]; - int *next_delays = new int[n_monitors]; struct timeval * last_capture_times = new struct timeval[n_monitors]; for ( int i = 0; i < n_monitors; i++ ) { last_capture_times[i].tv_sec = last_capture_times[i].tv_usec = 0; From b2c9c2961d70a0ef5da08c01d8c27a9e1020d9a2 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 11 Aug 2018 18:49:30 -0400 Subject: [PATCH 0129/2339] spacing, code style, remove useless debug logging --- src/zm_event.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 868fd8971..0f7c842d4 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -199,6 +199,7 @@ Event::Event( /* Save as video */ if ( monitor->GetOptVideoWriter() != 0 ) { + Debug(2,"Video writer was %d", monitor->GetOptVideoWriter()); std::string container = monitor->OutputContainer(); if ( container == "auto" || container == "" ) { if ( monitor->OutputCodec() == AV_CODEC_ID_H264 ) { @@ -234,6 +235,7 @@ Event::~Event() { /* Close the video file */ if ( videoStore ) { + Debug(2,"Deleting video store"); delete videoStore; videoStore = NULL; } @@ -463,7 +465,8 @@ void Event::AddFramesInternal(int n_frames, int start_frame, Image **images, str } int sql_len = strlen(sql); - snprintf(sql+sql_len, sizeof(sql)-sql_len, "( %" PRIu64 ", %d, from_unixtime(%ld), %s%ld.%02ld ), ", id, frames, timestamps[i]->tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec); + snprintf(sql+sql_len, sizeof(sql)-sql_len, "( %" PRIu64 ", %d, from_unixtime(%ld), %s%ld.%02ld ), ", + id, frames, timestamps[i]->tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec); frameCount++; } // end foreach frame @@ -472,7 +475,7 @@ void Event::AddFramesInternal(int n_frames, int start_frame, Image **images, str Debug(1, "Adding %d/%d frames to DB", frameCount, n_frames); *(sql+strlen(sql)-2) = '\0'; db_mutex.lock(); - if ( mysql_query( &dbconn, sql ) ) { + if ( mysql_query(&dbconn, sql) ) { Error("Can't insert frames: %s, sql was (%s)", mysql_error(&dbconn), sql); } db_mutex.unlock(); @@ -482,7 +485,7 @@ void Event::AddFramesInternal(int n_frames, int start_frame, Image **images, str } } -void Event::AddPacket( ZMPacket *packet, int score, Image *alarm_image ) { +void Event::AddPacket(ZMPacket *packet, int score, Image *alarm_image) { have_video_keyframe = have_video_keyframe || ( ( packet->codec_type == AVMEDIA_TYPE_VIDEO ) && packet->keyframe ); if ( videoStore ) { @@ -492,8 +495,6 @@ void Event::AddPacket( ZMPacket *packet, int score, Image *alarm_image ) { Debug(2, "No video keyframe yet, not writing"); } //FIXME if it fails, we should write a jpeg - } else { - Debug(2,"AddPacket but no videostore?!"); } if ( have_video_keyframe && ( packet->codec_type == AVMEDIA_TYPE_VIDEO ) ) { AddFrame(packet->image, *packet->timestamp, score, alarm_image); From 4297d39df686e1c0abeb29287184ec2d74ae350f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 11 Aug 2018 18:49:48 -0400 Subject: [PATCH 0130/2339] spacing, code style, remove useless debug logging --- src/zm_monitor.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index d08c155e9..02b6f337d 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -2420,12 +2420,12 @@ bool Monitor::closeEvent() { if ( function == RECORD || function == MOCORD ) { gettimeofday(&(event->EndTime()), NULL); } +#if 0 if ( event_delete_thread ) { event_delete_thread->join(); delete event_delete_thread; event_delete_thread = NULL; } -#if 0 event_delete_thread = new std::thread([](Event *event) { Event * e = event; event = NULL; @@ -2691,14 +2691,15 @@ void Monitor::get_ref_image() { ( shared_data->last_write_time == 0 ) && ! zm_terminate ) { - Warning( "Waiting for capture daemon lastwriteindex(%d) lastwritetime(%d)", shared_data->last_write_index, shared_data->last_write_time ); - usleep( 50000 ); + Info("Waiting for capture daemon lastwriteindex(%d) lastwritetime(%d)", + shared_data->last_write_index, shared_data->last_write_time); + usleep(50000); } if ( zm_terminate ) return; int last_write_index = shared_data->last_write_index ; - Warning("Waiting for capture daemon unlock"); + Debug(2,"Waiting for capture daemon unlock"); image_buffer[last_write_index].mutex.lock(); ref_image.Assign(width, height, camera->Colours(), camera->SubpixelOrder(), image_buffer[last_write_index].image->Buffer(), camera->ImageSize()); image_buffer[last_write_index].mutex.unlock(); From 4670a7f26bfa24db8dd9a3dfbc1b3d4175eab9f5 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 13 Aug 2018 10:01:04 -0400 Subject: [PATCH 0131/2339] move variables into deeper block --- src/zm_logger.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/zm_logger.cpp b/src/zm_logger.cpp index a42f79d19..3c265b3fa 100644 --- a/src/zm_logger.cpp +++ b/src/zm_logger.cpp @@ -533,13 +533,15 @@ void Logger::logPrint( bool hex, const char * const filepath, const int line, co } *syslogEnd = '\0'; if ( level <= mDatabaseLevel ) { - char sql[ZM_SQL_MED_BUFSIZ]; - char escapedString[(strlen(syslogStart)*2)+1]; - if ( ! db_mutex.trylock() ) { - mysql_real_escape_string( &dbconn, escapedString, syslogStart, strlen(syslogStart) ); + if ( !db_mutex.trylock() ) { + char sql[ZM_SQL_MED_BUFSIZ]; + char escapedString[(strlen(syslogStart)*2)+1]; + mysql_real_escape_string(&dbconn, escapedString, syslogStart, strlen(syslogStart)); - snprintf( sql, sizeof(sql), "insert into Logs ( TimeKey, Component, ServerId, Pid, Level, Code, Message, File, Line ) values ( %ld.%06ld, '%s', %d, %d, %d, '%s', '%s', '%s', %d )", timeVal.tv_sec, timeVal.tv_usec, mId.c_str(), staticConfig.SERVER_ID, tid, level, classString, escapedString, file, line ); + snprintf(sql, sizeof(sql), + "insert into Logs ( TimeKey, Component, ServerId, Pid, Level, Code, Message, File, Line ) values ( %ld.%06ld, '%s', %d, %d, %d, '%s', '%s', '%s', %d )", + timeVal.tv_sec, timeVal.tv_usec, mId.c_str(), staticConfig.SERVER_ID, tid, level, classString, escapedString, file, line ); if ( mysql_query(&dbconn, sql) ) { Level tempDatabaseLevel = mDatabaseLevel; databaseLevel(NOLOG); From 59b01601446f5c34dd5b9e7aec48338857c09b9a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 13 Aug 2018 10:01:16 -0400 Subject: [PATCH 0132/2339] use ++it instead of it++ --- src/zm_packetqueue.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index 8f36e0cd7..23c8530fa 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -97,7 +97,7 @@ ZMPacket* zm_packetqueue::popPacket( ) { ZMPacket *packet = pktQueue.front(); if ( *analysis_it == packet ) - analysis_it ++; + ++analysis_it; pktQueue.pop_front(); if ( packet->codec_type == AVMEDIA_TYPE_VIDEO ) { @@ -164,7 +164,7 @@ unsigned int zm_packetqueue::clearQueue( unsigned int frames_to_keep, int stream } if ( it != pktQueue.rend() ) { // We want to keep this packet, so advance to the next - it ++; + ++it; packets_to_delete--; } int delete_count = 0; From 1016096a00e01337d31a82e1d8588bcd731793c9 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 13 Aug 2018 10:01:27 -0400 Subject: [PATCH 0133/2339] spacing --- src/zm_stream.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/zm_stream.cpp b/src/zm_stream.cpp index f911f2c78..effc534d3 100644 --- a/src/zm_stream.cpp +++ b/src/zm_stream.cpp @@ -212,11 +212,11 @@ Image *StreamBase::prepareImage( Image *image ) { Debug( 3, "Cropping to %d,%d -> %d,%d", last_crop.LoX(), last_crop.LoY(), last_crop.HiX(), last_crop.HiY() ); if ( !image_copied ) { static Image copy_image; - copy_image.Assign( *image ); + copy_image.Assign(*image); image = ©_image; image_copied = true; } - image->Crop( last_crop ); + image->Crop(last_crop); } last_scale = scale; last_zoom = zoom; From 5b1f8fbd7119f79b331ca5eaec332d1f6c7598ef Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 13 Aug 2018 10:01:39 -0400 Subject: [PATCH 0134/2339] initialize more vars in constructor --- src/zm_videostore.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index b0303faa1..e1b8a008e 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -48,14 +48,19 @@ VideoStore::VideoStore( monitor = p_monitor; video_in_stream = p_video_in_stream; + video_in_stream_index = -1; audio_in_stream = p_audio_in_stream; + audio_in_stream_index = -1; filename = filename_in; format = format_in; packets_written = 0; frame_count = 0; in_frame = NULL; + video_in_frame = NULL; + video_in_ctx = NULL; + video_out_ctx = NULL; video_out_codec = NULL; video_out_stream = NULL; @@ -64,6 +69,8 @@ VideoStore::VideoStore( audio_in_codec = NULL; audio_in_ctx = NULL; audio_out_stream = NULL; + audio_out_ctx = NULL; + out_frame = NULL; #ifdef HAVE_LIBAVRESAMPLE resample_ctx = NULL; @@ -73,6 +80,9 @@ VideoStore::VideoStore( video_start_pts = 0; audio_next_pts = 0; audio_next_dts = 0; + out_format = NULL; + oc = NULL; + ret = 0; } // VideoStore::VideoStore bool VideoStore::open() { From 96a1ac14e8f65daac7aed5b051f91ac3d48b91d1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 17 Aug 2018 16:02:40 -0400 Subject: [PATCH 0135/2339] Don't do all the event notes stuff if notes is empty --- src/zm_event.cpp | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 0f7c842d4..9d02d0d05 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -190,6 +190,7 @@ Event::Event( else Error("Can't fopen %s: %s", id_file.c_str(), strerror(errno)); } // deep storage or not + Debug(2,"Created event %d at %s", id, path.c_str()); last_db_frame = 0; @@ -275,16 +276,20 @@ Event::~Event() { } // Event::~Event() void Event::createNotes(std::string ¬es) { - notes.clear(); - for ( StringSetMap::const_iterator mapIter = noteSetMap.begin(); mapIter != noteSetMap.end(); ++mapIter ) { - notes += mapIter->first; - notes += ": "; - const StringSet &stringSet = mapIter->second; - for ( StringSet::const_iterator setIter = stringSet.begin(); setIter != stringSet.end(); ++setIter ) { - if ( setIter != stringSet.begin() ) - notes += ", "; - notes += *setIter; + if ( !notes.empty() ) { + notes.clear(); + for ( StringSetMap::const_iterator mapIter = noteSetMap.begin(); mapIter != noteSetMap.end(); ++mapIter ) { + notes += mapIter->first; + notes += ": "; + const StringSet &stringSet = mapIter->second; + for ( StringSet::const_iterator setIter = stringSet.begin(); setIter != stringSet.end(); ++setIter ) { + if ( setIter != stringSet.begin() ) + notes += ", "; + notes += *setIter; + } } + } else { + notes = ""; } } @@ -307,14 +312,14 @@ Debug(3, "Writing image to %s", event_file); return rc; } // end Event::WriteFrameImage( Image *image, struct timeval timestamp, const char *event_file, bool alarm_frame ) -bool Event::WritePacket( ZMPacket &packet ) { +bool Event::WritePacket(ZMPacket &packet) { - if ( videoStore->writePacket( &packet ) < 0 ) + if ( videoStore->writePacket(&packet) < 0 ) return false; return true; } -void Event::updateNotes( const StringSetMap &newNoteSetMap ) { +void Event::updateNotes(const StringSetMap &newNoteSetMap) { bool update = false; //Info( "Checking notes, %d <> %d", noteSetMap.size(), newNoteSetMap.size() ); @@ -328,19 +333,19 @@ void Event::updateNotes( const StringSetMap &newNoteSetMap ) { const StringSet &newNoteSet = newNoteSetMapIter->second; //Info( "Got %d new strings", newNoteSet.size() ); if ( newNoteSet.size() > 0 ) { - StringSetMap::iterator noteSetMapIter = noteSetMap.find( newNoteGroup ); + StringSetMap::iterator noteSetMapIter = noteSetMap.find(newNoteGroup); if ( noteSetMapIter == noteSetMap.end() ) { //Info( "Can't find note group %s, copying %d strings", newNoteGroup.c_str(), newNoteSet.size() ); - noteSetMap.insert( StringSetMap::value_type( newNoteGroup, newNoteSet ) ); + noteSetMap.insert(StringSetMap::value_type(newNoteGroup, newNoteSet)); update = true; } else { StringSet ¬eSet = noteSetMapIter->second; //Info( "Found note group %s, got %d strings", newNoteGroup.c_str(), newNoteSet.size() ); for ( StringSet::const_iterator newNoteSetIter = newNoteSet.begin(); newNoteSetIter != newNoteSet.end(); ++newNoteSetIter ) { const std::string &newNote = *newNoteSetIter; - StringSet::iterator noteSetIter = noteSet.find( newNote ); + StringSet::iterator noteSetIter = noteSet.find(newNote); if ( noteSetIter == noteSet.end() ) { - noteSet.insert( newNote ); + noteSet.insert(newNote); update = true; } } // end for @@ -352,9 +357,9 @@ void Event::updateNotes( const StringSetMap &newNoteSetMap ) { if ( update ) { std::string notes; - createNotes( notes ); + createNotes(notes); - Debug( 2, "Updating notes for event %d, '%s'", id, notes.c_str() ); + Debug(2, "Updating notes for event %d, '%s'", id, notes.c_str()); static char sql[ZM_SQL_MED_BUFSIZ]; #if USE_PREPARED_SQL static MYSQL_STMT *stmt = 0; From 376e15b76386dfaf71e70720e4c5b60acca1e780 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 17 Aug 2018 16:04:12 -0400 Subject: [PATCH 0136/2339] trylock was interesting for debugging, but really logging should wait for the lock --- src/zm_logger.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/zm_logger.cpp b/src/zm_logger.cpp index a42f79d19..148ba31c0 100644 --- a/src/zm_logger.cpp +++ b/src/zm_logger.cpp @@ -536,7 +536,8 @@ void Logger::logPrint( bool hex, const char * const filepath, const int line, co char sql[ZM_SQL_MED_BUFSIZ]; char escapedString[(strlen(syslogStart)*2)+1]; - if ( ! db_mutex.trylock() ) { + //if ( ! db_mutex.trylock() ) { + db_mutex.lock(); mysql_real_escape_string( &dbconn, escapedString, syslogStart, strlen(syslogStart) ); snprintf( sql, sizeof(sql), "insert into Logs ( TimeKey, Component, ServerId, Pid, Level, Code, Message, File, Line ) values ( %ld.%06ld, '%s', %d, %d, %d, '%s', '%s', '%s', %d )", timeVal.tv_sec, timeVal.tv_usec, mId.c_str(), staticConfig.SERVER_ID, tid, level, classString, escapedString, file, line ); @@ -547,12 +548,12 @@ void Logger::logPrint( bool hex, const char * const filepath, const int line, co databaseLevel(tempDatabaseLevel); } db_mutex.unlock(); - } else { - Level tempDatabaseLevel = mDatabaseLevel; - databaseLevel(NOLOG); - Error("Can't insert log entry: sql(%s) error(db is locked)", logString); - databaseLevel(tempDatabaseLevel); - } + ///} else { + ///Level tempDatabaseLevel = mDatabaseLevel; + ///databaseLevel(NOLOG); + ///Error("Can't insert log entry: sql(%s) error(db is locked)", logString); + ///databaseLevel(tempDatabaseLevel); + ///} } if ( level <= mSyslogLevel ) { int priority = smSyslogPriorities[level]; From 53eae61883b5ca31ca295fc615b79b88d106225d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 17 Aug 2018 16:05:02 -0400 Subject: [PATCH 0137/2339] Mostly spacing, but simplified logic removing assumption that local cameras give keyframes. They might not in future. --- src/zm_monitor.cpp | 45 +++++++++++++++++++-------------------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 02b6f337d..1f806b417 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -556,8 +556,6 @@ void Monitor::Load(MYSQL_ROW dbrow, bool load_zones=true, Purpose p = QUERY) { this->AddPrivacyBitmask(zones); // maybe unneeded - storage = new Storage(storage_id); - Debug(1, "Storage path: %s", storage->Path()); // Should maybe store this for later use char monitor_dir[PATH_MAX] = ""; snprintf(monitor_dir, sizeof(monitor_dir), "%s/%d", storage->Path(), id); @@ -851,7 +849,7 @@ bool Monitor::connect() { } if ( purpose == CAPTURE ) { - memset( mem_ptr, 0, mem_size ); + memset(mem_ptr, 0, mem_size); shared_data->size = sizeof(SharedData); Debug( 1, "shared.size=%d", shared_data->size ); shared_data->active = enabled; @@ -2223,8 +2221,8 @@ int Monitor::Capture() { } else if ( captureResult > 0 ) { // Analysis thread will take care of consuming and emptying the packets. - Debug(2, "Have packet (%d) != videostream_id:(%d) q.vpktcount(%d) event?(%d) ", - packet->packet.stream_index, video_stream_id, packetqueue->video_packet_count, ( event ? 1 : 0 ) ); + Debug(2, "Have packet (%d) ?= videostream_id:(%d) q.vpktcount(%d) event?(%d) ", + packet->packet.stream_index, video_stream_id, packetqueue->video_packet_count, ( event ? 1 : 0 ) ); if ( packet->packet.stream_index != video_stream_id ) { Debug(2, "Have audio packet (%d) != videostream_id:(%d) q.vpktcount(%d) event?(%d) ", @@ -2263,23 +2261,18 @@ int Monitor::Capture() { packet->get_image(); } // Have an av_packet, - Debug(2,"Before mutex lock"); - mutex.lock(); - if ( packetqueue->video_packet_count || packet->keyframe || event ) { - Debug(2, "Have video packet for index (%d)", index ); - packetqueue->queuePacket( packet ); - } else { - Debug(2, "Not queiing video packet for index (%d)", index ); - } - mutex.unlock(); - } else { - mutex.lock(); - // Non-avpackets are all keyframes. - Debug(2, "Queueing decoded video packet"); - packetqueue->queuePacket(packet); - mutex.unlock(); } + Debug(2,"Before mutex lock"); + mutex.lock(); + if ( packetqueue->video_packet_count || packet->keyframe || event ) { + Debug(2, "Have video packet for index (%d)", index); + packetqueue->queuePacket(packet); + } else { + Debug(2, "Not queuing video packet for index (%d)", index); + } + mutex.unlock(); + /* Deinterlacing */ if ( deinterlacing_value ) { if ( deinterlacing_value == 1 ) { @@ -2289,9 +2282,9 @@ int Monitor::Capture() { } else if ( deinterlacing_value == 3 ) { capture_image->Deinterlace_Blend(); } else if ( deinterlacing_value == 4 ) { - capture_image->Deinterlace_4Field( next_buffer.image, (deinterlacing>>8)&0xff ); + capture_image->Deinterlace_4Field(next_buffer.image, (deinterlacing>>8)&0xff); } else if ( deinterlacing_value == 5 ) { - capture_image->Deinterlace_Blend_CustomRatio( (deinterlacing>>8)&0xff ); + capture_image->Deinterlace_Blend_CustomRatio((deinterlacing>>8)&0xff); } } @@ -2303,20 +2296,20 @@ int Monitor::Capture() { case ROTATE_90 : case ROTATE_180 : case ROTATE_270 : - capture_image->Rotate( (orientation-1)*90 ); + capture_image->Rotate((orientation-1)*90); break; case FLIP_HORI : case FLIP_VERT : - capture_image->Flip( orientation==FLIP_HORI ); + capture_image->Flip(orientation==FLIP_HORI); break; } } // end if have rotation if ( privacy_bitmask ) - capture_image->MaskPrivacy( privacy_bitmask ); + capture_image->MaskPrivacy(privacy_bitmask); if ( config.timestamp_on_capture ) { - TimestampImage( capture_image, packet->timestamp ); + TimestampImage(capture_image, packet->timestamp); } shared_data->signal = signal_check_points ? CheckSignal(capture_image) : true; From abb6d4f7d96c49ff78011bc5d2c3ff5956cf642d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 17 Aug 2018 16:06:03 -0400 Subject: [PATCH 0138/2339] fixup some logic, remove redundant call to clearQueue, increase first_video_packet_index when clearing video frames from front in queuePacket --- src/zm_packetqueue.cpp | 70 ++++++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 26 deletions(-) diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index 8f36e0cd7..79798bbc1 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -33,23 +33,32 @@ zm_packetqueue::~zm_packetqueue() { clearQueue(); } +/* Enqueues the given packet. Will maintain the analysis_it pointer and image packet counts. + * If we have reached our max image packet count, it will pop off as many packets as are needed. + * Thus it will ensure that the same packet never gets queued twice. + */ + bool zm_packetqueue::queuePacket( ZMPacket* zm_packet ) { if ( zm_packet->image_index != -1 ) { // If we can never queue the same packet, then they can never go past if ( zm_packet->image_index == first_video_packet_index ) { - Debug(2, "queuing packet that is already on the queue(%d)", zm_packet->image_index ); + Debug(2, "queuing packet that is already on the queue(%d)", zm_packet->image_index); ZMPacket *p = NULL;; while ( pktQueue.size() && (p = pktQueue.front()) && ( p->image_index != zm_packet->image_index ) ) { if ( ( analysis_it != pktQueue.end() ) && ( *analysis_it == p ) ) { - Debug(2, "Increasing analysis_it"); + Debug(2, "Increasing analysis_it, meaning analysis is not keeping up"); ++analysis_it; } pktQueue.pop_front(); if ( p->codec_type == AVMEDIA_TYPE_VIDEO ) { - Debug(2, "Descreasing video_packet_count (%d)", video_packet_count); + Debug(2, "Decreasing video_packet_count (%d), popped (%d)", + video_packet_count, p->image_index); video_packet_count -= 1; + first_video_packet_index += 1; + first_video_packet_index %= max_video_packet_count; + } else { Debug(2, "Deleteing audio frame(%d)", p->image_index); delete p; @@ -66,7 +75,14 @@ bool zm_packetqueue::queuePacket( ZMPacket* zm_packet ) { first_video_packet_index %= max_video_packet_count; } else { - Error("SHould have found the packet!"); + Error("SHould have found the packet! front packet index was %d, new packet index is %d ", + p->image_index, zm_packet->image_index + ); + } + if ( analysis_it == pktQueue.end() ) { + // Analsys_it should only point to end when queue is empty + Debug(2,"pointing analysis_it to begining"); + analysis_it = pktQueue.begin(); } } else if ( first_video_packet_index == -1 ) { // Initialize the first_video_packet indicator @@ -74,18 +90,17 @@ bool zm_packetqueue::queuePacket( ZMPacket* zm_packet ) { } // end if } // end if queuing a video packet - pktQueue.push_back( zm_packet ); + pktQueue.push_back(zm_packet); + +#if 0 + // This code should not be neccessary. Taken care of by the above code that ensure that no packet appears twice if ( zm_packet->codec_type == AVMEDIA_TYPE_VIDEO ) { video_packet_count += 1; if ( video_packet_count >= max_video_packet_count ) - clearQueue( max_video_packet_count, video_stream_id ); + clearQueue(max_video_packet_count, video_stream_id); } +#endif - if ( analysis_it == pktQueue.end() ) { - // ANalsys_it should only point to end when queue it empty - Debug(2,"pointing analysis_it to begining"); - analysis_it = pktQueue.begin(); - } return true; } // end bool zm_packetqueue::queuePacket(ZMPacket* zm_packet) @@ -104,6 +119,7 @@ ZMPacket* zm_packetqueue::popPacket( ) { video_packet_count -= 1; if ( video_packet_count ) { // There is another video packet, so it must be the next one + Debug(2,"Incrementing first video packet index was (%d)", first_video_packet_index); first_video_packet_index += 1; first_video_packet_index %= max_video_packet_count; } else { @@ -116,10 +132,9 @@ ZMPacket* zm_packetqueue::popPacket( ) { unsigned int zm_packetqueue::clearQueue( unsigned int frames_to_keep, int stream_id ) { - Debug(3, "Clearing all but %d frames, queue has %d", frames_to_keep, pktQueue.size() ); + Debug(3, "Clearing all but %d frames, queue has %d", frames_to_keep, pktQueue.size()); if ( pktQueue.empty() ) { - Debug(3, "Queue is empty"); return 0; } frames_to_keep += 1; @@ -131,12 +146,12 @@ unsigned int zm_packetqueue::clearQueue( unsigned int frames_to_keep, int stream std::list::reverse_iterator it; ZMPacket *packet = NULL; - for ( it = pktQueue.rbegin(); it != pktQueue.rend() && frames_to_keep; ++it ) { + for ( it = pktQueue.rbegin(); frames_to_keep && (it != pktQueue.rend()); ++it ) { ZMPacket *zm_packet = *it; AVPacket *av_packet = &(zm_packet->packet); - Debug(4, "Looking at packet with stream index (%d) with keyframe(%d), frames_to_keep is (%d)", - av_packet->stream_index, zm_packet->keyframe, frames_to_keep ); + Debug(4, "Looking at packet with stream index (%d) with keyframe(%d), Image_index(%d) frames_to_keep is (%d)", + av_packet->stream_index, zm_packet->keyframe, zm_packet->image_index, frames_to_keep ); // Want frames_to_keep video keyframes. Otherwise, we may not have enough if ( av_packet->stream_index == stream_id ) { @@ -145,38 +160,41 @@ unsigned int zm_packetqueue::clearQueue( unsigned int frames_to_keep, int stream } } - // Make sure we start on a keyframe + // Make sure we start on a keyframe for ( ; it != pktQueue.rend(); ++it ) { ZMPacket *zm_packet = *it; AVPacket *av_packet = &(zm_packet->packet); - Debug(5, "Looking for keyframe at packet with stream index (%d) with keyframe (%d), frames_to_keep is (%d)", av_packet->stream_index, ( av_packet->flags & AV_PKT_FLAG_KEY ), frames_to_keep ); + Debug(5, "Looking for keyframe at packet with stream index (%d) with keyframe (%d), image_index(%d) frames_to_keep is (%d)", + av_packet->stream_index, ( av_packet->flags & AV_PKT_FLAG_KEY ), zm_packet->image_index, frames_to_keep ); // Want frames_to_keep video keyframes. Otherwise, we may not have enough if ( ( av_packet->stream_index == stream_id) && ( av_packet->flags & AV_PKT_FLAG_KEY ) ) { - Debug(4, "Found keyframe at packet with stream index (%d) with keyframe (%d), frames_to_keep is (%d)", av_packet->stream_index, ( av_packet->flags & AV_PKT_FLAG_KEY ), frames_to_keep ); + Debug(4, "Found keyframe at packet with stream index (%d) with keyframe (%d), frames_to_keep is (%d)", + av_packet->stream_index, ( av_packet->flags & AV_PKT_FLAG_KEY ), frames_to_keep ); break; } packets_to_delete--; } if ( frames_to_keep ) { - Debug(3, "Hit end of queue, still need (%d) video frames", frames_to_keep ); + Debug(3, "Hit end of queue, still need (%d) video frames", frames_to_keep); } if ( it != pktQueue.rend() ) { // We want to keep this packet, so advance to the next - it ++; + ++it; packets_to_delete--; } int delete_count = 0; if ( packets_to_delete > 0 ) { - Debug(4, "Deleting packets from the front, count is (%d)", packets_to_delete ); + Debug(4, "Deleting packets from the front, count is (%d)", packets_to_delete); while ( --packets_to_delete ) { - Debug(4, "Deleting a packet from the front, count is (%d), queue size is %d", delete_count, pktQueue.size() ); + Debug(4, "Deleting a packet from the front, count is (%d), queue size is %d", + delete_count, pktQueue.size()); packet = pktQueue.front(); if ( *analysis_it == packet ) - analysis_it ++; + ++analysis_it; if ( packet->codec_type == AVMEDIA_TYPE_VIDEO ) { video_packet_count -= 1; if ( video_packet_count ) { @@ -204,14 +222,14 @@ unsigned int zm_packetqueue::clearQueue( unsigned int frames_to_keep, int stream } #endif - Debug(3, "Deleted packets, resulting size is %d", pktQueue.size() ); + Debug(3, "Deleted packets, resulting size is %d", pktQueue.size()); return delete_count; } // end unsigned int zm_packetqueue::clearQueue( unsigned int frames_to_keep, int stream_id ) void zm_packetqueue::clearQueue() { mutex.lock(); ZMPacket *packet = NULL; - while(!pktQueue.empty()) { + while ( !pktQueue.empty() ) { packet = pktQueue.front(); pktQueue.pop_front(); if ( packet->image_index == -1 ) From db560a5540c721d2bb7450c3c2514376dc9eed42 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 17 Aug 2018 16:06:30 -0400 Subject: [PATCH 0139/2339] Don't do delay calcs if delay is empty, result will always be negative --- src/zmc.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/zmc.cpp b/src/zmc.cpp index dbe317731..48aed7bcb 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -318,13 +318,18 @@ int main(int argc, char *argv[]) { gettimeofday(&now, NULL); // capture_delay is the amount of time we should sleep to achieve the desired framerate. - if ( last_capture_times[i].tv_sec ) { + int delay = monitors[i]->GetState() == Monitor::ALARM ? alarm_capture_delays[i] : capture_delays[i]; + if ( delay && last_capture_times[i].tv_sec ) { int sleep_time; DELTA_TIMEVAL(delta_time, now, last_capture_times[i], DT_PREC_3); - int delay = monitors[i]->GetState() == Monitor::ALARM ? alarm_capture_delays[i] : capture_delays[i]; sleep_time = delay - delta_time.delta; - Debug(3, "Sleep time is %d from now:%d.%d last:%d.%d delay: %d", sleep_time, now.tv_sec, now.tv_usec, last_capture_times[i].tv_sec, last_capture_times[i].tv_usec, delay ); + Debug(3, "Sleep time is %d from now:%d.%d last:%d.%d delay: %d", + sleep_time, + now.tv_sec, now.tv_usec, + last_capture_times[i].tv_sec, last_capture_times[i].tv_usec, + delay + ); if ( sleep_time < 0 ) sleep_time = 0; From fd550c13abc08cbe7dabc6b151a1e7325e1c86ae Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 31 Aug 2018 19:12:05 -0400 Subject: [PATCH 0140/2339] fix merge --- scripts/ZoneMinder/lib/ZoneMinder/Logger.pm | 4 ---- src/zm_camera.h | 3 +-- src/zm_event.cpp | 5 ----- 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm index 7875bb376..e474335fb 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm @@ -663,11 +663,7 @@ sub Dump { sub debug { my $log = shift; -<<<<<<< HEAD - $log->logPrint(DEBUG, @_); -======= $log->logPrint(DEBUG, @_, caller); ->>>>>>> storageareas } sub Debug( @ ) { diff --git a/src/zm_camera.h b/src/zm_camera.h index 96e987c1a..1d11b7b1c 100644 --- a/src/zm_camera.h +++ b/src/zm_camera.h @@ -117,9 +117,8 @@ public: virtual int PrimeCapture() { return 0; } virtual int PreCapture() = 0; - virtual int Capture(Image &image) = 0; + virtual int Capture(ZMPacket &p)=0; virtual int PostCapture() = 0; - virtual int CaptureAndRecord(Image &image, timeval recording, char* event_directory) = 0; virtual int Close() = 0; }; diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 3977c22c5..9d02d0d05 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -146,14 +146,9 @@ Event::Event( errno = 0; if ( mkdir(path.c_str(), 0755) ) { // FIXME This should not be fatal. Should probably move to a different storage area. -<<<<<<< HEAD if ( errno != EEXIST ) { Error("Can't mkdir %s: %s", path.c_str(), strerror(errno)); } -======= - if ( errno != EEXIST ) - Error("Can't mkdir %s: %s", path, strerror(errno)); ->>>>>>> storageareas } if ( i == 2 ) strncpy(date_path, path.c_str(), sizeof(date_path)); From 6b0551582867a12a4cc05223856de481dc7f2d63 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 31 Aug 2018 19:14:18 -0400 Subject: [PATCH 0141/2339] fix missing sql --- src/zm_logger.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/zm_logger.cpp b/src/zm_logger.cpp index 35be94b6d..c6d6e41e8 100644 --- a/src/zm_logger.cpp +++ b/src/zm_logger.cpp @@ -538,6 +538,7 @@ void Logger::logPrint( bool hex, const char * const filepath, const int line, co db_mutex.lock(); char escapedString[(strlen(syslogStart)*2)+1]; mysql_real_escape_string(&dbconn, escapedString, syslogStart, strlen(syslogStart)); + char sql[ZM_SQL_MED_BUFSIZ]; snprintf(sql, sizeof(sql), "INSERT INTO Logs " "( TimeKey, Component, ServerId, Pid, Level, Code, Message, File, Line )" From 36f7e9abb128784709fd77c428a1fbdbeddd993b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 21 Nov 2018 09:46:14 -0500 Subject: [PATCH 0142/2339] Merge h265 and begin work on swsresample --- src/zm_camera.h | 11 +++--- src/zm_ffmpeg.cpp | 1 + src/zm_ffmpeg.h | 7 ++++ src/zm_packet.cpp | 44 ++++++++++++++++++++- src/zm_packet.h | 1 + src/zm_videostore.cpp | 90 +++++++++++++++++++++++-------------------- src/zm_videostore.h | 14 ++++++- 7 files changed, 119 insertions(+), 49 deletions(-) diff --git a/src/zm_camera.h b/src/zm_camera.h index 5f5c1e7bd..c10df11f2 100644 --- a/src/zm_camera.h +++ b/src/zm_camera.h @@ -53,14 +53,13 @@ protected: int contrast; bool capture; bool record_audio; + int mVideoStreamId; + int mAudioStreamId; + AVCodecContext *mVideoCodecContext; + AVCodecContext *mAudioCodecContext; + AVStream *video_stream; unsigned int bytes; - int mVideoStreamId; - int mAudioStreamId; - AVCodecContext *mVideoCodecContext; - AVCodecContext *mAudioCodecContext; - AVStream *video_stream; - public: Camera( unsigned int p_monitor_id, diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index 13f6ae1af..2baebea32 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -474,3 +474,4 @@ void zm_free_codec( AVCodecContext **ctx ) { *ctx = NULL; } // end if } + diff --git a/src/zm_ffmpeg.h b/src/zm_ffmpeg.h index 6cb06eff8..84b950a6b 100644 --- a/src/zm_ffmpeg.h +++ b/src/zm_ffmpeg.h @@ -334,4 +334,11 @@ bool is_video_stream( AVStream * stream ); bool is_audio_stream( AVStream * stream ); int zm_receive_frame( AVCodecContext *context, AVFrame *frame, AVPacket &packet ); void dumpPacket(AVStream *, AVPacket *,const char *text=""); +#ifndef HAVE_LIBSWRESAMPLE +#ifdef HAVE_LIBAVRESAMPLE +#define av_opt_set_channel_layout(ctx, setting, value, 0) av_opt_set_int(ctx, setting, value, 0); +#define av_opt_set_sample_fmt(ctx, setting, value, 0) av_opt_set_int(ctx, setting, value, 0); +#else +#endif +#endif #endif // ZM_FFMPEG_H diff --git a/src/zm_packet.cpp b/src/zm_packet.cpp index 3a0fd92d8..3576e4d47 100644 --- a/src/zm_packet.cpp +++ b/src/zm_packet.cpp @@ -196,7 +196,49 @@ AVPacket *ZMPacket::set_packet(AVPacket *p) { Error("error refing packet"); } //dumpPacket(&packet, "zmpacket:"); - gettimeofday( timestamp, NULL ); + gettimeofday(timestamp, NULL); keyframe = p->flags & AV_PKT_FLAG_KEY; return &packet; } + +AVFrame *ZMPacket::get_out_frame( const AVCodecContext *ctx ) { + if ( !out_frame ) { + out_frame = zm_av_frame_alloc(); + if ( !out_frame ) { + Error("Unable to allocate a frame"); + return NULL; + } +#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) + int codec_imgsize = av_image_get_buffer_size( + ctx->pix_fmt, + ctx->width, + ctx->height, 1); + buffer = (uint8_t *)av_malloc(codec_imgsize); + av_image_fill_arrays( + out_frame->data, + out_frame->linesize, + buffer, + ctx->pix_fmt, + ctx->width, + ctx->height, + 1); +#else + int codec_imgsize = avpicture_get_size( + ctx->pix_fmt, + ctx->width, + ctx->height); + buffer = (uint8_t *)av_malloc(codec_imgsize); + avpicture_fill( + (AVPicture *)out_frame, + buffer, + ctx->pix_fmt, + ctx->width, + ctx->height + ); +#endif + out_frame->width = ctx->width; + out_frame->height = ctx->height; + out_frame->format = ctx->pix_fmt; + } + return out_frame; +} // end AVFrame *ZMPacket::get_out_frame( AVCodecContext *ctx ); diff --git a/src/zm_packet.h b/src/zm_packet.h index 747ac06b5..e2aa89090 100644 --- a/src/zm_packet.h +++ b/src/zm_packet.h @@ -63,6 +63,7 @@ class ZMPacket { ~ZMPacket(); void lock() { mutex.lock(); }; void unlock() { mutex.unlock(); }; + AVFrame *get_out_frame( const AVCodecContext *ctx ); }; #endif /* ZM_PACKET_H */ diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index e9a0e706c..ba1c793a1 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -819,7 +819,13 @@ bool VideoStore::setup_resampler() { out_frame->sample_rate = audio_out_ctx->sample_rate; // Setup the audio resampler +#ifdef HAVE_LIBSWRESAMPLE + resample_ctx = swr_alloc(); +#else +#ifdef HAVE_LIBAVRESAMPLE resample_ctx = avresample_alloc_context(); +#endif +#endif if ( !resample_ctx ) { Error("Could not allocate resample ctx\n"); return false; @@ -828,16 +834,15 @@ bool VideoStore::setup_resampler() { uint64_t mono_layout = av_get_channel_layout("mono"); // Some formats (i.e. WAV) do not produce the proper channel layout if ( audio_in_ctx->channel_layout == 0 ) { - av_opt_set_int(resample_ctx, "in_channel_layout", mono_layout, 0); - Debug(1, "Bad channel layout. Need to set it to mono (%d).", mono_layout); + av_opt_set_channel_layout(resample_ctx, "in_channel_layout", mono_layout, 0); + Debug(1, "Bad channel layout. Had to set it to mono (%d).", mono_layout); } else { - Debug(1, "channel layout. set it to mono (%d).", audio_in_ctx->channel_layout); - av_opt_set_int(resample_ctx, "in_channel_layout", + Debug(1, "channel layout. set it to (%d).", audio_in_ctx->channel_layout); + av_opt_set_channel_layout(resample_ctx, "in_channel_layout", audio_in_ctx->channel_layout, 0); } - av_opt_set_int(resample_ctx, "in_sample_fmt", audio_in_ctx->sample_fmt, 0); - av_opt_set_int(resample_ctx, "in_sample_rate", audio_in_ctx->sample_rate, 0); + av_opt_set_sample_fmt(resample_ctx, "in_sample_fmt", audio_in_ctx->sample_fmt, 0); av_opt_set_int(resample_ctx, "in_channels", audio_in_ctx->channels, 0); // av_opt_set_int( resample_ctx, "out_channel_layout", // audio_out_ctx->channel_layout, 0); @@ -849,10 +854,12 @@ bool VideoStore::setup_resampler() { av_opt_set_int(resample_ctx, "out_channels", audio_out_ctx->channels, 0); +#ifdef HAVE_LIBAVRESAMPLE if ( (ret = avresample_open(resample_ctx)) < 0 ) { Error("Could not open resample ctx\n"); return false; } +#endif out_frame->nb_samples = audio_out_ctx->frame_size; out_frame->format = audio_out_ctx->sample_fmt; @@ -907,46 +914,13 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { if ( video_out_ctx->codec_id != video_in_ctx->codec_id ) { //Debug(3, "Have encoding video frame count (%d)", frame_count); - if ( ! zm_packet->out_frame ) { + if ( !zm_packet->out_frame ) { //Debug(3, "Have no out frame"); - AVFrame *out_frame = zm_packet->out_frame = zm_av_frame_alloc(); + AVFrame *out_frame = zm_packet->get_out_frame(video_out_ctx); if ( !out_frame ) { Error("Unable to allocate a frame"); return 0; } -#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) - int codec_imgsize = av_image_get_buffer_size( - video_out_ctx->pix_fmt, - video_out_ctx->width, - video_out_ctx->height, 1); - zm_packet->buffer = (uint8_t *)av_malloc(codec_imgsize); - av_image_fill_arrays( - out_frame->data, - out_frame->linesize, - zm_packet->buffer, - video_out_ctx->pix_fmt, - video_out_ctx->width, - video_out_ctx->height, - 1); -#else - int codec_imgsize = avpicture_get_size( - video_out_ctx->pix_fmt, - video_out_ctx->width, - video_out_ctx->height); - zm_packet->buffer = (uint8_t *)av_malloc(codec_imgsize); - avpicture_fill( - (AVPicture *)out_frame, - zm_packet->buffer, - video_out_ctx->pix_fmt, - video_out_ctx->width, - video_out_ctx->height - ); -#endif - - out_frame->width = video_out_ctx->width; - out_frame->height = video_out_ctx->height; - out_frame->format = video_out_ctx->pix_fmt; - //out_frame->pkt_duration = 0; if ( !zm_packet->in_frame ) { //Debug(2,"Have no in_frame"); @@ -1063,6 +1037,40 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { if ( opkt.dts != AV_NOPTS_VALUE) opkt.dts = av_rescale_q(opkt.dts, video_out_ctx->time_base, video_out_stream->time_base); + int64_t duration; + if ( ipkt->duration ) { + duration = av_rescale_q( + ipkt->duration, + video_in_stream->time_base, + video_out_stream->time_base); + Debug(1, "duration from ipkt: pts(%" PRId64 ") - last_pts(%" PRId64 ") = (%" PRId64 ") => (%" PRId64 ") (%d/%d) (%d/%d)", + ipkt->pts, + video_last_pts, + ipkt->duration, + duration, + video_in_stream->time_base.num, + video_in_stream->time_base.den, + video_out_stream->time_base.num, + video_out_stream->time_base.den + ); + } else { + duration = + av_rescale_q( + ipkt->pts - video_last_pts, + video_in_stream->time_base, + video_out_stream->time_base); + Debug(1, "duration calc: pts(%" PRId64 ") - last_pts(%" PRId64 ") = (%" PRId64 ") => (%" PRId64 ")", + ipkt->pts, + video_last_pts, + ipkt->pts - video_last_pts, + duration + ); + if ( duration <= 0 ) { + duration = ipkt->duration ? ipkt->duration : av_rescale_q(1,video_in_stream->time_base, video_out_stream->time_base); + } + } + opkt.duration = duration; + } else { // codec matches, we are doing passthrough AVPacket *ipkt = &zm_packet->packet; Debug(3, "Doing passthrough, just copy packet"); diff --git a/src/zm_videostore.h b/src/zm_videostore.h index 610eaf69b..40ebddf76 100644 --- a/src/zm_videostore.h +++ b/src/zm_videostore.h @@ -3,9 +3,14 @@ #include "zm_ffmpeg.h" extern "C" { +#ifdef HAVE_LIBSWRESAMPLE +#include "libswresample/swresample.h" +#endif +#else #ifdef HAVE_LIBAVRESAMPLE #include "libavresample/avresample.h" #endif +#endif } #if HAVE_LIBAVCODEC @@ -60,8 +65,12 @@ int audio_in_stream_index; // The following are used when encoding the audio stream to AAC AVCodec *audio_out_codec; AVCodecContext *audio_out_ctx; +#ifdef HAVE_LIBSWRESAMPLE + SwrContext* resample_ctx; +#else #ifdef HAVE_LIBAVRESAMPLE AVAudioResampleContext* resample_ctx; +#endif #endif uint8_t *converted_in_samples; @@ -71,6 +80,8 @@ int audio_in_stream_index; // These are for in uint64_t video_start_pts; + int64_t video_last_pts; + int64_t video_last_dts; int64_t audio_last_pts; int64_t audio_last_dts; @@ -80,7 +91,8 @@ int audio_in_stream_index; int64_t audio_first_dts; // These are for out, should start at zero. We assume they do not wrap because we just aren't going to save files that big. -; + int64_t video_next_pts; + int64_t video_next_dts; int64_t audio_next_pts; int64_t audio_next_dts; From e15227d53e73017ca81d09da8390619a994ea600 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 26 Dec 2018 18:18:22 -0500 Subject: [PATCH 0143/2339] remove zma restarts --- scripts/zmwatch.pl.in | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/scripts/zmwatch.pl.in b/scripts/zmwatch.pl.in index c7cd73d95..2c2da9245 100644 --- a/scripts/zmwatch.pl.in +++ b/scripts/zmwatch.pl.in @@ -123,7 +123,7 @@ while( 1 ) { ) ? (3/$monitor->{MaxFPS}) : $Config{ZM_WATCH_MAX_DELAY} ; - my $image_delay = $now-$capture_time; + my $image_delay = $now - $capture_time; Debug("Monitor $monitor->{Id} last captured $image_delay seconds ago, max is $max_image_delay"); if ( $image_delay > $max_image_delay ) { Info("Restarting capture daemon for " @@ -138,9 +138,6 @@ while( 1 ) { } if ( $restart ) { - # Because zma depends on zmc, and zma can hold the shm in place, preventing zmc from using the space in /dev/shm, - # we need to stop zma before restarting zmc. - runCommand("zmdc.pl stop zma -m $$monitor{Id}") if $monitor->{Function} ne 'Monitor'; my $command; if ( $monitor->{Type} eq 'Local' ) { $command = "zmdc.pl restart zmc -d $monitor->{Device}"; @@ -148,7 +145,6 @@ while( 1 ) { $command = "zmdc.pl restart zmc -m $monitor->{Id}"; } runCommand($command); - runCommand("zmdc.pl start zma -m $$monitor{Id}") if $monitor->{Function} ne 'Monitor'; } elsif ( $monitor->{Function} ne 'Monitor' ) { # Now check analysis daemon $restart = 0; From f2e7ec7e364bfdd7e9b6d4596fc01ee14f7280b3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 19 Feb 2019 09:47:04 -0500 Subject: [PATCH 0144/2339] Sleep less when waiting for zmc to capture an image. Return camera in getCamera --- src/zm_monitor.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 0d47fee61..799b0059c 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -735,6 +735,7 @@ Camera * Monitor::getCamera() { } // end if type camera->setMonitor(this); + return camera; } // end Monitor::getCamera Monitor *Monitor::Load(unsigned int p_id, bool load_zones, Purpose purpose) { @@ -2708,7 +2709,7 @@ void Monitor::get_ref_image() { ) { Info("Waiting for capture daemon lastwriteindex(%d) lastwritetime(%d)", shared_data->last_write_index, shared_data->last_write_time); - usleep(50000); + usleep(10000); } if ( zm_terminate ) return; From 448294f59398187f7a9a33bfe1dc80cf0bb9c444 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 25 Feb 2019 10:21:43 -0500 Subject: [PATCH 0145/2339] wip --- src/zm_ffmpeg_camera.cpp | 2 +- src/zm_local_camera.cpp | 4 + src/zm_monitor.cpp | 64 +++++------ src/zm_monitorstream.cpp | 22 ++-- src/zm_packet.cpp | 74 +++++++------ src/zm_packet.h | 8 +- src/zm_packetqueue.cpp | 117 ++++++++++++++------ src/zm_packetqueue.h | 4 +- web/index.php | 5 +- web/skins/classic/views/event.php | 21 ++-- web/skins/classic/views/js/postlogin.js.php | 7 +- 11 files changed, 193 insertions(+), 135 deletions(-) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 8bd180b65..8617f898d 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -241,7 +241,7 @@ int FfmpegCamera::OpenFfmpeg() { } if ( ret < 0 ) { - Warning("Could not set rtsp_transport method '%s'\n", method.c_str()); + Warning("Could not set rtsp_transport method '%s'", method.c_str()); } Debug(1, "Calling avformat_open_input for %s", mPath.c_str()); diff --git a/src/zm_local_camera.cpp b/src/zm_local_camera.cpp index 03a5460f3..dddaf48b7 100644 --- a/src/zm_local_camera.cpp +++ b/src/zm_local_camera.cpp @@ -2082,6 +2082,10 @@ int LocalCamera::Capture( ZMPacket &zm_packet ) { } /* prime capture */ + if ( ! zm_packet.image ) { + zm_packet.image = new Image(width, height, colours, subpixelorder); + } + if ( conversion_type != 0 ) { Debug(3, "Performing format conversion"); diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 799b0059c..d570be230 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1630,6 +1630,7 @@ bool Monitor::Analyse() { ZMPacket *snap; // Is it possible for snap->score to be ! -1? + // get_analysis_packet will lock the packet while ( ( snap = packetqueue->get_analysis_packet() ) && ( snap->score == -1 ) ) { unsigned int index = snap->image_index; Debug(2, "Analysis index (%d), last_Write(%d)", index, shared_data->last_write_index); @@ -1638,7 +1639,6 @@ bool Monitor::Analyse() { return 0; } - snap->lock(); packets_processed += 1; if ( snap->image_index == -1 ) { @@ -2069,7 +2069,6 @@ void Monitor::ReloadLinkedMonitors(const char *p_linked_monitors) { db_mutex.lock(); static char sql[ZM_SQL_SML_BUFSIZ]; - db_mutex.lock(); snprintf(sql, sizeof(sql), "SELECT Id, Name FROM Monitors WHERE Id = %d AND Function != 'None' AND Function != 'Monitor' AND Enabled = 1", link_ids[i] ); if ( mysql_query(&dbconn, sql) ) { db_mutex.unlock(); @@ -2177,25 +2176,27 @@ int Monitor::LoadFfmpegMonitors(const char *file, Monitor **&monitors, Purpose p int Monitor::Capture() { static int FirstCapture = 1; // Used in de-interlacing to indicate whether this is the even or odd image - unsigned int index = image_count % image_buffer_count; + unsigned int index = 0; + //image_count % image_buffer_count; if ( (index == shared_data->last_read_index) && (function > MONITOR) ) { - Warning( "Buffer overrun at index %d, image %d, slow down capture, speed up analysis or increase ring buffer size", index, image_count ); + Warning("Buffer overrun at index %d, image %d, slow down capture, speed up analysis or increase ring buffer size", index, image_count); time_t now = time(0); double approxFps = double(image_buffer_count)/double(now-image_buffer[index].timestamp->tv_sec); time_t last_read_delta = now - shared_data->last_read_time; if ( last_read_delta > (image_buffer_count/approxFps) ) { - Warning( "Last image read from shared memory %ld seconds ago, zma may have gone away", last_read_delta ) + Warning("Last image read from shared memory %ld seconds ago, zma may have gone away", last_read_delta) shared_data->last_read_index = image_buffer_count; } } else { - Debug(2,"Capture: Current write index %d, last read index %d, current (%d)", shared_data->last_write_index, shared_data->last_read_index, index ); + Debug(2,"Capture: Last write(capture) index %d, last read(analysis) index %d, current (%d)", + shared_data->last_write_index, shared_data->last_read_index, index ); } - ZMPacket *packet = &image_buffer[index]; - Debug(2,"before lock"); + ZMPacket *packet = new ZMPacket(); + //&image_buffer[index]; + Debug(2,"before packet lock"); packet->lock(); - Debug(2,"before reset"); packet->reset(); Image* capture_image = packet->image; int captureResult = 0; @@ -2243,23 +2244,23 @@ int Monitor::Capture() { if ( packet->packet.stream_index != video_stream_id ) { Debug(2, "Have audio packet (%d) != videostream_id:(%d) q.vpktcount(%d) event?(%d) ", packet->packet.stream_index, video_stream_id, packetqueue->video_packet_count, ( event ? 1 : 0 ) ); - // Only queue if we have some video packets in there. - mutex.lock(); + // Only queue if we have some video packets in there. Should push this logic into packetqueue + //mutex.lock(); if ( packetqueue->video_packet_count || event ) { // Need to copy it into another ZMPacket. - ZMPacket *audio_packet = new ZMPacket(*packet); + //ZMPacket *audio_packet = new ZMPacket(*packet); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - audio_packet->codec_type = camera->get_AudioStream()->codecpar->codec_type; + packet->codec_type = camera->get_AudioStream()->codecpar->codec_type; #else - audio_packet->codec_type = camera->get_AudioStream()->codec->codec_type; + packet->codec_type = camera->get_AudioStream()->codec->codec_type; #endif Debug(2, "Queueing packet"); - packetqueue->queuePacket(audio_packet); + packetqueue->queuePacket(packet); } // Don't update last_write_index because that is used for live streaming //shared_data->last_write_time = image_buffer[index].timestamp->tv_sec; - mutex.unlock(); + //mutex.unlock(); packet->unlock(); return 1; } @@ -2274,20 +2275,21 @@ int Monitor::Capture() { //Debug(2,"About to decode"); if ( packet->decode(camera->get_VideoCodecContext()) ) { //Debug(2,"Getimage"); - packet->get_image(); + packet->get_image( image_buffer[index].image ); } // Have an av_packet, } - Debug(2,"Before mutex lock"); - mutex.lock(); + //Debug(2,"Before mutex lock"); + // FIXME this mutex is useless, packetqueue has it's own + //mutex.lock(); if ( packetqueue->video_packet_count || packet->keyframe || event ) { Debug(2, "Have video packet for index (%d)", index); packetqueue->queuePacket(packet); } else { Debug(2, "Not queuing video packet for index (%d)", index); } - mutex.unlock(); + //mutex.unlock(); /* Deinterlacing */ if ( deinterlacing_value ) { @@ -2355,7 +2357,7 @@ int Monitor::Capture() { // assume that we are connected snprintf(sql, sizeof(sql), "INSERT INTO Monitor_Status (MonitorId,CaptureFPS,CaptureBandwidth,Status) " - "VALUES (%d, %.2lf,%u) ON DUPLICATE KEY UPDATE " + "VALUES (%d, %.2lf, %u, 'Connected') ON DUPLICATE KEY UPDATE " "CaptureFPS = %.2lf, CaptureBandwidth=%u, Status='Connected'", id, capture_fps, new_capture_bandwidth, capture_fps, new_capture_bandwidth); if ( mysql_query(&dbconn, sql) ) { @@ -2701,24 +2703,18 @@ Monitor::Orientation Monitor::getOrientation() const { return orientation; } // Wait for camera to get an image, and then assign it as the base reference image. So this should be done as the first task in the analysis thread startup. void Monitor::get_ref_image() { - while ( - ( shared_data->last_write_index == (unsigned int)image_buffer_count ) - && - ( shared_data->last_write_time == 0 ) - && ! zm_terminate - ) { - Info("Waiting for capture daemon lastwriteindex(%d) lastwritetime(%d)", + ZMPacket * snap; + while ( ((!( snap = packetqueue->get_analysis_packet())) || ( snap->image_index == -1 )) && !zm_terminate) { + Debug(1, "Waiting for capture daemon lastwriteindex(%d) lastwritetime(%d)", shared_data->last_write_index, shared_data->last_write_time); - usleep(10000); + //usleep(10000); } if ( zm_terminate ) return; - int last_write_index = shared_data->last_write_index ; - Debug(2,"Waiting for capture daemon unlock"); - image_buffer[last_write_index].mutex.lock(); - ref_image.Assign(width, height, camera->Colours(), camera->SubpixelOrder(), image_buffer[last_write_index].image->Buffer(), camera->ImageSize()); - image_buffer[last_write_index].mutex.unlock(); + ref_image.Assign(width, height, camera->Colours(), camera->SubpixelOrder(), snap->image->Buffer(), camera->ImageSize()); + Debug(2,"Have image about to unlock"); + snap->unlock(); } std::vector Monitor::Groups() { diff --git a/src/zm_monitorstream.cpp b/src/zm_monitorstream.cpp index c1a253cf3..b5a0429e6 100644 --- a/src/zm_monitorstream.cpp +++ b/src/zm_monitorstream.cpp @@ -74,9 +74,9 @@ bool MonitorStream::checkSwapPath(const char *path, bool create_path) { } // end bool MonitorStream::checkSwapPath( const char *path, bool create_path ) void MonitorStream::processCommand(const CmdMsg *msg) { - Debug( 2, "Got message, type %d, msg %d", msg->msg_type, msg->msg_data[0] ); + Debug(2, "Got message, type %d, msg %d", msg->msg_type, msg->msg_data[0]); // Check for incoming command - switch( (MsgCommand)msg->msg_data[0] ) { + switch ( (MsgCommand)msg->msg_data[0] ) { case CMD_PAUSE : Debug(1, "Got PAUSE command"); paused = true; @@ -414,19 +414,19 @@ bool MonitorStream::sendFrame(Image *image, struct timeval *timestamp) { return false; } fputs("\r\n\r\n",stdout); - fflush( stdout ); + fflush(stdout); struct timeval frameEndTime; - gettimeofday( &frameEndTime, NULL ); + gettimeofday(&frameEndTime, NULL); - int frameSendTime = tvDiffMsec( frameStartTime, frameEndTime ); + int frameSendTime = tvDiffMsec(frameStartTime, frameEndTime); if ( frameSendTime > 1000/maxfps ) { maxfps /= 1.5; - Error( "Frame send time %d msec too slow, throttling maxfps to %.2f", frameSendTime, maxfps ); + Error("Frame send time %d msec too slow, throttling maxfps to %.2f", frameSendTime, maxfps); } } - last_frame_sent = TV_2_FLOAT( now ); - return( true ); + last_frame_sent = TV_2_FLOAT(now); + return true; } // end bool MonitorStream::sendFrame( Image *image, struct timeval *timestamp ) void MonitorStream::runStream() { @@ -483,7 +483,7 @@ void MonitorStream::runStream() { } else { swap_path = staticConfig.PATH_SWAP; - Debug( 3, "Checking swap path folder: %s", swap_path.c_str() ); + Debug(3, "Checking swap path folder: %s", swap_path.c_str()); if ( checkSwapPath(swap_path.c_str(), true) ) { swap_path += stringtf("/zmswap-m%d", monitor->Id()); @@ -503,8 +503,8 @@ void MonitorStream::runStream() { } else { Debug(2, "Assigning temporary buffer"); temp_image_buffer = new SwapImage[temp_image_buffer_count]; - memset( temp_image_buffer, 0, sizeof(*temp_image_buffer)*temp_image_buffer_count ); - Debug( 2, "Assigned temporary buffer" ); + memset(temp_image_buffer, 0, sizeof(*temp_image_buffer)*temp_image_buffer_count); + Debug(2, "Assigned temporary buffer"); } } } else { diff --git a/src/zm_packet.cpp b/src/zm_packet.cpp index ecd18a5b8..a49ab06e2 100644 --- a/src/zm_packet.cpp +++ b/src/zm_packet.cpp @@ -31,7 +31,7 @@ ZMPacket::ZMPacket( ) { out_frame = NULL; image = NULL; buffer = NULL; - av_init_packet( &packet ); + av_init_packet(&packet); packet.size = 0; // So we can detect whether it has been filled. timestamp = NULL; analysis_image = NULL; @@ -47,8 +47,8 @@ ZMPacket::ZMPacket( ZMPacket &p ) { out_frame = NULL; image = NULL; buffer = NULL; - av_init_packet( &packet ); - if ( zm_av_packet_ref( &packet, &p.packet ) < 0 ) { + av_init_packet(&packet); + if ( zm_av_packet_ref(&packet, &p.packet) < 0 ) { Error("error refing packet"); } timestamp = new struct timeval; @@ -59,17 +59,17 @@ ZMPacket::ZMPacket( ZMPacket &p ) { } ZMPacket::~ZMPacket() { - zm_av_packet_unref( &packet ); + zm_av_packet_unref(&packet); if ( in_frame ) { //av_free(frame->data); - av_frame_free( &in_frame ); + av_frame_free(&in_frame); } if ( out_frame ) { //av_free(frame->data); - av_frame_free( &out_frame ); + av_frame_free(&out_frame); } if ( buffer ) { - av_freep( &buffer ); + av_freep(&buffer); } if ( analysis_image ) { delete analysis_image; @@ -82,19 +82,19 @@ ZMPacket::~ZMPacket() { void ZMPacket::reset() { //Debug(2,"reset"); - zm_av_packet_unref( &packet ); + zm_av_packet_unref(&packet); packet.size = 0; if ( in_frame ) { //Debug(4,"reset frame"); - av_frame_free( &in_frame ); + av_frame_free(&in_frame); } if ( out_frame ) { //Debug(4,"reset frame"); - av_frame_free( &out_frame ); + av_frame_free(&out_frame); } if ( buffer ) { //Debug(4,"freeing buffer"); - av_freep( &buffer ); + av_freep(&buffer); } if ( analysis_image ) { delete analysis_image; @@ -111,42 +111,44 @@ void ZMPacket::reset() { } int ZMPacket::decode( AVCodecContext *ctx ) { - Debug(4, "about to decode video, image_index is (%d)", image_index ); + Debug(4, "about to decode video, image_index is (%d)", image_index); if ( in_frame ) { - Error("Already have a frame?"); + Error("Already have a frame?"); } else { - in_frame = zm_av_frame_alloc(); + in_frame = zm_av_frame_alloc(); } #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - int ret = avcodec_send_packet( ctx, &packet ); + Debug(4,"send_packet"); + int ret = avcodec_send_packet(ctx, &packet); if ( ret < 0 ) { - Error( "Unable to send packet: %s", av_make_error_string(ret).c_str() ); - av_frame_free( &in_frame ); + Error("Unable to send packet: %s", av_make_error_string(ret).c_str()); + av_frame_free(&in_frame); return 0; } #if HAVE_AVUTIL_HWCONTEXT_H if ( hwaccel ) { - ret = avcodec_receive_frame( ctx, hwFrame ); + ret = avcodec_receive_frame(ctx, hwFrame); if ( ret < 0 ) { - Error( "Unable to receive frame: %s", av_make_error_string(ret).c_str() ); - av_frame_free( &in_frame ); + Error("Unable to receive frame: %s", av_make_error_string(ret).c_str()); + av_frame_free(&in_frame); return 0; } ret = av_hwframe_transfer_data(frame, hwFrame, 0); if ( ret < 0 ) { - Error( "Unable to transfer frame: %s", av_make_error_string(ret).c_str() ); - av_frame_free( &in_frame ); + Error("Unable to transfer frame: %s", av_make_error_string(ret).c_str()); + av_frame_free(&in_frame); return 0; } } else { #endif - ret = avcodec_receive_frame( ctx, in_frame ); + Debug(4,"receive_frame"); + ret = avcodec_receive_frame(ctx, in_frame); if ( ret < 0 ) { - Error( "Unable to receive frame: %s", av_make_error_string(ret).c_str() ); - av_frame_free( &in_frame ); + Error("Unable to receive frame: %s", av_make_error_string(ret).c_str()); + av_frame_free(&in_frame); return 0; } @@ -156,38 +158,38 @@ int ZMPacket::decode( AVCodecContext *ctx ) { # else int frameComplete = 0; - int ret = zm_avcodec_decode_video( ctx, in_frame, &frameComplete, &packet ); + int ret = zm_avcodec_decode_video(ctx, in_frame, &frameComplete, &packet); if ( ret < 0 ) { - Error( "Unable to decode frame at frame %s", av_make_error_string(ret).c_str() ); - av_frame_free( &in_frame ); + Error("Unable to decode frame at frame %s", av_make_error_string(ret).c_str()); + av_frame_free(&in_frame); return 0; } - if ( ! frameComplete ) { + if ( !frameComplete ) { Debug(1, "incomplete frame?"); - av_frame_free( &in_frame ); + av_frame_free(&in_frame); return 0; } #endif return 1; } // end ZMPacket::decode -Image * ZMPacket::get_image( Image *i ) { - if ( ! in_frame ) { +Image *ZMPacket::get_image(Image *i) { + if ( !in_frame ) { Error("Can't get image without frame.. maybe need to decode first"); return NULL; } - if ( ! image ) { - if ( ! i ) { + if ( !image ) { + if ( !i ) { Error("Need a pre-allocated image buffer"); return NULL; } image = i; } - image->Assign( in_frame ); + image->Assign(in_frame); return image; } -Image *ZMPacket::set_image( Image *i ) { +Image *ZMPacket::set_image(Image *i) { image = i; return image; } diff --git a/src/zm_packet.h b/src/zm_packet.h index 1d7dc34de..1f0dbf704 100644 --- a/src/zm_packet.h +++ b/src/zm_packet.h @@ -62,8 +62,12 @@ class ZMPacket { explicit ZMPacket( ZMPacket &packet ); ZMPacket(); ~ZMPacket(); - void lock() { mutex.lock(); }; - void unlock() { mutex.unlock(); }; + void lock() { + Debug(2,"Locking packet %d", this->image_index); + mutex.lock(); + Debug(2,"packet %d locked", this->image_index); + }; + void unlock() { Debug(2,"packet %d unlocked", this->image_index);mutex.unlock(); }; AVFrame *get_out_frame( const AVCodecContext *ctx ); int get_codec_imgsize() { return codec_imgsize; }; }; diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index 513c44d69..94297bd98 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -33,12 +33,15 @@ zm_packetqueue::zm_packetqueue( int video_image_count, int p_video_stream_id, in packet_counts = new int[max_stream_id+1]; for ( int i=0; i <= max_stream_id; ++i ) packet_counts[i] = 0; + condition = new Condition(mutex); } zm_packetqueue::~zm_packetqueue() { clearQueue(); delete[] packet_counts; packet_counts = NULL; + delete condition; + condition = NULL; } /* Enqueues the given packet. Will maintain the analysis_it pointer and image packet counts. @@ -48,6 +51,7 @@ zm_packetqueue::~zm_packetqueue() { bool zm_packetqueue::queuePacket( ZMPacket* zm_packet ) { Debug(4, "packetqueue queuepacket, first_video_packet_index is %d", first_video_packet_index); + mutex.lock(); if ( zm_packet->image_index != -1 ) { // It's a video packet @@ -55,51 +59,33 @@ bool zm_packetqueue::queuePacket( ZMPacket* zm_packet ) { // If we can never queue the same packet, then they can never go past if ( zm_packet->image_index == first_video_packet_index ) { Debug(2, "queuing packet that is already on the queue(%d)", zm_packet->image_index); - ZMPacket *p = NULL;; - while ( pktQueue.size() && (p = pktQueue.front()) && ( p->image_index != zm_packet->image_index ) ) { - if ( ( analysis_it != pktQueue.end() ) && ( *analysis_it == p ) ) { - Debug(2, "Increasing analysis_it, meaning analysis is not keeping up"); - ++analysis_it; - } + while ( pktQueue.size() ) { + mutex.unlock(); + ZMPacket *p = popPacket(); + Debug(2,"Front packet index: %d", p->image_index); + mutex.lock(); - pktQueue.pop_front(); - if ( p->codec_type == AVMEDIA_TYPE_VIDEO ) { - Debug(2, "Decreasing video_packet_count (%d), popped (%d)", - video_packet_count, p->image_index); - video_packet_count -= 1; - first_video_packet_index += 1; - first_video_packet_index %= max_video_packet_count; - - } else { - Debug(2, "Deleteing audio frame(%d)", p->image_index); + if ( p->codec_type != AVMEDIA_TYPE_VIDEO ) { + Debug(2, "Deleting audio frame(%d)", p->image_index); delete p; p = NULL; } - Debug(2,"pktQueue.size(%d)", pktQueue.size() ); + Debug(2,"pktQueue.size(%d)", pktQueue.size()); + if ( p->image_index == zm_packet->image_index ) + break; } // end while there are packets at the head of the queue that are not this one - if ( p && ( p->image_index == zm_packet->image_index ) ) { - // it should - video_packet_count -= 1; - pktQueue.pop_front(); - first_video_packet_index += 1; - first_video_packet_index %= max_video_packet_count; - - } else { - Error("SHould have found the packet! front packet index was %d, new packet index is %d ", - p->image_index, zm_packet->image_index - ); - } if ( analysis_it == pktQueue.end() ) { // Analsys_it should only point to end when queue is empty Debug(2,"pointing analysis_it to begining"); analysis_it = pktQueue.begin(); } - } else if ( first_video_packet_index == -1 ) { + } + if ( first_video_packet_index == -1 ) { // Initialize the first_video_packet indicator first_video_packet_index = zm_packet->image_index; - video_packet_count += 1; } // end if + video_packet_count += 1; } // end if queuing a video packet pktQueue.push_back(zm_packet); @@ -114,6 +100,10 @@ bool zm_packetqueue::queuePacket( ZMPacket* zm_packet ) { } #endif + // We signal on every packet because someday we may analyze sound + Debug(2,"Signalling"); + condition->signal(); + mutex.unlock(); return true; } // end bool zm_packetqueue::queuePacket(ZMPacket* zm_packet) @@ -122,6 +112,9 @@ ZMPacket* zm_packetqueue::popPacket( ) { if ( pktQueue.empty() ) { return NULL; } + Debug(2,"Mutex locking"); + mutex.lock(); + Debug(2,"Have Mutex lock"); ZMPacket *packet = pktQueue.front(); if ( *analysis_it == packet ) @@ -140,7 +133,9 @@ ZMPacket* zm_packetqueue::popPacket( ) { } } packet_counts[packet->packet.stream_index] -= 1; + mutex.unlock(); + // Should we lock the packet? return packet; } @@ -155,6 +150,7 @@ unsigned int zm_packetqueue::clearQueue(unsigned int frames_to_keep, int stream_ if ( pktQueue.size() <= frames_to_keep ) { return 0; } + mutex.lock(); int packets_to_delete = pktQueue.size(); std::list::reverse_iterator it; @@ -241,6 +237,7 @@ unsigned int zm_packetqueue::clearQueue(unsigned int frames_to_keep, int stream_ #endif Debug(3, "Deleted packets, resulting size is %d", pktQueue.size()); + mutex.unlock(); return delete_count; } // end unsigned int zm_packetqueue::clearQueue( unsigned int frames_to_keep, int stream_id ) @@ -278,15 +275,22 @@ int zm_packetqueue::packet_count( int stream_id ) { // Returns a packet to analyse or NULL ZMPacket *zm_packetqueue::get_analysis_packet() { - if ( ! pktQueue.size() ) - return NULL; - if ( analysis_it == pktQueue.end() ) - return NULL; + mutex.lock(); + while ( (! pktQueue.size()) || ( analysis_it == pktQueue.end() ) ) { + Debug(2,"waiting. Queue size %d analysis_it == end? %d", pktQueue.size(), ( analysis_it == pktQueue.end() ) ); + + condition->wait(); + } //Debug(2, "Distance from head: (%d)", std::distance( pktQueue.begin(), analysis_it ) ); //Debug(2, "Distance from end: (%d)", std::distance( analysis_it, pktQueue.end() ) ); + ZMPacket *p = *analysis_it; + Debug(2,"analysis_packet image_index: %d, about to lock packet", p->image_index); + p->lock(); + Debug(2, "Locked packet, unlocking mutex"); + mutex.unlock(); - return *analysis_it; + return p; } // end ZMPacket *zm_packetqueue::get_analysis_packet() // The idea is that analsys_it will only be == end() if the queue is empty @@ -301,3 +305,44 @@ bool zm_packetqueue::increment_analysis_it( ) { analysis_it = next_it; return true; } // end bool zm_packetqueue::increment_analysis_it( ) + +// Locks the packet, but also removes it from the queue including analysis_it +void zm_packetqueue::lock_packet( ZMPacket &packet ) { + mutex.lock(); + if ( packet.image_index != -1 ) { + // It's a video packet + + // If we can never queue the same packet, then they can never go past + if ( packet.image_index == first_video_packet_index ) { + Debug(2, "queuing packet that is already on the queue(%d)", packet.image_index); + while ( pktQueue.size() ) { + mutex.unlock(); + ZMPacket *p = popPacket(); + Debug(2,"Front packet index: %d", p->image_index); + mutex.lock(); + + if ( p->codec_type != AVMEDIA_TYPE_VIDEO ) { + Debug(2, "Deleting audio frame(%d)", p->image_index); + delete p; + p = NULL; + } + Debug(2,"pktQueue.size(%d)", pktQueue.size()); + if ( p->image_index == packet.image_index ) + break; + } // end while there are packets at the head of the queue that are not this one + + if ( analysis_it == pktQueue.end() ) { + // Analsys_it should only point to end when queue is empty + Debug(2,"pointing analysis_it to begining"); + analysis_it = pktQueue.begin(); + } + } + if ( first_video_packet_index == -1 ) { + // Initialize the first_video_packet indicator + first_video_packet_index = packet.image_index; + } // end if + video_packet_count += 1; + } // end if queuing a video packet + packet.lock(); + mutex.unlock(); +} diff --git a/src/zm_packetqueue.h b/src/zm_packetqueue.h index 033528101..b87ccba33 100644 --- a/src/zm_packetqueue.h +++ b/src/zm_packetqueue.h @@ -42,7 +42,8 @@ class zm_packetqueue { int max_stream_id; int *packet_counts; /* packet count for each stream_id, to keep track of how many video vs audio packets are in the queue */ - Mutex mutex; + RecursiveMutex mutex; + Condition *condition; public: zm_packetqueue(int p_max_video_packet_count, int p_video_stream_id, int p_audio_stream_id); @@ -60,6 +61,7 @@ class zm_packetqueue { // Functions to manage the analysis frame logic bool increment_analysis_it(); ZMPacket *get_analysis_packet(); + void lock_packet( ZMPacket &packet ); }; #endif /* ZM_PACKETQUEUE_H */ diff --git a/web/index.php b/web/index.php index 6df75ef04..f9bbf6e53 100644 --- a/web/index.php +++ b/web/index.php @@ -215,8 +215,9 @@ if ( $action ) { # If I put this here, it protects all views and popups, but it has to go after actions.php because actions.php does the actual logging in. if ( ZM_OPT_USE_AUTH and !isset($user) and ($view != 'login') ) { Logger::Debug('Redirecting to login'); - $view = 'none'; - $redirect = ZM_BASE_URL.$_SERVER['PHP_SELF'].'?view=login'; + # We adjust the view instead of redirecting so that we can store the original url and just to it after logging in + $view = 'login'; + #$redirect = ZM_BASE_URL.$_SERVER['PHP_SELF'].'?view=login'; $request = null; } else if ( ZM_SHOW_PRIVACY && ($view != 'privacy') && ($view != 'options') && (!$request) && canEdit('System') ) { $view = 'none'; diff --git a/web/skins/classic/views/event.php b/web/skins/classic/views/event.php index 6b657b2b0..b197684de 100644 --- a/web/skins/classic/views/event.php +++ b/web/skins/classic/views/event.php @@ -36,7 +36,7 @@ if ( $user['MonitorIds'] ) { } $Monitor = $Event->Monitor(); -if (isset($_REQUEST['rate'])) { +if ( isset($_REQUEST['rate']) ) { $rate = validInt($_REQUEST['rate']); } else if ( isset($_COOKIE['zmEventRate']) ) { $rate = $_COOKIE['zmEventRate']; @@ -44,7 +44,7 @@ if (isset($_REQUEST['rate'])) { $rate = reScale(RATE_BASE, $Monitor->DefaultRate(), ZM_WEB_DEFAULT_RATE); } -if (isset($_REQUEST['scale'])) { +if ( isset($_REQUEST['scale']) ) { $scale = validInt($_REQUEST['scale']); } else if ( isset( $_COOKIE['zmEventScaleAuto'] ) ) { // If we're using scale to fit use it on all monitors @@ -56,12 +56,12 @@ if (isset($_REQUEST['scale'])) { } $codec = 'auto'; -if (isset($_REQUEST['codec'])) { +if ( isset($_REQUEST['codec']) ) { $codec = $_REQUEST['codec']; session_start(); $_SESSION['zmEventCodec'.$Event->MonitorId()] = $codec; session_write_close(); -} else if ( isset( $_SESSION['zmEventCodec'.$Event->MonitorId()] ) ) { +} else if ( isset($_SESSION['zmEventCodec'.$Event->MonitorId()]) ) { $codec = $_SESSION['zmEventCodec'.$Event->MonitorId()]; } else { $codec = $Monitor->DefaultCodec(); @@ -91,7 +91,7 @@ if ( isset( $_REQUEST['replayMode'] ) ) if ( isset( $_COOKIE['replayMode']) && preg_match('#^[a-z]+$#', $_COOKIE['replayMode']) ) $replayMode = validHtmlStr($_COOKIE['replayMode']); -if ( ( ! $replayMode ) or ( ! $replayModes[$replayMode] ) ) { +if ( ( !$replayMode ) or ( !$replayModes[$replayMode] ) ) { $replayMode = 'none'; } @@ -145,7 +145,7 @@ if ( ! $Event->Id() ) {
+
DefaultVideo ?>
-
-
+
+
'changeCodec(this);') ); ?>
@@ -192,7 +192,6 @@ if ( $video_tag ) { -
- +

diff --git a/web/skins/classic/views/js/postlogin.js.php b/web/skins/classic/views/js/postlogin.js.php index 7a945f9ef..b8a33ee48 100644 --- a/web/skins/classic/views/js/postlogin.js.php +++ b/web/skins/classic/views/js/postlogin.js.php @@ -18,8 +18,11 @@ } ?>"; - //var newUrl = thisUrl + querySuffix; - var newUrl = '' + querySuffix; + if ( querySuffix == '?view=login' ) { + querySuffix = '?view=console'; + } + var newUrl = querySuffix; + console.log("Redirecting to" + newUrl + ' ' + thisUrl); window.location.replace(newUrl); } ).delay( 500 ); From bddef3ad597db4352892ac15787640ec9edf523b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 26 Feb 2019 09:38:26 -0500 Subject: [PATCH 0146/2339] Add required update_function_points to Assign --- src/zm_image.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/zm_image.cpp b/src/zm_image.cpp index 3cecc0802..5a03f89b1 100644 --- a/src/zm_image.cpp +++ b/src/zm_image.cpp @@ -597,6 +597,7 @@ void Image::AssignDirect( const unsigned int p_width, const unsigned int p_heigh buffertype = p_buffertype; buffer = new_buffer; } + update_function_pointers(); } @@ -647,6 +648,7 @@ void Image::Assign(const unsigned int p_width, const unsigned int p_height, cons if ( new_buffer != buffer ) (*fptr_imgbufcpy)(buffer, new_buffer, size); + update_function_pointers(); } @@ -1747,7 +1749,7 @@ Image *Image::Highlight( unsigned int n_images, Image *images[], const Rgb thres } /* New function to allow buffer re-using instead of allocationg memory for the delta image every time */ -void Image::Delta( const Image &image, Image* targetimage) const { +void Image::Delta(const Image &image, Image* targetimage) const { #ifdef ZM_IMAGE_PROFILING struct timespec start,end,diff; unsigned long long executetime; @@ -4200,6 +4202,7 @@ void ssse3_delta8_rgb32(const uint8_t* col1, const uint8_t* col2, uint8_t* resul /* RGB32: RGBA SSSE3 */ void ssse3_delta8_rgba(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count) { + Debug(2,"sse3 rgba"); ssse3_delta8_rgb32(col1, col2, result, count, 0x00010502); } From 62d95e4d6eac2457d37aa15ecafd6e5f82e57426 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 26 Feb 2019 09:45:20 -0500 Subject: [PATCH 0147/2339] wip deprecate a lot of the index code. We are basically just using imag_buffer[0] for current image --- src/zm_monitor.cpp | 155 ++++++++++++++++++++------------------- src/zm_monitorstream.cpp | 6 +- 2 files changed, 84 insertions(+), 77 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index d570be230..ea0386e03 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -747,7 +747,9 @@ Monitor *Monitor::Load(unsigned int p_id, bool load_zones, Purpose purpose) { return NULL; } Monitor *monitor = new Monitor(); - monitor->Load(dbrow.mysql_row(),load_zones,purpose); + monitor->Load(dbrow.mysql_row(), load_zones, purpose); +#if 0 + // We are explicitly connecting now if ( purpose == CAPTURE ) { Debug(1,"Connecting"); if ( ! ( @@ -759,6 +761,7 @@ Monitor *Monitor::Load(unsigned int p_id, bool load_zones, Purpose purpose) { return NULL; } } +#endif return monitor; } // end Monitor *Monitor::Load(unsigned int p_id, bool load_zones, Purpose purpose) @@ -1131,6 +1134,7 @@ uint64_t Monitor::GetLastEventId() const { // This function is crap. double Monitor::GetFPS() const { + return capture_fps; // last_write_index is the last capture index. It starts as == image_buffer_count so that the first asignment % image_buffer_count = 0; int index1 = shared_data->last_write_index; if ( index1 >= image_buffer_count ) { @@ -1593,14 +1597,17 @@ void Monitor::UpdateAnalysisFPS() { struct timeval now; gettimeofday(&now, NULL); double new_analysis_fps = double(fps_report_interval)/(now.tv_sec - last_analysis_fps_time); - Info("%s: %d - Analysing at %.2f fps", name, image_count, new_analysis_fps); + Info("%s: %d - Analysing at %.2f fps", name, analysis_image_count, new_analysis_fps); if ( new_analysis_fps != analysis_fps ) { analysis_fps = new_analysis_fps; char sql[ZM_SQL_SML_BUFSIZ]; - snprintf(sql, sizeof(sql), "INSERT INTO Monitor_Status (MonitorId,AnalysisFPS) VALUES (%d, %.2lf) ON DUPLICATE KEY UPDATE AnalysisFPS = %.2lf", id, analysis_fps, analysis_fps); + snprintf(sql, sizeof(sql), + "INSERT INTO Monitor_Status (MonitorId,AnalysisFPS) VALUES (%d, %.2lf)" + " ON DUPLICATE KEY UPDATE AnalysisFPS = %.2lf", + id, analysis_fps, analysis_fps); db_mutex.lock(); - if ( mysql_query( &dbconn, sql ) ) { + if ( mysql_query(&dbconn, sql) ) { Error("Can't run query: %s", mysql_error(&dbconn)); } db_mutex.unlock(); @@ -1633,20 +1640,14 @@ bool Monitor::Analyse() { // get_analysis_packet will lock the packet while ( ( snap = packetqueue->get_analysis_packet() ) && ( snap->score == -1 ) ) { unsigned int index = snap->image_index; - Debug(2, "Analysis index (%d), last_Write(%d)", index, shared_data->last_write_index); - if ( index == shared_data->last_read_index ) { - Debug(2, "Returning because we are re-analyzing"); - return 0; - } packets_processed += 1; - if ( snap->image_index == -1 ) { + if ( snap->packet.stream_index != video_stream_id ) { snap->unlock(); Debug(2, "skipping because audio"); // We want to skip, but if we return, we may sleep. - // - if ( ! packetqueue->increment_analysis_it() ) { + if ( !packetqueue->increment_analysis_it() ) { Debug(2, "No more packets to analyse"); return false; } @@ -1662,7 +1663,7 @@ bool Monitor::Analyse() { // if we have been told to be OFF, then we are off and don't do any processing. if ( trigger_data->trigger_state != TRIGGER_OFF ) { - Debug(4, "Trigger not oFF state is (%d)", trigger_data->trigger_state ); + Debug(4, "Trigger not oFF state is (%d)", trigger_data->trigger_state); unsigned int score = 0; // Ready means that we have captured the warmpup # of frames if ( Ready() ) { @@ -1688,7 +1689,7 @@ bool Monitor::Analyse() { if ( !signal ) { signalText = "Lost"; if ( event ) { - Info( "%s: %03d - Closing event %" PRIu64 ", signal loss", name, analysis_image_count, event->Id() ); + Info("%s: %03d - Closing event %" PRIu64 ", signal loss", name, analysis_image_count, event->Id()); closeEvent(); last_section_mod = 0; } @@ -1696,7 +1697,7 @@ bool Monitor::Analyse() { signalText = "Reacquired"; score += 100; } - Warning( "%s: %s", SIGNAL_CAUSE, signalText ); + Warning("%s: %s", SIGNAL_CAUSE, signalText); if ( !event ) { if ( cause.length() ) cause += ", "; @@ -1717,11 +1718,16 @@ bool Monitor::Analyse() { Event::StringSet zoneSet; int motion_score = last_motion_score; if ( !(analysis_image_count % (motion_frame_skip+1) ) ) { - // Get new score. - Debug(3,"before DetectMotion"); - motion_score = DetectMotion( *snap_image, zoneSet ); + if ( snap->image ) { - Debug( 3, "After motion detection, last_motion_score(%d), new motion score(%d)", last_motion_score, motion_score ); + // Get new score. + Debug(3,"before DetectMotion packet index is %d", snap->image_index); + motion_score = DetectMotion( *snap_image, zoneSet ); + + Debug(3, "After motion detection, last_motion_score(%d), new motion score(%d)", last_motion_score, motion_score); + } else { + Warning("No image in snap"); + } // Why are we updating the last_motion_score too? last_motion_score = motion_score; } @@ -1735,10 +1741,11 @@ bool Monitor::Analyse() { noteSetMap[MOTION_CAUSE] = zoneSet; } // end if motion_score shared_data->active = signal; - } + } // if ( Active() && (function == MODECT || function == MOCORD) ) // If we aren't recording, check linked monitors to see if we should be. if ( n_linked_monitors > 0 ) { + Debug(2, "Checking linked monitors"); Event::StringSet noteSet; for ( int i=0; i < n_linked_monitors; i++ ) { if ( ! linked_monitors[i]->isConnected() ) @@ -1762,13 +1769,15 @@ bool Monitor::Analyse() { // If doing record, check to see if we need to close the event or not. if ( event ) { + Debug(2,"Have event in mocard"); if ( section_length ) { // TODO: Wouldn't this be clearer if we just did something like if now - event->start > section_length ? int section_mod = timestamp->tv_sec % section_length; - Debug( 3, "Section length (%d) Last Section Mod(%d), tv_sec(%d) new section mod(%d)", section_length, last_section_mod, timestamp->tv_sec, section_mod ); + Debug(3, "Section length (%d) Last Section Mod(%d), tv_sec(%d) new section mod(%d)", + section_length, last_section_mod, timestamp->tv_sec, section_mod); // This is not clear, but basically due to pauses, etc we might not get section_mod == 0 if ( ( section_mod < last_section_mod ) && ( timestamp->tv_sec >= 10 ) ) { - Info( "%s: %03d - Closing event %llu, section end forced ", name, analysis_image_count, event->Id() ); + Info("%s: %03d - Closing event %llu, section end forced ", name, analysis_image_count, event->Id()); closeEvent(); last_section_mod = 0; } else { @@ -1777,25 +1786,27 @@ bool Monitor::Analyse() { } // end if section_length } // end if event - if ( ! event ) { + if ( !event ) { + Debug(2,"Creating continuous event"); // Create event - event = new Event( this, *timestamp, "Continuous", noteSetMap ); + event = new Event(this, *timestamp, "Continuous", noteSetMap); shared_data->last_event_id = event->Id(); // lets construct alarm cause. It will contain cause + names of zones alarmed - std::string alarm_cause="Continuous"; - for ( int i=0; i < n_zones; i++) { + std::string alarm_cause = "Continuous"; + for ( int i=0; i < n_zones; i++ ) { if (zones[i]->Alarmed()) { alarm_cause += std::string(zones[i]->Label()); - if (i < n_zones-1) { + if ( i < n_zones-1 ) { alarm_cause +=","; } } } alarm_cause = cause+" "+alarm_cause; - strncpy( shared_data->alarm_cause,alarm_cause.c_str() , sizeof(shared_data->alarm_cause) ); + strncpy(shared_data->alarm_cause,alarm_cause.c_str() , sizeof(shared_data->alarm_cause)); video_store_data->recording = event->StartTime(); - Info( "%s: %03d - Opening new event %" PRIu64 ", section start", name, analysis_image_count, event->Id() ); + Info("%s: %03d - Opening new event %" PRIu64 ", section start", + name, analysis_image_count, event->Id()); /* To prevent cancelling out an existing alert\prealarm\alarm state */ if ( state == IDLE ) { shared_data->state = state = TAPE; @@ -1804,47 +1815,49 @@ bool Monitor::Analyse() { } // end if RECORDING if ( score ) { - Debug(9, "Score: (%d)", score ); + Debug(9, "Score: (%d)", score); if ( state == IDLE || state == TAPE || state == PREALARM ) { if ( Event::PreAlarmCount() >= (alarm_frame_count-1) ) { - Info( "%s: %03d - Gone into alarm state", name, analysis_image_count ); + Info("%s: %03d - Gone into alarm state", name, analysis_image_count); shared_data->state = state = ALARM; - if ( ! event ) { - // lets construct alarm cause. It will contain cause + names of zones alarmed - std::string alarm_cause=""; - for ( int i=0; i < n_zones; i++) { + if ( !event ) { + // lets construct alarm cause. It will contain cause + names of zones alarmed + std::string alarm_cause = ""; + for ( int i=0; i < n_zones; i++) { if (zones[i]->Alarmed()) { - alarm_cause += std::string(zones[i]->Label()); - if (i < n_zones-1) { - alarm_cause +=","; - } + alarm_cause += std::string(zones[i]->Label()); + if (i < n_zones-1) { + alarm_cause +=","; + } } - } - alarm_cause = cause+" "+alarm_cause; - strncpy( shared_data->alarm_cause,alarm_cause.c_str() , sizeof(shared_data->alarm_cause) ); - event = new Event( this, *timestamp, cause, noteSetMap ); + } + alarm_cause = cause+" "+alarm_cause; + strncpy(shared_data->alarm_cause,alarm_cause.c_str() , sizeof(shared_data->alarm_cause)); + event = new Event(this, *timestamp, cause, noteSetMap); shared_data->last_event_id = event->Id(); } } else if ( state != PREALARM ) { - Info( "%s: %03d - Gone into prealarm state", name, analysis_image_count ); + Info("%s: %03d - Gone into prealarm state", name, analysis_image_count); shared_data->state = state = PREALARM; } } else if ( state == ALERT ) { - Info( "%s: %03d - Gone back into alarm state", name, analysis_image_count ); + Info("%s: %03d - Gone back into alarm state", name, analysis_image_count); shared_data->state = state = ALARM; } last_alarm_count = analysis_image_count; } else { // no score? if ( state == ALARM ) { - Info("%s: %03d - Gone into alert state", name, analysis_image_count ); + Info("%s: %03d - Gone into alert state", name, analysis_image_count); shared_data->state = state = ALERT; } else if ( state == ALERT ) { if ( analysis_image_count-last_alarm_count > post_event_count ) { - Info("%s: %03d - Left alarm state (%" PRIu64 ") - %d(%d) images", name, analysis_image_count, event->Id(), event->Frames(), event->AlarmFrames() ); + Info("%s: %03d - Left alarm state (%" PRIu64 ") - %d(%d) images", + name, analysis_image_count, event->Id(), event->Frames(), event->AlarmFrames()); //if ( function != MOCORD || event_close_mode == CLOSE_ALARM || event->Cause() == SIGNAL_CAUSE ) if ( (function != RECORD && function != MOCORD ) || event_close_mode == CLOSE_ALARM ) { shared_data->state = state = IDLE; - Info("%s: %03d - Closing event %" PRIu64 ", alarm end%s", name, analysis_image_count, event->Id(), (function==MOCORD)?", section truncated":"" ); + Info("%s: %03d - Closing event %" PRIu64 ", alarm end%s", + name, analysis_image_count, event->Id(), (function==MOCORD)?", section truncated":"" ); closeEvent(); } else { shared_data->state = state = TAPE; @@ -2179,23 +2192,11 @@ int Monitor::Capture() { unsigned int index = 0; //image_count % image_buffer_count; - if ( (index == shared_data->last_read_index) && (function > MONITOR) ) { - Warning("Buffer overrun at index %d, image %d, slow down capture, speed up analysis or increase ring buffer size", index, image_count); - time_t now = time(0); - double approxFps = double(image_buffer_count)/double(now-image_buffer[index].timestamp->tv_sec); - time_t last_read_delta = now - shared_data->last_read_time; - if ( last_read_delta > (image_buffer_count/approxFps) ) { - Warning("Last image read from shared memory %ld seconds ago, zma may have gone away", last_read_delta) - shared_data->last_read_index = image_buffer_count; - } - } else { - Debug(2,"Capture: Last write(capture) index %d, last read(analysis) index %d, current (%d)", - shared_data->last_write_index, shared_data->last_read_index, index ); - } - ZMPacket *packet = new ZMPacket(); + packet->timestamp = image_buffer[index].timestamp; + packet->image_index = image_count; + //&image_buffer[index]; - Debug(2,"before packet lock"); packet->lock(); packet->reset(); Image* capture_image = packet->image; @@ -2208,7 +2209,7 @@ int Monitor::Capture() { } /* Capture a new next image */ captureResult = camera->Capture(*packet); - gettimeofday( packet->timestamp, NULL ); + gettimeofday(packet->timestamp, NULL); if ( FirstCapture ) { packet->unlock(); @@ -2218,7 +2219,7 @@ int Monitor::Capture() { } else { Debug(4, "Capturing"); captureResult = camera->Capture(*packet); - gettimeofday( packet->timestamp, NULL ); + gettimeofday(packet->timestamp, NULL); if ( captureResult < 0 ) { Debug(2,"failed capture"); // Unable to capture image for temporary reason @@ -2275,7 +2276,7 @@ int Monitor::Capture() { //Debug(2,"About to decode"); if ( packet->decode(camera->get_VideoCodecContext()) ) { //Debug(2,"Getimage"); - packet->get_image( image_buffer[index].image ); + packet->get_image(image_buffer[index].image); } // Have an av_packet, } @@ -2287,7 +2288,7 @@ int Monitor::Capture() { Debug(2, "Have video packet for index (%d)", index); packetqueue->queuePacket(packet); } else { - Debug(2, "Not queuing video packet for index (%d)", index); + Debug(2, "Not queuing video packet for index (%d) packet count %d", index, packetqueue->video_packet_count); } //mutex.unlock(); @@ -2364,7 +2365,7 @@ int Monitor::Capture() { Error("Can't run query: %s", mysql_error(&dbconn)); } db_mutex.unlock(); - } + } // now != last_fps_time } // end if report fps } else { // result == 0 // Question is, do we update last_write_index etc? @@ -2462,26 +2463,26 @@ unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &z bool alarm = false; unsigned int score = 0; - if ( n_zones <= 0 ) return( alarm ); + if ( n_zones <= 0 ) return alarm; Storage *storage = this->getStorage(); if ( config.record_diag_images ) { static char diag_path[PATH_MAX] = ""; if ( !diag_path[0] ) { - snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-r.jpg", storage->Path(), id ); + snprintf(diag_path, sizeof(diag_path), "%s/%d/diag-r.jpg", storage->Path(), id); } ref_image.WriteJpeg( diag_path ); } - ref_image.Delta( comp_image, &delta_image ); + ref_image.Delta(comp_image, &delta_image); if ( config.record_diag_images ) { static char diag_path[PATH_MAX] = ""; if ( !diag_path[0] ) { snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-d.jpg", storage->Path(), id ); } - delta_image.WriteJpeg( diag_path ); + delta_image.WriteJpeg(diag_path); } // Blank out all exclusion zones @@ -2493,8 +2494,8 @@ unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &z if ( !zone->IsInactive() ) { continue; } - Debug( 3, "Blanking inactive zone %s", zone->Label() ); - delta_image.Fill( RGB_BLACK, zone->GetPolygon() ); + Debug(3, "Blanking inactive zone %s", zone->Label()); + delta_image.Fill(RGB_BLACK, zone->GetPolygon()); } // Check preclusive zones first @@ -2610,7 +2611,7 @@ unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &z } // This is a small and innocent hack to prevent scores of 0 being returned in alarm state - return( score?score:alarm ); + return score?score:alarm; } bool Monitor::DumpSettings( char *output, bool verbose ) { @@ -2704,7 +2705,9 @@ Monitor::Orientation Monitor::getOrientation() const { return orientation; } // Wait for camera to get an image, and then assign it as the base reference image. So this should be done as the first task in the analysis thread startup. void Monitor::get_ref_image() { ZMPacket * snap; - while ( ((!( snap = packetqueue->get_analysis_packet())) || ( snap->image_index == -1 )) && !zm_terminate) { + while ( ( (!( snap = packetqueue->get_analysis_packet())) + || ( snap->packet.stream_index != video_stream_id ) ) + && !zm_terminate) { Debug(1, "Waiting for capture daemon lastwriteindex(%d) lastwritetime(%d)", shared_data->last_write_index, shared_data->last_write_time); //usleep(10000); diff --git a/src/zm_monitorstream.cpp b/src/zm_monitorstream.cpp index b5a0429e6..af3687f15 100644 --- a/src/zm_monitorstream.cpp +++ b/src/zm_monitorstream.cpp @@ -461,6 +461,8 @@ void MonitorStream::runStream() { temp_read_index = temp_image_buffer_count; temp_write_index = temp_image_buffer_count; + struct timeval last_frame_time; + std::string swap_path; bool buffered_playback = false; @@ -631,9 +633,11 @@ void MonitorStream::runStream() { } } // end if ( buffered_playback && delayed ) - if ( last_read_index != monitor->shared_data->last_write_index ) { // have a new image to send int index = monitor->shared_data->last_write_index % monitor->image_buffer_count; // % shouldn't be neccessary + ZMPacket *snap = &monitor->image_buffer[index]; + if ( tvCmp(last_frame_time, *(snap->timestamp)) ) { + last_read_index = monitor->shared_data->last_write_index; Debug( 2, "index: %d: frame_mod: %d frame count: %d paused(%d) delayed(%d)", index, frame_mod, frame_count, paused, delayed ); if ( (frame_mod == 1) || ((frame_count%frame_mod) == 0) ) { From 240abd824be94499f095e1309fd9069cb0c46826 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 26 Feb 2019 09:45:40 -0500 Subject: [PATCH 0148/2339] Don't use image_index anymore --- src/zm_packetqueue.cpp | 59 ++++++++++-------------------------------- 1 file changed, 14 insertions(+), 45 deletions(-) diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index 94297bd98..4de77be1c 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -19,6 +19,7 @@ #include "zm_packetqueue.h" #include "zm_ffmpeg.h" +#include "zm_signal.h" #include zm_packetqueue::zm_packetqueue( int video_image_count, int p_video_stream_id, int p_audio_stream_id ) { @@ -53,6 +54,7 @@ bool zm_packetqueue::queuePacket( ZMPacket* zm_packet ) { Debug(4, "packetqueue queuepacket, first_video_packet_index is %d", first_video_packet_index); mutex.lock(); +#if 0 if ( zm_packet->image_index != -1 ) { // It's a video packet @@ -87,9 +89,17 @@ bool zm_packetqueue::queuePacket( ZMPacket* zm_packet ) { } // end if video_packet_count += 1; } // end if queuing a video packet - +#endif + if ( zm_packet->packet.stream_index == video_stream_id ) { + video_packet_count += 1; + } pktQueue.push_back(zm_packet); packet_counts[zm_packet->packet.stream_index] += 1; + if ( analysis_it == pktQueue.end() ) { + // Analsys_it should only point to end when queue is empty + Debug(2,"pointing analysis_it to begining"); + analysis_it = pktQueue.begin(); + } #if 0 // This code should not be neccessary. Taken care of by the above code that ensure that no packet appears twice @@ -218,7 +228,7 @@ unsigned int zm_packetqueue::clearQueue(unsigned int frames_to_keep, int stream_ } packet_counts[packet->packet.stream_index] -= 1; pktQueue.pop_front(); - if ( packet->image_index == -1 ) + //if ( packet->image_index == -1 ) delete packet; delete_count += 1; @@ -249,7 +259,7 @@ void zm_packetqueue::clearQueue() { packet = pktQueue.front(); packet_counts[packet->packet.stream_index] -= 1; pktQueue.pop_front(); - if ( packet->image_index == -1 ) + //if ( packet->image_index == -1 ) delete packet; delete_count += 1; } @@ -276,7 +286,7 @@ int zm_packetqueue::packet_count( int stream_id ) { ZMPacket *zm_packetqueue::get_analysis_packet() { mutex.lock(); - while ( (! pktQueue.size()) || ( analysis_it == pktQueue.end() ) ) { + while ( ((! pktQueue.size()) || ( analysis_it == pktQueue.end() )) && !zm_terminate ) { Debug(2,"waiting. Queue size %d analysis_it == end? %d", pktQueue.size(), ( analysis_it == pktQueue.end() ) ); condition->wait(); @@ -305,44 +315,3 @@ bool zm_packetqueue::increment_analysis_it( ) { analysis_it = next_it; return true; } // end bool zm_packetqueue::increment_analysis_it( ) - -// Locks the packet, but also removes it from the queue including analysis_it -void zm_packetqueue::lock_packet( ZMPacket &packet ) { - mutex.lock(); - if ( packet.image_index != -1 ) { - // It's a video packet - - // If we can never queue the same packet, then they can never go past - if ( packet.image_index == first_video_packet_index ) { - Debug(2, "queuing packet that is already on the queue(%d)", packet.image_index); - while ( pktQueue.size() ) { - mutex.unlock(); - ZMPacket *p = popPacket(); - Debug(2,"Front packet index: %d", p->image_index); - mutex.lock(); - - if ( p->codec_type != AVMEDIA_TYPE_VIDEO ) { - Debug(2, "Deleting audio frame(%d)", p->image_index); - delete p; - p = NULL; - } - Debug(2,"pktQueue.size(%d)", pktQueue.size()); - if ( p->image_index == packet.image_index ) - break; - } // end while there are packets at the head of the queue that are not this one - - if ( analysis_it == pktQueue.end() ) { - // Analsys_it should only point to end when queue is empty - Debug(2,"pointing analysis_it to begining"); - analysis_it = pktQueue.begin(); - } - } - if ( first_video_packet_index == -1 ) { - // Initialize the first_video_packet indicator - first_video_packet_index = packet.image_index; - } // end if - video_packet_count += 1; - } // end if queuing a video packet - packet.lock(); - mutex.unlock(); -} From 56d41e8f509fe1bd47d22a0fafd8984ab015f4c6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 26 Feb 2019 09:45:51 -0500 Subject: [PATCH 0149/2339] drop lock_packet --- src/zm_packetqueue.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/zm_packetqueue.h b/src/zm_packetqueue.h index b87ccba33..b61c06f31 100644 --- a/src/zm_packetqueue.h +++ b/src/zm_packetqueue.h @@ -61,7 +61,6 @@ class zm_packetqueue { // Functions to manage the analysis frame logic bool increment_analysis_it(); ZMPacket *get_analysis_packet(); - void lock_packet( ZMPacket &packet ); }; #endif /* ZM_PACKETQUEUE_H */ From 8bbcf0f6315a3f94b49b3996c66c9de9fe9573e1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 25 Apr 2019 14:49:16 -0400 Subject: [PATCH 0150/2339] merge storageareas --- src/zm_event.cpp | 12 +- src/zm_event.h | 5 +- src/zm_ffmpeg_camera.cpp | 9 - src/zm_monitor.cpp | 75 +++--- src/zm_videostore.cpp | 503 +++++++-------------------------------- src/zm_videostore.h | 7 +- 6 files changed, 132 insertions(+), 479 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 8938a6ae0..7ec2bbf8e 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -192,14 +192,14 @@ Event::Event( Error("Can't fopen %s: %s", id_file.c_str(), strerror(errno)); } // deep storage or not - Debug(2,"Created event %d at %s", id, path.c_str()); + Debug(2, "Created event %d at %s", id, path.c_str()); last_db_frame = 0; video_name[0] = 0; - snprintf(snapshot_file, sizeof(snapshot_file), "%s/snapshot.jpg", path); - snprintf(alarm_file, sizeof(alarm_file), "%s/alarm.jpg", path); + snapshot_file = path + "/snapshot.jpg"; + alarm_file = path + "/alarm.jpg"; /* Save as video */ @@ -562,12 +562,9 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a if ( (!alarm_frame_written) && (score > 0) ) { write_to_db = true; // OD processing will need it, so the db needs to know about it alarm_frame_written = true; - WriteFrameImage(image, timestamp, alarm_file); + WriteFrameImage(image, timestamp, alarm_file.c_str()); } } // end if save_jpegs - if ( videowriter != NULL ) { - WriteFrameVideo(image, timestamp, videowriter); - } struct DeltaTimeval delta_time; DELTA_TIMEVAL(delta_time, timestamp, start_time, DT_PREC_2); @@ -625,6 +622,7 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a if ( alarm_image ) { if ( save_jpegs & 2 ) { + static char event_file[PATH_MAX]; snprintf(event_file, sizeof(event_file), staticConfig.analyse_file_format, path.c_str(), frames); Debug(1, "Writing analysis frame %d", frames); if ( ! WriteFrameImage(alarm_image, timestamp, event_file, true) ) { diff --git a/src/zm_event.h b/src/zm_event.h index f9aa2dbb0..56fa38cf5 100644 --- a/src/zm_event.h +++ b/src/zm_event.h @@ -92,8 +92,9 @@ class Event { unsigned int max_score; std::string path; VideoStore *videoStore; - char snapshot_file[PATH_MAX]; - char alarm_file[PATH_MAX]; + std::string snapshot_file; + std::string alarm_file; + VideoWriter* videowriter; char video_name[PATH_MAX]; char video_file[PATH_MAX]; diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 088049b7b..62ebd6237 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -144,9 +144,6 @@ FfmpegCamera::~FfmpegCamera() { Close(); - if ( capture ) { - Terminate(); - } FFMPEGDeInit(); } @@ -493,12 +490,6 @@ int FfmpegCamera::Close() { mRawFrame = NULL; } - - if ( videoStore ) { - delete videoStore; - videoStore = NULL; - } - if ( mVideoCodecContext ) { avcodec_close(mVideoCodecContext); Debug(1,"After codec close"); diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 61f896ede..ace096abc 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -565,6 +565,11 @@ void Monitor::Load(MYSQL_ROW dbrow, bool load_zones=true, Purpose p = QUERY) { Error("Can't mkdir %s: %s", monitor_dir, strerror(errno)); } } + } else if ( purpose == ANALYSIS ) { + if ( config.record_diag_images ) { + diag_path_r = stringtf("%s/%d/diag-r.jpg", storage->Path(), id); + diag_path_d = stringtf("%s/%d/diag-d.jpg", storage->Path(), id); + } } //this0>delta_image( width, height, ZM_COLOUR_GRAY8, ZM_SUBPIX_ORDER_NONE ), @@ -762,10 +767,6 @@ Monitor *Monitor::Load(unsigned int p_id, bool load_zones, Purpose purpose) { } } #endif - if ( config.record_diag_images ) { - diag_path_r = stringtf("%s/%d/diag-r.jpg", storage->Path(), id); - diag_path_d = stringtf("%s/%d/diag-d.jpg", storage->Path(), id); - } return monitor; } // end Monitor *Monitor::Load(unsigned int p_id, bool load_zones, Purpose purpose) @@ -1196,7 +1197,6 @@ double Monitor::GetFPS() const { /* I think this returns the # of micro seconds that we should sleep in order to maintain the desired analysis rate */ useconds_t Monitor::GetAnalysisRate() { -<<<<<<< HEAD capture_fps = GetFPS(); if ( !analysis_fps_limit ) { return 0; @@ -2405,48 +2405,47 @@ int Monitor::Capture() { } // end Monitor::Capture void Monitor::TimestampImage( Image *ts_image, const struct timeval *ts_time ) const { - if ( label_format[0] ) { - // Expand the strftime macros first - char label_time_text[256]; - strftime( label_time_text, sizeof(label_time_text), label_format, localtime( &ts_time->tv_sec ) ); + if ( !label_format[0] ) + return; - char label_text[1024]; - const char *s_ptr = label_time_text; - char *d_ptr = label_text; - while ( *s_ptr && ((d_ptr-label_text) < (unsigned int)sizeof(label_text)) ) { - if ( *s_ptr == config.timestamp_code_char[0] ) { - bool found_macro = false; - switch ( *(s_ptr+1) ) { - case 'N' : - d_ptr += snprintf( d_ptr, sizeof(label_text)-(d_ptr-label_text), "%s", name ); - found_macro = true; - break; - case 'Q' : - d_ptr += snprintf( d_ptr, sizeof(label_text)-(d_ptr-label_text), "%s", trigger_data->trigger_showtext ); - found_macro = true; - break; - case 'f' : - d_ptr += snprintf( d_ptr, sizeof(label_text)-(d_ptr-label_text), "%02ld", ts_time->tv_usec/10000 ); - found_macro = true; - break; - } - if ( found_macro ) { - s_ptr += 2; - continue; - } + // Expand the strftime macros first + char label_time_text[256]; + strftime( label_time_text, sizeof(label_time_text), label_format, localtime( &ts_time->tv_sec ) ); + + char label_text[1024]; + const char *s_ptr = label_time_text; + char *d_ptr = label_text; + while ( *s_ptr && ((d_ptr-label_text) < (unsigned int)sizeof(label_text)) ) { + if ( *s_ptr == config.timestamp_code_char[0] ) { + bool found_macro = false; + switch ( *(s_ptr+1) ) { + case 'N' : + d_ptr += snprintf( d_ptr, sizeof(label_text)-(d_ptr-label_text), "%s", name ); + found_macro = true; + break; + case 'Q' : + d_ptr += snprintf( d_ptr, sizeof(label_text)-(d_ptr-label_text), "%s", trigger_data->trigger_showtext ); + found_macro = true; + break; + case 'f' : + d_ptr += snprintf( d_ptr, sizeof(label_text)-(d_ptr-label_text), "%02ld", ts_time->tv_usec/10000 ); + found_macro = true; + break; + } + if ( found_macro ) { + s_ptr += 2; + continue; } } *d_ptr++ = *s_ptr++; } // end while *d_ptr = '\0'; - ts_image->Annotate( label_text, label_coord, label_size ); + ts_image->Annotate(label_text, label_coord, label_size); } // end void Monitor::TimestampImage bool Monitor::closeEvent() { - if ( event ) { - if ( function == RECORD || function == MOCORD ) { - gettimeofday(&(event->EndTime()), NULL); - } + if ( !event ) + return true; #if 0 if ( event_delete_thread ) { event_delete_thread->join(); diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index de049931f..0ef04d932 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -46,10 +46,7 @@ VideoStore::VideoStore( Monitor *p_monitor ) { -<<<<<<< HEAD monitor = p_monitor; -======= ->>>>>>> storageareas video_in_stream = p_video_in_stream; video_in_stream_index = -1; audio_in_stream = p_audio_in_stream; @@ -62,6 +59,8 @@ VideoStore::VideoStore( in_frame = NULL; video_in_frame = NULL; video_in_ctx = NULL; + // In future, we should just pass in the codec context instead of the stream. Don't really need the stream. + video_in_ctx = video_in_stream->codec; video_out_ctx = NULL; video_out_codec = NULL; @@ -81,13 +80,7 @@ VideoStore::VideoStore( fifo = NULL; #endif #endif -<<<<<<< HEAD FFMPEGInit(); -======= - - // In future, we should just pass in the codec context instead of the stream. Don't really need the stream. - video_in_ctx = video_in_stream->codec; ->>>>>>> storageareas video_start_pts = 0; audio_next_pts = 0; @@ -120,36 +113,26 @@ bool VideoStore::open() { filename, format); return false; } else { -<<<<<<< HEAD - Debug(4, "Success alocating out ctx"); -======= Debug(4, "Success allocating out ctx"); ->>>>>>> storageareas } } // end if ! oc Debug(2, "Success opening output contect"); AVDictionary *pmetadata = NULL; -<<<<<<< HEAD ret = av_dict_set(&pmetadata, "title", "Zoneminder Security Recording", 0); if ( ret < 0 ) Warning("%s:%d: title set failed", __FILE__, __LINE__); -======= - int dsr = - av_dict_set(&pmetadata, "title", "Zoneminder Security Recording", 0); - if ( dsr < 0 ) Warning("%s:%d: title set failed", __FILE__, __LINE__); ->>>>>>> storageareas oc->metadata = pmetadata; out_format = oc->oformat; out_format->flags |= AVFMT_TS_NONSTRICT; // allow non increasing dts -<<<<<<< HEAD if ( video_in_stream ) { video_in_stream_index = video_in_stream->index; #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) video_in_ctx = avcodec_alloc_context3(NULL); Debug(2, "copy to video_in_context"); - if ( (ret=avcodec_parameters_to_context(video_in_ctx, video_in_stream->codecpar)) < 0 ) { + ret = avcodec_parameters_to_context(video_in_ctx, video_in_stream->codecpar); + if ( ret < 0 ) { Error("Couldn't copy params to context"); return false; } else { @@ -160,23 +143,6 @@ bool VideoStore::open() { Debug(2,"Copied video context from input stream"); zm_dump_codec(video_in_ctx); #endif - // Fix deprecated formats - switch ( video_in_ctx->pix_fmt ) { - case AV_PIX_FMT_YUVJ420P : - video_in_ctx->pix_fmt = AV_PIX_FMT_YUV420P; - break; - case AV_PIX_FMT_YUVJ422P : - video_in_ctx->pix_fmt = AV_PIX_FMT_YUV422P; - break; - case AV_PIX_FMT_YUVJ444P : - video_in_ctx->pix_fmt = AV_PIX_FMT_YUV444P; - break; - case AV_PIX_FMT_YUVJ440P : - video_in_ctx->pix_fmt = AV_PIX_FMT_YUV440P; - break; - default: - break; - } } else { Debug(2, "No input ctx"); video_in_ctx = avcodec_alloc_context3(NULL); @@ -197,12 +163,12 @@ bool VideoStore::open() { Debug(2, "No codec_tag, setting to %d", video_out_ctx->codec_tag); } int wanted_codec = monitor->OutputCodec(); - if ( ! wanted_codec ) { + if ( !wanted_codec ) { // default to h264 wanted_codec = AV_CODEC_ID_H264; } - // // FIXME SHould check that we are set to passthrough + // FIXME SHould check that we are set to passthrough. Might be same codec, but want privacy overlays if ( video_in_stream && ( video_in_ctx->codec_id == wanted_codec ) ) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) ret = avcodec_parameters_to_context(video_out_ctx, video_in_stream->codecpar); @@ -283,17 +249,11 @@ bool VideoStore::open() { video_out_ctx->time_base = AV_TIME_BASE_Q; } video_out_stream->time_base = video_in_stream->time_base; - //video_out_ctx->gop_size = 12; - //video_out_ctx->qmin = 10; - //video_out_ctx->qmax = 51; - //video_out_ctx->qcompress = 0.6; - video_out_ctx->bit_rate = 400*1024; - video_out_ctx->thread_count = 0; if ( video_out_ctx->codec_id == AV_CODEC_ID_H264 ) { video_out_ctx->max_b_frames = 1; if ( video_out_ctx->priv_data ) { - av_opt_set(video_out_ctx->priv_data, "crf", "1", AV_OPT_SEARCH_CHILDREN); + //av_opt_set(video_out_ctx->priv_data, "crf", "1", AV_OPT_SEARCH_CHILDREN); //av_opt_set(video_out_ctx->priv_data, "preset", "ultrafast", 0); } else { Debug(2, "Not setting priv_data"); @@ -330,209 +290,36 @@ bool VideoStore::open() { AVDictionaryEntry *e = NULL; while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { - Warning( "Encoder Option %s not recognized by ffmpeg codec", e->key); + Warning("Encoder Option %s not recognized by ffmpeg codec", e->key); } av_dict_free(&opts); if ( video_out_codec ) break; } // end foreach codec - if ( ! video_out_codec ) { + if ( !video_out_codec ) { Error("Can't open video codec!"); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) // We allocate and copy in newer ffmpeg, so need to free it avcodec_free_context(&video_out_ctx); -======= - video_out_codec = avcodec_find_encoder(video_in_ctx->codec_id); - if ( !video_out_codec ) { -#if (LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 11, 0) && (LIBAVFORMAT_VERSION_MICRO >= 100)) - Fatal("Could not find encoder for '%s'", avcodec_get_name(video_out_ctx->codec_id)); -#else - Fatal("Could not find encoder for '%d'", video_out_ctx->codec_id); -#endif - } - - video_out_stream = avformat_new_stream(oc, NULL); - if ( !video_out_stream ) { - Error("Unable to create video out stream"); - return; - } else { - Debug(2, "Success creating video out stream"); - } - -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - // by allocating our own copy, we don't run into the problems when we free the streams - video_out_ctx = avcodec_alloc_context3(video_out_codec); - // Since we are not re-encoding, all we have to do is copy the parameters - // Copy params from instream to ctx - ret = avcodec_parameters_to_context(video_out_ctx, video_in_stream->codecpar); - if ( ret < 0 ) { - Error("Could not initialize video_out_ctx parameters"); - return; - } -#else - video_out_ctx = video_out_stream->codec; - // This will wipe out the codec defaults - ret = avcodec_copy_context(video_out_ctx, video_in_ctx); - if ( ret < 0 ) { - Fatal("Unable to copy in video ctx to out video ctx %s", - av_make_error_string(ret).c_str()); - } else { - Debug(3, "Success copying ctx"); - } -#endif - - // Just copy them from the in, no reason to choose different - video_out_ctx->time_base = video_in_ctx->time_base; - if ( ! (video_out_ctx->time_base.num && video_out_ctx->time_base.den) ) { - Debug(2,"No timebase found in video in context, defaulting to Q"); - video_out_ctx->time_base = AV_TIME_BASE_Q; - } - - zm_dump_codec(video_out_ctx); - -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - //// Fix deprecated formats - switch ( video_out_ctx->pix_fmt ) { - case AV_PIX_FMT_YUVJ422P : - video_out_ctx->pix_fmt = AV_PIX_FMT_YUV422P; - break; - case AV_PIX_FMT_YUVJ444P : - video_out_ctx->pix_fmt = AV_PIX_FMT_YUV444P; - break; - case AV_PIX_FMT_YUVJ440P : - video_out_ctx->pix_fmt = AV_PIX_FMT_YUV440P; - break; - case AV_PIX_FMT_NONE : - case AV_PIX_FMT_YUVJ420P : - default: - video_out_ctx->pix_fmt = AV_PIX_FMT_YUV420P; - break; - } - - if ( !video_out_ctx->codec_tag ) { - Debug(2, "No codec_tag"); - if ( - !oc->oformat->codec_tag - || - av_codec_get_id(oc->oformat->codec_tag, video_in_ctx->codec_tag) == video_out_ctx->codec_id - || - av_codec_get_tag(oc->oformat->codec_tag, video_in_ctx->codec_id) <= 0 - ) { - Warning("Setting codec tag"); - video_out_ctx->codec_tag = video_in_ctx->codec_tag; - } - } -#endif - - video_out_stream->time_base = video_in_stream->time_base; - if ( video_in_stream->avg_frame_rate.num ) { - Debug(3,"Copying avg_frame_rate (%d/%d)", - video_in_stream->avg_frame_rate.num, - video_in_stream->avg_frame_rate.den - ); - video_out_stream->avg_frame_rate = video_in_stream->avg_frame_rate; - } - if ( video_in_stream->r_frame_rate.num ) { - Debug(3,"Copying r_frame_rate (%d/%d) to out (%d/%d)", - video_in_stream->r_frame_rate.num, - video_in_stream->r_frame_rate.den , - video_out_stream->r_frame_rate.num, - video_out_stream->r_frame_rate.den - ); - video_out_stream->r_frame_rate = video_in_stream->r_frame_rate; - } -#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) -#if 0 - if ( video_out_ctx->codec_id == AV_CODEC_ID_H264 ) { - //video_out_ctx->level = 32;I// - video_out_ctx->bit_rate = 400*1024; - video_out_ctx->max_b_frames = 1; - if ( video_out_ctx->priv_data ) { - av_opt_set(video_out_ctx->priv_data, "crf", "1", AV_OPT_SEARCH_CHILDREN); - av_opt_set(video_out_ctx->priv_data, "preset", "ultrafast", 0); - } else { - Debug(2, "Not setting priv_data"); - } - } -#endif - ret = avcodec_parameters_from_context(video_out_stream->codecpar, video_out_ctx); - if ( ret < 0 ) { - Error("Could not initialize video_out_ctx parameters"); - return; - } else { - zm_dump_codec(video_out_ctx); - } - - zm_dump_codecpar(video_in_stream->codecpar); - zm_dump_codecpar(video_out_stream->codecpar); -#endif - Debug(3, - "Time bases: VIDEO in stream (%d/%d) in codec: (%d/%d) out " - "stream: (%d/%d) out codec (%d/%d)", - video_in_stream->time_base.num, video_in_stream->time_base.den, - video_in_ctx->time_base.num, video_in_ctx->time_base.den, - video_out_stream->time_base.num, video_out_stream->time_base.den, - video_out_ctx->time_base.num, video_out_ctx->time_base.den); - - if ( oc->oformat->flags & AVFMT_GLOBALHEADER ) { -#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) - video_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; -#else - video_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; ->>>>>>> storageareas #endif video_out_ctx = NULL; -<<<<<<< HEAD return false; } // end if can't open codec - Debug(2,"Sucess opening codec"); + Debug(2, "Sucess opening codec"); - } // end if copying or trasncoding + } // end if copying or transcoding if ( !video_out_ctx->codec_tag ) { video_out_ctx->codec_tag = av_codec_get_tag(oc->oformat->codec_tag, video_out_ctx->codec_id); Debug(2, "No codec_tag, setting to h264 ? "); -======= -#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) - AVDictionary *opts = 0; - if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) { - Warning("Can't open video codec (%s) %s", - video_out_codec->name, - av_make_error_string(ret).c_str() - ); - video_out_codec = NULL; - } - - AVDictionaryEntry *e = NULL; - while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { - Warning("Encoder Option %s not recognized by ffmpeg codec", e->key); - } -#endif - - Monitor::Orientation orientation = monitor->getOrientation(); - if ( orientation ) { - if ( orientation == Monitor::ROTATE_0 ) { - } else if ( orientation == Monitor::ROTATE_90 ) { - dsr = av_dict_set(&video_out_stream->metadata, "rotate", "90", 0); - if ( dsr < 0 ) Warning("%s:%d: title set failed", __FILE__, __LINE__); - } else if ( orientation == Monitor::ROTATE_180 ) { - dsr = av_dict_set(&video_out_stream->metadata, "rotate", "180", 0); - if ( dsr < 0 ) Warning("%s:%d: title set failed", __FILE__, __LINE__); - } else if ( orientation == Monitor::ROTATE_270 ) { - dsr = av_dict_set(&video_out_stream->metadata, "rotate", "270", 0); - if ( dsr < 0 ) Warning("%s:%d: title set failed", __FILE__, __LINE__); - } else { - Warning("Unsupported Orientation(%d)", orientation); - } ->>>>>>> storageareas } video_out_stream = avformat_new_stream(oc, video_out_codec); - if ( ! video_out_stream ) { + if ( !video_out_stream ) { Error("Unable to create video out stream"); return false; } @@ -556,29 +343,28 @@ bool VideoStore::open() { audio_next_dts = 0; if ( audio_in_stream ) { -<<<<<<< HEAD audio_in_stream_index = audio_in_stream->index; #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) audio_in_ctx = avcodec_alloc_context3(NULL); ret = avcodec_parameters_to_context(audio_in_ctx, audio_in_stream->codecpar); audio_in_ctx->time_base = audio_in_stream->time_base; -======= - Debug(3, "Have audio stream"); +#else + audio_in_ctx = audio_in_stream->codec; +#endif if ( #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) audio_in_stream->codecpar->codec_id ->>>>>>> storageareas #else audio_in_stream->codec->codec_id #endif - != AV_CODEC_ID_AAC ) { + ) { audio_out_codec = avcodec_find_encoder(AV_CODEC_ID_AAC); if ( !audio_out_codec ) { Error("Could not find codec for AAC"); - return; + return false; } #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) @@ -588,7 +374,7 @@ bool VideoStore::open() { if ( !audio_out_ctx ) { Error("could not allocate codec ctx for AAC"); audio_out_stream = NULL; - return; + return false; } #else audio_out_stream = avformat_new_stream(oc, audio_out_codec); @@ -605,7 +391,7 @@ bool VideoStore::open() { audio_out_stream = avformat_new_stream(oc, NULL); if ( !audio_out_stream ) { Error("Could not allocate new stream"); - return; + return false; } audio_out_stream->time_base = audio_in_stream->time_base; @@ -614,7 +400,7 @@ bool VideoStore::open() { audio_out_ctx = avcodec_alloc_context3(audio_out_codec); if ( !audio_out_ctx ) { Error("Could not allocate new output_context"); - return; + return false; } // We don't actually care what the time_base is.. @@ -644,23 +430,6 @@ bool VideoStore::open() { } // end if audio_out_ctx->codec_tag = 0; #endif -<<<<<<< HEAD - if ( ret < 0 ) { - Error("Unable to copy audio ctx %s", - av_make_error_string(ret).c_str()); - audio_out_stream = NULL; - } else { - if ( audio_out_ctx->channels > 1 ) { - Warning("Audio isn't mono, changing it."); - audio_out_ctx->channels = 1; - } else { - Debug(3, "Audio is mono"); - } - } - } // end if audio_out_stream - } // end if is AAC -======= ->>>>>>> storageareas if ( audio_out_ctx->channels > 1 ) { Warning("Audio isn't mono, changing it."); @@ -672,36 +441,18 @@ bool VideoStore::open() { if ( oc->oformat->flags & AVFMT_GLOBALHEADER ) { #if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) -<<<<<<< HEAD - audio_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; -#else - audio_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; -======= audio_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; #else audio_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; ->>>>>>> storageareas #endif } } // end if audio_in_stream -<<<<<<< HEAD /* open the out file, if needed */ if ( !(out_format->flags & AVFMT_NOFILE) ) { if ( (ret = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE, NULL, NULL) ) < 0 ) { Error("Could not open out file '%s': %s", filename, av_make_error_string(ret).c_str()); -======= -} // VideoStore::VideoStore - -bool VideoStore::open() { - /* open the out file, if needed */ - if ( !(out_format->flags & AVFMT_NOFILE) ) { - ret = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE, NULL, NULL); - if ( ret < 0 ) { - Error("Could not open out file '%s': %s", filename, - av_make_error_string(ret).c_str()); ->>>>>>> storageareas return false; } } @@ -710,27 +461,18 @@ bool VideoStore::open() { if (audio_out_stream) zm_dump_stream_format(oc, 1, 0, 1); AVDictionary *opts = NULL; -<<<<<<< HEAD - av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0); -======= // av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0); // Shiboleth reports that this may break seeking in mp4 before it downloads //av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0); // av_dict_set(&opts, "movflags", // "frag_keyframe+empty_moov+default_base_moof", 0); ->>>>>>> storageareas if ( (ret = avformat_write_header(oc, &opts)) < 0 ) { // if ((ret = avformat_write_header(oc, &opts)) < 0) { Warning("Unable to set movflags to frag_custom+dash+delay_moov"); /* Write the stream header, if any. */ ret = avformat_write_header(oc, NULL); -<<<<<<< HEAD } else if ( av_dict_count(opts) != 0 ) { - Warning("some options not set\n"); -======= - } else if (av_dict_count(opts) != 0) { Warning("some options not set"); ->>>>>>> storageareas } if ( opts ) av_dict_free(&opts); if ( ret < 0 ) { @@ -786,31 +528,9 @@ void VideoStore::flush_codecs() { pkt.data = NULL; pkt.size = 0; av_init_packet(&pkt); -<<<<<<< HEAD #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) if ( (ret = avcodec_receive_packet(video_out_ctx, &pkt)) < 0 ) { if ( AVERROR_EOF != ret ) { -======= -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - // Put encoder into flushing mode - avcodec_send_frame(audio_out_ctx, NULL); -#endif - - while (1) { -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - ret = avcodec_receive_packet(audio_out_ctx, &pkt); - if ( ret < 0 ) { - if ( AVERROR_EOF != ret ) { - Error("Error encoding audio while flushing (%d) (%s)", ret, - av_err2str(ret)); - } - break; - } -#else - int got_packet = 0; - ret = avcodec_encode_audio2(audio_out_ctx, &pkt, NULL, &got_packet); - if ( ret < 0 ) { ->>>>>>> storageareas Error("Error encoding audio while flushing (%d) (%s)", ret, av_err2str(ret)); } @@ -826,7 +546,6 @@ void VideoStore::flush_codecs() { break; } #endif -<<<<<<< HEAD write_video_packet(pkt); zm_av_packet_unref(&pkt); } // while have buffered frames @@ -861,7 +580,7 @@ void VideoStore::flush_codecs() { zm_av_packet_unref(&pkt); } // while have buffered frames } // end if audio_out_codec -} +} // end flush_codecs VideoStore::~VideoStore() { if ( oc->pb ) { @@ -869,17 +588,9 @@ VideoStore::~VideoStore() { Debug(2,"Different codecs between in and out"); flush_codecs(); } // end if buffers -======= - pkt.stream_index = audio_out_stream->index; - dumpPacket(audio_out_stream, &pkt, "writing flushed packet"); - av_interleaved_write_frame(oc, &pkt); - zm_av_packet_unref(&pkt); - } // while have buffered frames - } // end if audio_out_codec ->>>>>>> storageareas // Flush Queues - Debug(1,"Flushing interleaved queues"); + Debug(1, "Flushing interleaved queues"); av_interleaved_write_frame(oc, NULL); Debug(1,"Writing trailer"); @@ -901,11 +612,7 @@ VideoStore::~VideoStore() { } else { Debug(3, "Not closing avio because we are not writing to a file."); } -<<<<<<< HEAD } // end if oc->pb -======= - } // end if ( oc->pb ) ->>>>>>> storageareas // I wonder if we should be closing the file first. // I also wonder if we really need to be doing all the ctx @@ -918,7 +625,7 @@ VideoStore::~VideoStore() { // We allocate and copy in newer ffmpeg, so need to free it //avcodec_free_context(&video_in_ctx); #endif - video_in_ctx=NULL; + video_in_ctx = NULL; if ( video_out_codec ) { avcodec_close(video_out_ctx); @@ -996,6 +703,7 @@ bool VideoStore::setup_resampler() { return false; #else +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) // Newer ffmpeg wants to keep everything separate... so have to lookup our own // decoder, can't reuse the one from the camera. audio_in_codec = @@ -1016,19 +724,6 @@ bool VideoStore::setup_resampler() { //audio_in_codec = avcodec_find_decoder(audio_in_stream->codec->codec_id); #endif -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) -#else -#if 0 - ret = avcodec_copy_context(audio_in_ctx, audio_in_stream->codec); - if ( ret < 0 ) { - Fatal("Unable to copy in video ctx to out video ctx %s", - av_make_error_string(ret).c_str()); - } else { - Debug(3, "Success copying ctx"); - } -#endif -#endif - // if the codec is already open, nothing is done. if ( (ret = avcodec_open2(audio_in_ctx, audio_in_codec, NULL)) < 0 ) { Error("Can't open audio in codec!"); @@ -1288,7 +983,7 @@ int VideoStore::writePacket( ZMPacket *ipkt ) { return 0; } -int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { +int VideoStore::writeVideoFramePacket(ZMPacket *zm_packet) { frame_count += 1; // if we have to transcode @@ -1368,6 +1063,9 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { Debug(2, "Not Setting keyframe"); } + av_init_packet(&opkt); + opkt.data = NULL; + opkt.size = 0; #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) // Do this to allow the encoder to choose whether to use I/P/B frame zm_packet->out_frame->pict_type = AV_PICTURE_TYPE_NONE; @@ -1377,9 +1075,6 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { return -1; } - av_init_packet(&opkt); - opkt.data = NULL; - opkt.size = 0; if ( (ret = avcodec_receive_packet(video_out_ctx, &opkt)) < 0 ) { zm_av_packet_unref(&opkt); if ( AVERROR(EAGAIN) == ret ) { @@ -1395,9 +1090,6 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { } //Debug(2, "Got packet using receive_packet, dts:%" PRId64 ", pts:%" PRId64 ", keyframe:%d", opkt.dts, opkt.pts, opkt.flags & AV_PKT_FLAG_KEY ); #else - av_init_packet(&opkt); - opkt.data = NULL; - opkt.size = 0; int data_present; if ( (ret = avcodec_encode_video2( video_out_ctx, &opkt, zm_packet->out_frame, &data_present)) < 0) { @@ -1412,6 +1104,7 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { return 0; } #endif + // Need to adjust pts/dts values from codec time to stream time if ( opkt.pts != AV_NOPTS_VALUE) opkt.pts = av_rescale_q(opkt.pts, video_out_ctx->time_base, video_out_stream->time_base); @@ -1468,12 +1161,12 @@ int VideoStore::writeVideoFramePacket( ZMPacket * zm_packet ) { } else { dumpPacket(video_in_stream, ipkt); if ( ipkt->pts != AV_NOPTS_VALUE ) - opkt.pts = av_rescale_q( ipkt->pts - video_start_pts, video_in_stream->time_base, video_out_stream->time_base ); + opkt.pts = av_rescale_q(ipkt->pts - video_start_pts, video_in_stream->time_base, video_out_stream->time_base); else opkt.pts = 0; if ( ipkt->dts != AV_NOPTS_VALUE ) - opkt.dts = av_rescale_q( ipkt->dts - video_start_pts, video_in_stream->time_base, video_out_stream->time_base ); + opkt.dts = av_rescale_q(ipkt->dts - video_start_pts, video_in_stream->time_base, video_out_stream->time_base); else opkt.dts = 0; @@ -1549,13 +1242,14 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { if ( !audio_out_stream ) { Debug(1, "Called writeAudioFramePacket when no audio_out_stream"); - return 0; // FIXME -ve return codes do not free packet in ffmpeg_camera at - // the moment + return 0; + // FIXME -ve return codes do not free packet in ffmpeg_camera at the moment } dumpPacket(audio_in_stream, ipkt, "input packet"); if ( audio_out_codec ) { Debug(2, "Have output codec"); + #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) if ( ! zm_receive_frame(audio_in_ctx, in_frame, *ipkt) ) { return 0; } @@ -1564,7 +1258,6 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { Error("avcodec_receive_frame fail %s", av_make_error_string(ret).c_str()); return 0; } - zm_dump_frame(in_frame, "In frame from decode"); #else /** * Decode the audio frame stored in the packet. @@ -1577,7 +1270,6 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { audio_in_ctx, in_frame, &data_present, ipkt)) < 0 ) { Error("Could not decode frame (error '%s')", av_make_error_string(ret).c_str()); - dumpPacket(audio_in_stream, ipkt); av_frame_free(&in_frame); return 0; } @@ -1586,6 +1278,7 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { return 0; } #endif + zm_dump_frame(in_frame, "In frame from decode"); int frame_size = out_frame->nb_samples; in_frame->pts = audio_next_pts; @@ -1596,29 +1289,6 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { zm_dump_frame(out_frame, "Out frame after resample"); out_frame->pts = in_frame->pts; - #else - #if defined(HAVE_LIBAVRESAMPLE) - (ret = avresample_convert(resample_ctx, NULL, 0, 0, in_frame->data, - 0, in_frame->nb_samples)) - av_frame_unref(in_frame); - if ( ret < 0 ) { - Error("Could not resample frame (error '%s')", - av_make_error_string(ret).c_str()); - return 0; - } - int samples_available = avresample_available(resample_ctx); - if ( samples_available < frame_size ) { - Debug(1, "Not enough samples yet (%d)", samples_available); - return 0; - } - - // Read a frame audio data from the resample fifo - if ( avresample_read(resample_ctx, out_frame->data, frame_size) != - frame_size) { - Warning("Error reading resampled audio:"); - return 0; - } - audio_next_pts = out_frame->pts + out_frame->nb_samples; av_init_packet(&opkt); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) @@ -1658,9 +1328,6 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { return 0; } #endif -#else - Error("Have audio codec but no resampler?!"); -#endif opkt.duration = av_rescale_q(opkt.duration, audio_in_stream->time_base, audio_out_stream->time_base); @@ -1680,63 +1347,63 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { opkt.duration = ipkt->duration; } - if ( ipkt->duration && (ipkt->duration != AV_NOPTS_VALUE) ) { - opkt.duration = av_rescale_q( - ipkt->duration, + if ( ipkt->duration && (ipkt->duration != AV_NOPTS_VALUE) ) { + opkt.duration = av_rescale_q( + ipkt->duration, + audio_in_stream->time_base, + audio_out_stream->time_base); + } + // Scale the PTS of the outgoing packet to be the correct time base + if ( ipkt->pts != AV_NOPTS_VALUE ) { + if ( !audio_first_pts ) { + opkt.pts = 0; + audio_first_pts = ipkt->pts; + Debug(1, "No audio_first_pts"); + } else { + opkt.pts = av_rescale_q( + ipkt->pts - audio_first_pts, audio_in_stream->time_base, audio_out_stream->time_base); + Debug(2, "audio opkt.pts = %" PRId64 " from ipkt->pts(%" PRId64 ") - first_pts(%" PRId64 ")", + opkt.pts, ipkt->pts, audio_first_pts); } - // Scale the PTS of the outgoing packet to be the correct time base - if ( ipkt->pts != AV_NOPTS_VALUE ) { - if ( !audio_first_pts ) { - opkt.pts = 0; - audio_first_pts = ipkt->pts; - Debug(1, "No audio_first_pts"); - } else { - opkt.pts = av_rescale_q( - ipkt->pts - audio_first_pts, - audio_in_stream->time_base, - audio_out_stream->time_base); - Debug(2, "audio opkt.pts = %" PRId64 " from ipkt->pts(%" PRId64 ") - first_pts(%" PRId64 ")", - opkt.pts, ipkt->pts, audio_first_pts); - } - } else { - Debug(2, "opkt.pts = undef"); - opkt.pts = AV_NOPTS_VALUE; - } + } else { + Debug(2, "opkt.pts = undef"); + opkt.pts = AV_NOPTS_VALUE; + } -// audio_last_dts = ipkt->dts; -if ( opkt.dts > opkt.pts ) { - Debug(1, - "opkt.dts(%" PRId64 ") must be <= opkt.pts(%" PRId64 "). Decompression must happen " - "before presentation.", - opkt.dts, opkt.pts); - opkt.dts = opkt.pts; -} + // audio_last_dts = ipkt->dts; + if ( opkt.dts > opkt.pts ) { + Debug(1, + "opkt.dts(%" PRId64 ") must be <= opkt.pts(%" PRId64 "). Decompression must happen " + "before presentation.", + opkt.dts, opkt.pts); + opkt.dts = opkt.pts; + } -//opkt.duration = out_frame ? out_frame->nb_samples : ipkt->duration; -// opkt.duration = av_rescale_q(ipkt->duration, audio_in_stream->time_base, -// audio_out_stream->time_base); -dumpPacket(audio_out_stream, &opkt); + //opkt.duration = out_frame ? out_frame->nb_samples : ipkt->duration; + // opkt.duration = av_rescale_q(ipkt->duration, audio_in_stream->time_base, + // audio_out_stream->time_base); + dumpPacket(audio_out_stream, &opkt); -// pkt.pos: byte position in stream, -1 if unknown -opkt.pos = -1; -opkt.stream_index = audio_out_stream->index; -audio_next_dts = opkt.dts + opkt.duration; -audio_next_pts = opkt.pts + opkt.duration; + // pkt.pos: byte position in stream, -1 if unknown + opkt.pos = -1; + opkt.stream_index = audio_out_stream->index; + audio_next_dts = opkt.dts + opkt.duration; + audio_next_pts = opkt.pts + opkt.duration; -AVPacket safepkt; -memcpy(&safepkt, &opkt, sizeof(AVPacket)); -ret = av_interleaved_write_frame(oc, &opkt); -if ( ret != 0 ) { - Error("Error writing audio frame packet: %s\n", - av_make_error_string(ret).c_str()); - dumpPacket(audio_out_stream, &safepkt); -} else { - Debug(2, "Success writing audio frame"); -} -zm_av_packet_unref(&opkt); -return 1; + AVPacket safepkt; + memcpy(&safepkt, &opkt, sizeof(AVPacket)); + ret = av_interleaved_write_frame(oc, &opkt); + if ( ret != 0 ) { + Error("Error writing audio frame packet: %s\n", + av_make_error_string(ret).c_str()); + dumpPacket(audio_out_stream, &safepkt); + } else { + Debug(2, "Success writing audio frame"); + } + zm_av_packet_unref(&opkt); + return 1; } // end int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) int VideoStore::write_packets( zm_packetqueue &queue ) { diff --git a/src/zm_videostore.h b/src/zm_videostore.h index 4a87167df..819a193a9 100644 --- a/src/zm_videostore.h +++ b/src/zm_videostore.h @@ -36,16 +36,13 @@ static struct CodecData codec_data[]; AVOutputFormat *out_format; AVFormatContext *oc; AVStream *video_out_stream; - AVStream *audio_out_stream; -int video_in_stream_index; -int audio_in_stream_index; + int video_in_stream_index; + int audio_in_stream_index; AVCodec *video_out_codec; AVCodecContext *video_out_ctx; - AVStream *video_out_stream; AVStream *video_in_stream; - AVStream *audio_in_stream; // Move this into the object so that we aren't constantly allocating/deallocating it on the stack From 37c829f2bf31d9236168ad5763399198dedba709 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 20 Apr 2020 11:19:33 -0400 Subject: [PATCH 0151/2339] cleanup code a bit. Move BlobStats to the Zone Object so that it isn't constantly being allocated/freed from the heap. Improve ParsePolygon. --- src/zm_zone.cpp | 147 +++++++++++++++++++----------------------------- src/zm_zone.h | 21 ++++--- 2 files changed, 68 insertions(+), 100 deletions(-) diff --git a/src/zm_zone.cpp b/src/zm_zone.cpp index 1e0a16cda..d7dc5f40d 100644 --- a/src/zm_zone.cpp +++ b/src/zm_zone.cpp @@ -113,8 +113,10 @@ void Zone::Setup( } if ( config.record_diag_images ) { - snprintf(diag_path, sizeof(diag_path), config.record_diag_images_fifo ? "%s/diagpipe-%d-poly.jpg" : "%s/diag-%d-poly.jpg", monitor->getStorage()->Path(), id); - if (config.record_diag_images_fifo) + snprintf(diag_path, sizeof(diag_path), + config.record_diag_images_fifo ? "%s/diagpipe-%d-poly.jpg" : "%s/diag-%d-poly.jpg", + monitor->getStorage()->Path(), id); + if ( config.record_diag_images_fifo ) FifoStream::fifo_create_if_missing(diag_path); pg_image->WriteJpeg(diag_path, config.record_diag_images_fifo); } else { @@ -129,7 +131,7 @@ Zone::~Zone() { delete[] ranges; } -void Zone::RecordStats( const Event *event ) { +void Zone::RecordStats(const Event *event) { static char sql[ZM_SQL_MED_BUFSIZ]; db_mutex.lock(); snprintf(sql, sizeof(sql), @@ -245,7 +247,7 @@ bool Zone::CheckAlarms(const Image *delta_image) { if ( config.record_diag_images_fifo ) { FifoDebug(5, "{\"zone\":%d,\"type\":\"ALRM\",\"pixels\":%d,\"avg_diff\":%d}", - id,alarm_pixels, pixel_diff); + id, alarm_pixels, pixel_diff); } if ( alarm_pixels ) { @@ -262,11 +264,7 @@ bool Zone::CheckAlarms(const Image *delta_image) { return false; } - if ( max_alarm_pixels != 0 ) - score = (100*alarm_pixels)/max_alarm_pixels; - else - score = (100*alarm_pixels)/polygon.Area(); - + score = (100*alarm_pixels)/(max_alarm_pixels?max_alarm_pixels:polygon.Area()); if ( score < 1 ) score = 1; /* Fix for score of 0 when frame meets thresholds but alarmed area is not big enough */ Debug(5, "Current score is %d", score); @@ -356,8 +354,7 @@ bool Zone::CheckAlarms(const Image *delta_image) { if ( check_method >= BLOBS ) { Debug(5, "Checking for blob pixels"); - typedef struct { unsigned char tag; int count; int lo_x; int hi_x; int lo_y; int hi_y; } BlobStats; - BlobStats blob_stats[256]; + // ICON FIXME Would like to get rid of this memset memset(blob_stats, 0, sizeof(BlobStats)*256); uint8_t *spdiff; uint8_t last_x, last_y; @@ -367,22 +364,15 @@ bool Zone::CheckAlarms(const Image *delta_image) { int lo_x = ranges[y].lo_x; int hi_x = ranges[y].hi_x; - pdiff = (uint8_t*)diff_image->Buffer( lo_x, y ); + pdiff = (uint8_t*)diff_image->Buffer(lo_x, y); for ( int x = lo_x; x <= hi_x; x++, pdiff++ ) { if ( *pdiff == WHITE ) { Debug(9, "Got white pixel at %d,%d (%p)", x, y, pdiff); - //last_x = (x>lo_x)?*(pdiff-1):0; - //last_y = (y>lo_y&&x>=last_lo_x&&x<=last_hi_x)?*(pdiff-diff_width):0; - last_x = 0; - if ( x > 0 ) { - if ( (x-1) >= lo_x ) { - last_x = *(pdiff-1); - } - } + last_x = ((x > 0) && ( (x-1) >= lo_x )) ? *(pdiff-1) : 0; last_y = 0; - if (y > 0 ) { + if ( y > 0 ) { if ( (y-1) >= lo_y && ranges[(y-1)].lo_x <= x && ranges[(y-1)].hi_x >= x ) { last_y = *(pdiff-diff_width); } @@ -629,7 +619,7 @@ bool Zone::CheckAlarms(const Image *delta_image) { } if ( max_blob_pixels != 0 ) - score = (100*alarm_blob_pixels)/(max_blob_pixels); + score = (100*alarm_blob_pixels)/max_blob_pixels; else score = (100*alarm_blob_pixels)/polygon.Area(); @@ -756,67 +746,42 @@ bool Zone::CheckAlarms(const Image *delta_image) { } bool Zone::ParsePolygonString(const char *poly_string, Polygon &polygon) { - Debug(3, "Parsing polygon string '%s'", poly_string); - - char *str_ptr = new char[strlen(poly_string)+1]; - char *str = str_ptr; - strcpy(str, poly_string); + char *str = (char *)poly_string; char *ws; + char *cp; int n_coords = 0; int max_n_coords = strlen(str)/4; Coord *coords = new Coord[max_n_coords]; - while( true ) { - if ( *str == '\0' ) { - break; - } - ws = strchr(str, ' '); - if ( ws ) { - *ws = '\0'; - } - char *cp = strchr(str, ','); + while ( *str != '\0' ) { + cp = strchr(str, ','); if ( !cp ) { Error("Bogus coordinate %s found in polygon string", str); - delete[] coords; - delete[] str_ptr; - return false; - } else { - *cp = '\0'; - char *xp = str; - char *yp = cp+1; + break; + } + int x = atoi(str); + int y = atoi(cp+1); + Debug(3, "Got coordinate %d,%d from polygon string", x, y); + coords[n_coords++] = Coord(x, y); - int x = atoi(xp); - int y = atoi(yp); - - Debug(3, "Got coordinate %d,%d from polygon string", x, y); -#if 0 - if ( x < 0 ) - x = 0; - else if ( x >= width ) - x = width-1; - if ( y < 0 ) - y = 0; - else if ( y >= height ) - y = height-1; -#endif - coords[n_coords++] = Coord( x, y ); - } + ws = strchr(cp+2, ' '); if ( ws ) str = ws+1; else break; - } - polygon = Polygon(n_coords, coords); + } // end while ! end of string - Debug(3, "Successfully parsed polygon string"); - //printf( "Area: %d\n", pg.Area() ); - //printf( "Centre: %d,%d\n", pg.Centre().X(), pg.Centre().Y() ); + if ( n_coords > 2 ) { + Debug(3, "Successfully parsed polygon string %s", str); + polygon = Polygon(n_coords, coords); + } else { + Error("Not enough coordinates to form a polygon!"); + n_coords = 0; + } delete[] coords; - delete[] str_ptr; - - return true; -} + return n_coords ? true : false; +} // end bool Zone::ParsePolygonString(const char *poly_string, Polygon &polygon) bool Zone::ParseZoneString(const char *zone_string, int &zone_id, int &colour, Polygon &polygon) { Debug(3, "Parsing zone string '%s'", zone_string); @@ -825,13 +790,12 @@ bool Zone::ParseZoneString(const char *zone_string, int &zone_id, int &colour, P char *str = str_ptr; strcpy(str, zone_string); + zone_id = strtol(str, 0, 10); + Debug(3, "Got zone %d from zone string", zone_id); + char *ws = strchr(str, ' '); if ( !ws ) { Debug(3, "No initial whitespace found in zone string '%s', finishing", str); - } - zone_id = strtol(str, 0, 10); - Debug(3, "Got zone %d from zone string", zone_id); - if ( !ws ) { delete[] str_ptr; return true; } @@ -839,13 +803,11 @@ bool Zone::ParseZoneString(const char *zone_string, int &zone_id, int &colour, P *ws = '\0'; str = ws+1; + colour = strtol(str, 0, 16); + Debug(3, "Got colour %06x from zone string", colour); ws = strchr(str, ' '); if ( !ws ) { Debug(3, "No secondary whitespace found in zone string '%s', finishing", zone_string); - } - colour = strtol(str, 0, 16); - Debug(3, "Got colour %06x from zone string", colour); - if ( !ws ) { delete[] str_ptr; return true; } @@ -853,27 +815,28 @@ bool Zone::ParseZoneString(const char *zone_string, int &zone_id, int &colour, P str = ws+1; bool result = ParsePolygonString(str, polygon); - - //printf( "Area: %d\n", pg.Area() ); - //printf( "Centre: %d,%d\n", pg.Centre().X(), pg.Centre().Y() ); - delete[] str_ptr; return result; -} +} // end bool Zone::ParseZoneString(const char *zone_string, int &zone_id, int &colour, Polygon &polygon) int Zone::Load(Monitor *monitor, Zone **&zones) { static char sql[ZM_SQL_MED_BUFSIZ]; db_mutex.lock(); - snprintf(sql, sizeof(sql), "select Id,Name,Type+0,Units,Coords,AlarmRGB,CheckMethod+0,MinPixelThreshold,MaxPixelThreshold,MinAlarmPixels,MaxAlarmPixels,FilterX,FilterY,MinFilterPixels,MaxFilterPixels,MinBlobPixels,MaxBlobPixels,MinBlobs,MaxBlobs,OverloadFrames,ExtendAlarmFrames from Zones where MonitorId = %d order by Type, Id", monitor->Id()); + snprintf(sql, sizeof(sql), "SELECT Id,Name,Type+0,Units,Coords,AlarmRGB,CheckMethod+0," + "MinPixelThreshold,MaxPixelThreshold,MinAlarmPixels,MaxAlarmPixels," + "FilterX,FilterY,MinFilterPixels,MaxFilterPixels," + "MinBlobPixels,MaxBlobPixels,MinBlobs,MaxBlobs," + "OverloadFrames,ExtendAlarmFrames" + " FROM Zones WHERE MonitorId = %d ORDER BY Type, Id", monitor->Id()); if ( mysql_query(&dbconn, sql) ) { Error("Can't run query: %s", mysql_error(&dbconn)); db_mutex.unlock(); return 0; } - MYSQL_RES *result = mysql_store_result( &dbconn ); + MYSQL_RES *result = mysql_store_result(&dbconn); if ( !result ) { Error("Can't use query result: %s", mysql_error(&dbconn)); db_mutex.unlock(); @@ -942,7 +905,13 @@ int Zone::Load(Monitor *monitor, Zone **&zones) { } else if ( atoi(dbrow[2]) == Zone::PRIVACY ) { zones[i] = new Zone(monitor, Id, Name, (Zone::ZoneType)Type, polygon); } - zones[i] = new Zone(monitor, Id, Name, (Zone::ZoneType)Type, polygon, AlarmRGB, (Zone::CheckMethod)CheckMethod, MinPixelThreshold, MaxPixelThreshold, MinAlarmPixels, MaxAlarmPixels, Coord( FilterX, FilterY ), MinFilterPixels, MaxFilterPixels, MinBlobPixels, MaxBlobPixels, MinBlobs, MaxBlobs, OverloadFrames, ExtendAlarmFrames); + zones[i] = new Zone( + monitor, Id, Name, (Zone::ZoneType)Type, polygon, AlarmRGB, + (Zone::CheckMethod)CheckMethod, MinPixelThreshold, MaxPixelThreshold, + MinAlarmPixels, MaxAlarmPixels, Coord( FilterX, FilterY ), + MinFilterPixels, MaxFilterPixels, + MinBlobPixels, MaxBlobPixels, MinBlobs, MaxBlobs, + OverloadFrames, ExtendAlarmFrames); } // end foreach row mysql_free_result(result); return n_zones; @@ -951,9 +920,9 @@ int Zone::Load(Monitor *monitor, Zone **&zones) { bool Zone::DumpSettings(char *output, bool /*verbose*/) { output[0] = 0; - sprintf( output+strlen(output), " Id : %d\n", id ); - sprintf( output+strlen(output), " Label : %s\n", label ); - sprintf( output+strlen(output), " Type: %d - %s\n", type, + sprintf(output+strlen(output), " Id : %d\n", id ); + sprintf(output+strlen(output), " Label : %s\n", label ); + sprintf(output+strlen(output), " Type: %d - %s\n", type, type==ACTIVE?"Active":( type==INCLUSIVE?"Inclusive":( type==EXCLUSIVE?"Exclusive":( @@ -1014,10 +983,10 @@ void Zone::std_alarmedpixels(Image* pdiff_image, const Image* ppoly_image, unsig *pdiff = BLACK; } } - } + } // end for y = lo_y to hi_y /* Store the results */ *pixel_count = pixelsalarmed; *pixel_sum = pixelsdifference; Debug(7, "STORED pixelsalarmed(%d), pixelsdifference(%d)", pixelsalarmed, pixelsdifference); -} +} // end void Zone::std_alarmedpixels(Image* pdiff_image, const Image* ppoly_image, unsigned int* pixel_count, unsigned int* pixel_sum) diff --git a/src/zm_zone.h b/src/zm_zone.h index 0c7b26a57..7d7797725 100644 --- a/src/zm_zone.h +++ b/src/zm_zone.h @@ -32,15 +32,14 @@ class Monitor; // This describes a 'zone', or an area of an image that has certain // detection characteristics. // -class Zone -{ +class Zone { protected: - struct Range - { + struct Range { int lo_x; int hi_x; int off_x; }; + typedef struct { unsigned char tag; int count; int lo_x; int hi_x; int lo_y; int hi_y; } BlobStats; public: typedef enum { ACTIVE=1, INCLUSIVE, EXCLUSIVE, PRECLUSIVE, INACTIVE, PRIVACY } ZoneType; @@ -52,8 +51,8 @@ protected: int id; char *label; - ZoneType type; - Polygon polygon; + ZoneType type; + Polygon polygon; Rgb alarm_rgb; CheckMethod check_method; @@ -67,17 +66,18 @@ protected: int min_filter_pixels; int max_filter_pixels; + BlobStats blob_stats[256]; int min_blob_pixels; int max_blob_pixels; int min_blobs; int max_blobs; - int overload_frames; + int overload_frames; int extend_alarm_frames; // Outputs/Statistics - bool alarmed; - bool was_alarmed; + bool alarmed; + bool was_alarmed; int pixel_diff; unsigned int alarm_pixels; int alarm_filter_pixels; @@ -139,8 +139,7 @@ public: inline Coord GetAlarmCentre() const { return( alarm_centre ); } inline unsigned int Score() const { return( score ); } - inline void ResetStats() - { + inline void ResetStats() { alarmed = false; was_alarmed = false; pixel_diff = 0; From d23dc429810950b989a6c1a8557ebbe537225ede Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 21 Jul 2020 18:48:45 -0400 Subject: [PATCH 0152/2339] fix merge from master, make it compile --- src/zm_event.cpp | 2 +- src/zm_monitor.h | 4 ++-- src/zmc.cpp | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index ff07e7cae..5d0de2cb9 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -670,7 +670,7 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a // The idea is to write out 1/sec frame_data.push(new Frame(id, frames, frame_type, timestamp, delta_time, score)); - if ( write_to_db || (frame_data.size() > (int)monitor->get_fps()) ) { + if ( write_to_db || (frame_data.size() > (int)monitor->get_capture_fps()) ) { Debug(1, "Adding %d frames to DB", frame_data.size()); WriteDbFrames(); last_db_frame = frames; diff --git a/src/zm_monitor.h b/src/zm_monitor.h index f169429ba..142105aca 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -556,8 +556,8 @@ public: #if HAVE_LIBAVCODEC //void StreamMpeg( const char *format, int scale=100, int maxfps=10, int bitrate=100000 ); #endif // HAVE_LIBAVCODEC - double get_fps( ) const { - return fps; + double get_capture_fps( ) const { + return capture_fps; } }; diff --git a/src/zmc.cpp b/src/zmc.cpp index 3534f8584..a08aff1f4 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -235,6 +235,8 @@ int main(int argc, char *argv[]) { int result = 0; + int prime_capture_log_count = 0; + while ( !zm_terminate ) { result = 0; static char sql[ZM_SQL_SML_BUFSIZ]; From cf07e0a08986298d32cf1d9b50973b64c150dd66 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 22 Jul 2020 13:41:27 -0400 Subject: [PATCH 0153/2339] fix crashes, current status is: local camera works and can be viewed. Amazing --- src/zm_image.cpp | 18 ++++++++++++------ src/zm_monitor.cpp | 15 +++++++++------ 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/zm_image.cpp b/src/zm_image.cpp index a06213374..3f652d774 100644 --- a/src/zm_image.cpp +++ b/src/zm_image.cpp @@ -192,13 +192,13 @@ Image::Image( int p_width, int p_linesize, int p_height, int p_colours, int p_su } Image::Image(const AVFrame *frame) { - AVFrame *dest_frame = zm_av_frame_alloc(); text[0] = '\0'; width = frame->width; linesize = frame->linesize[0]; height = frame->height; pixels = width*height; + // FIXME colours = ZM_COLOUR_RGB32; subpixelorder = ZM_SUBPIX_ORDER_RGBA; @@ -206,10 +206,10 @@ Image::Image(const AVFrame *frame) { buffer = 0; holdbuffer = 0; AllocImgBuffer(size); - this->Assign( frame ); + this->Assign(frame); } -void Image::Assign( const AVFrame *frame ) { +void Image::Assign(const AVFrame *frame) { /* Assume the dimensions etc are correct. FIXME */ AVPixelFormat format = (AVPixelFormat)AVPixFormat(); @@ -1889,9 +1889,15 @@ void Image::MaskPrivacy( const unsigned char *p_bitmask, const Rgb pixel_colour } /* RGB32 compatible: complete */ -void Image::Annotate( const char *p_text, const Coord &coord, const unsigned int size, const Rgb fg_colour, const Rgb bg_colour ) -{ +void Image::Annotate( + const char *p_text, + const Coord &coord, + const unsigned int size, + const Rgb fg_colour, + const Rgb bg_colour) { + Debug(1, "text %s", p_text); strncpy(text, p_text, sizeof(text)-1); + Debug(1, "text %s", text); unsigned int index = 0; unsigned int line_no = 0; @@ -2046,7 +2052,7 @@ void Image::Annotate( const char *p_text, const Coord &coord, const unsigned int } } else { - Panic("Annotate called with unexpected colours: %d",colours); + Error("Annotate called with unexpected colours: %d", colours); return; } diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 4372d2cae..34f093818 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -900,7 +900,7 @@ bool Monitor::connect() { for ( int i = 0; i < image_buffer_count; i++ ) { image_buffer[i].image_index = i; image_buffer[i].timestamp = &(shared_timestamps[i]); - image_buffer[i].image = new Image( width, camera->LineSize(), height, camera->Colours(), camera->SubpixelOrder(), &(shared_images[i*camera->ImageSize()]) ); + image_buffer[i].image = new Image(width, camera->LineSize(), height, camera->Colours(), camera->SubpixelOrder(), &(shared_images[i*camera->ImageSize()])); image_buffer[i].image->HoldBuffer(true); /* Don't release the internal buffer or replace it with another */ } if ( deinterlacing_value == 4 ) { @@ -2273,17 +2273,20 @@ int Monitor::LoadFfmpegMonitors(const char *file, Monitor **&monitors, Purpose p int Monitor::Capture() { static int FirstCapture = 1; // Used in de-interlacing to indicate whether this is the even or odd image - unsigned int index = 0; - //image_count % image_buffer_count; + // I think was starting to work towards not using the buffer. So only ever use the first image. + // Let's not do this for now. + unsigned int index = image_count % image_buffer_count; - ZMPacket *packet = new ZMPacket(); - packet->timestamp = image_buffer[index].timestamp; - packet->image_index = image_count; + ZMPacket *packet = &image_buffer[index]; + //new ZMPacket(); + //packet->timestamp = image_buffer[index].timestamp; + //packet->image_index = image_count; //&image_buffer[index]; packet->lock(); packet->reset(); Image* capture_image = packet->image; + Debug(1, "capture image: %d x %d linesize: %d", capture_image->Width(), capture_image->Height(), capture_image->LineSize()); int captureResult = 0; if ( deinterlacing_value == 4 ) { From 2773737e54cf270926cf42aac2c9dacea975f1ad Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 19 Aug 2020 16:57:20 -0400 Subject: [PATCH 0154/2339] Use gcc builtin functions for cpuid --- src/zm_utils.cpp | 54 ++++++++++-------------------------------------- 1 file changed, 11 insertions(+), 43 deletions(-) diff --git a/src/zm_utils.cpp b/src/zm_utils.cpp index c96851e79..ecb220021 100644 --- a/src/zm_utils.cpp +++ b/src/zm_utils.cpp @@ -229,63 +229,31 @@ void hwcaps_detect() { neonversion = 0; sse_version = 0; #if (defined(__i386__) || defined(__x86_64__)) - /* x86 or x86-64 processor */ - uint32_t r_edx, r_ecx, r_ebx; + __builtin_cpu_init(); -#ifdef __x86_64__ - __asm__ __volatile__( - "push %%rbx\n\t" - "mov $0x0,%%ecx\n\t" - "mov $0x7,%%eax\n\t" - "cpuid\n\t" - "push %%rbx\n\t" - "mov $0x1,%%eax\n\t" - "cpuid\n\t" - "pop %%rax\n\t" - "pop %%rbx\n\t" - : "=d" (r_edx), "=c" (r_ecx), "=a" (r_ebx) - : - : - ); -#else - __asm__ __volatile__( - "push %%ebx\n\t" - "mov $0x0,%%ecx\n\t" - "mov $0x7,%%eax\n\t" - "cpuid\n\t" - "push %%ebx\n\t" - "mov $0x1,%%eax\n\t" - "cpuid\n\t" - "pop %%eax\n\t" - "pop %%ebx\n\t" - : "=d" (r_edx), "=c" (r_ecx), "=a" (r_ebx) - : - : - ); -#endif - if ( r_ebx & 0x00000020 ) { + if ( __builtin_cpu_supports("avx2") ) { sse_version = 52; /* AVX2 */ Debug(1, "Detected a x86\\x86-64 processor with AVX2"); - } else if ( r_ecx & 0x10000000 ) { + } else if ( __builtin_cpu_supports("avx") ) { sse_version = 51; /* AVX */ Debug(1, "Detected a x86\\x86-64 processor with AVX"); - } else if ( r_ecx & 0x00100000 ) { + } else if ( __builtin_cpu_supports("sse4.2") ) { sse_version = 42; /* SSE4.2 */ Debug(1, "Detected a x86\\x86-64 processor with SSE4.2"); - } else if ( r_ecx & 0x00080000 ) { + } else if ( __builtin_cpu_supports("sse4.1") ) { sse_version = 41; /* SSE4.1 */ Debug(1, "Detected a x86\\x86-64 processor with SSE4.1"); - } else if ( r_ecx & 0x00000200 ) { + } else if ( __builtin_cpu_supports("ssse3") ) { sse_version = 35; /* SSSE3 */ Debug(1,"Detected a x86\\x86-64 processor with SSSE3"); - } else if ( r_ecx & 0x00000001 ) { + } else if ( __builtin_cpu_supports("sse3") ) { sse_version = 30; /* SSE3 */ Debug(1, "Detected a x86\\x86-64 processor with SSE3"); - } else if ( r_edx & 0x04000000 ) { + } else if ( __builtin_cpu_supports("sse2") ) { sse_version = 20; /* SSE2 */ Debug(1, "Detected a x86\\x86-64 processor with SSE2"); - } else if ( r_edx & 0x02000000 ) { + } else if ( __builtin_cpu_supports("sse") ) { sse_version = 10; /* SSE */ Debug(1, "Detected a x86\\x86-64 processor with SSE"); } else { @@ -320,7 +288,7 @@ __attribute__((noinline,__target__("sse2"))) #endif void* sse2_aligned_memcpy(void* dest, const void* src, size_t bytes) { #if ((defined(__i386__) || defined(__x86_64__) || defined(ZM_KEEP_SSE)) && !defined(ZM_STRIP_SSE)) - if ( bytes > 128 ) { + if(bytes > 128) { unsigned int remainder = bytes % 128; const uint8_t* lastsrc = (uint8_t*)src + (bytes - remainder); @@ -362,7 +330,7 @@ void* sse2_aligned_memcpy(void* dest, const void* src, size_t bytes) { } #else /* Non x86\x86-64 platform, use memcpy */ - memcpy(dest, src, bytes); + memcpy(dest,src,bytes); #endif return dest; } From 74d2ba56db5d0b2376700edc923d524e97cd902a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 26 Aug 2020 15:15:10 -0400 Subject: [PATCH 0155/2339] Persist video volume in a cookie so that subsequent events remember the volume level. --- web/skins/classic/views/js/event.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/web/skins/classic/views/js/event.js b/web/skins/classic/views/js/event.js index 93da7e9f2..683f144f6 100644 --- a/web/skins/classic/views/js/event.js +++ b/web/skins/classic/views/js/event.js @@ -1077,6 +1077,12 @@ function initPage() { vid.on('click', function(event) { handleClick(event); }); + vid.on('volumechange', function() { + Cookie.write('volume', vid.volume(), {duration: 10*365}); + }); + if ( Cookie.read('volume') != null ) { + vid.volume(Cookie.read('volume')); + } vid.on('timeupdate', function() { $j('#progressValue').html(secsToTime(Math.floor(vid.currentTime()))); }); From 3b1be3346b2cda92454c3bc4cbd87e6161cebd8e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 7 Sep 2020 10:21:06 -0400 Subject: [PATCH 0156/2339] escape table name when updating Objects --- web/includes/Object.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/includes/Object.php b/web/includes/Object.php index 09be86a9e..2af989e8a 100644 --- a/web/includes/Object.php +++ b/web/includes/Object.php @@ -306,7 +306,7 @@ class ZM_Object { $fields = array_keys($fields); if ( $this->Id() ) { - $sql = 'UPDATE '.$table.' SET '.implode(', ', array_map(function($field) {return '`'.$field.'`=?';}, $fields)).' WHERE Id=?'; + $sql = 'UPDATE `'.$table.'` SET '.implode(', ', array_map(function($field) {return '`'.$field.'`=?';}, $fields)).' WHERE Id=?'; $values = array_map(function($field){ return $this->{$field};}, $fields); $values[] = $this->{'Id'}; if ( dbQuery($sql, $values) ) @@ -314,8 +314,8 @@ class ZM_Object { } else { unset($fields['Id']); - $sql = 'INSERT INTO '.$table. - ' ('.implode(', ', array_map(function($field) {return '`'.$field.'`';}, $fields)). + $sql = 'INSERT INTO `'.$table. + '` ('.implode(', ', array_map(function($field) {return '`'.$field.'`';}, $fields)). ') VALUES ('. implode(', ', array_map(function($field){return '?';}, $fields)).')'; From 2cd9c8e2327ba58563dae6b5a1b04a57384458f5 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 10 Sep 2020 13:31:39 -0400 Subject: [PATCH 0157/2339] Update api Zone Saving. Fixes #3037 --- web/api/app/Controller/ZonesController.php | 14 ++++++++------ web/api/app/Model/Zone.php | 4 ---- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/web/api/app/Controller/ZonesController.php b/web/api/app/Controller/ZonesController.php index f01931f65..8d5e661bb 100644 --- a/web/api/app/Controller/ZonesController.php +++ b/web/api/app/Controller/ZonesController.php @@ -115,6 +115,7 @@ class ZonesController extends AppController { if ( !$this->Zone->exists($id) ) { throw new NotFoundException(__('Invalid zone')); } + $message = ''; if ( $this->request->is(array('post', 'put')) ) { global $user; $canEdit = (!$user) || $user['Monitors'] == 'Edit'; @@ -123,14 +124,15 @@ class ZonesController extends AppController { return; } if ( $this->Zone->save($this->request->data) ) { - return $this->flash(__('The zone has been saved.'), array('action' => 'index')); + $message = 'The zone has been saved.'; + } else { + $message = 'Error ' . print_r($this->Zone->invalidFields()); } - } else { - $options = array('conditions' => array('Zone.' . $this->Zone->primaryKey => $id)); - $this->request->data = $this->Zone->find('first', $options); } - $monitors = $this->Zone->Monitor->find('list'); - $this->set(compact('monitors')); + $this->set(array( + 'message' => $message, + '_serialize' => array('message') + )); } /** diff --git a/web/api/app/Model/Zone.php b/web/api/app/Model/Zone.php index 0f5e4d653..cdf8464e2 100644 --- a/web/api/app/Model/Zone.php +++ b/web/api/app/Model/Zone.php @@ -41,19 +41,15 @@ class Zone extends AppModel { //array('naturalNumber'), 'message' => 'Zones must have a valid MonitorId', 'allowEmpty' => false, - 'required' => true, //'last' => false, // Stop validation after this rule //'on' => 'create', // Limit validation to 'create' or 'update' operations ), 'Name' => array( 'required' => array( - //'on' => 'create', 'rule' => 'notBlank', 'message' => 'Zone Name must be specified for creation', - 'required' => true, ), ) - ); //The Associations below have been created with all possible keys, those that are not needed can be removed From 8ad62b89050e7f4c0e97b931b1fe2bc60bd573e8 Mon Sep 17 00:00:00 2001 From: Pliable Pixels Date: Sun, 13 Sep 2020 16:43:49 -0400 Subject: [PATCH 0158/2339] another try at fixing Eventcontroller --- web/api/app/Controller/EventsController.php | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/web/api/app/Controller/EventsController.php b/web/api/app/Controller/EventsController.php index 5188c18b4..3b132e932 100644 --- a/web/api/app/Controller/EventsController.php +++ b/web/api/app/Controller/EventsController.php @@ -434,14 +434,11 @@ class EventsController extends AppController { // Find the max Frame for this Event. Error out otherwise. $this->loadModel('Frame'); - if (! $frame = $this->Frame->find('first', array( + $frame = $this->Frame->find('first', array( 'conditions' => array( - 'EventId' => $event['Event']['Id'], - 'Score' => $event['Event']['MaxScore'] - ) - ))) { - throw new NotFoundException(__('Can not find Frame for Event ' . $event['Event']['Id'])); - } - return $frame['Frame']['Id']; + 'EventId' => $event['Event']['Id'], + 'Score' => $event['Event']['MaxScore'] + ))); + return empty($frame)?null:$frame['Frame']['Id']; } } // end class EventsController From df18359f612bd9d631381e056e14f7dea046599f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 15 Sep 2020 11:12:20 -0400 Subject: [PATCH 0159/2339] query_string to querystring --- web/skins/classic/views/events.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/events.php b/web/skins/classic/views/events.php index a1c78b31b..7542061a5 100644 --- a/web/skins/classic/views/events.php +++ b/web/skins/classic/views/events.php @@ -97,7 +97,7 @@ if ( !empty($page) ) { } $maxShortcuts = 5; -$pagination = getPagination($pages, $page, $maxShortcuts, $filter->query_string().$sortQuery.$limitQuery); +$pagination = getPagination($pages, $page, $maxShortcuts, $filter->querystring().$sortQuery.$limitQuery); $focusWindow = true; From 9268db14a79c4ccd444c2bf8d24e62b13207b413 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 16 Sep 2020 14:14:31 -0400 Subject: [PATCH 0160/2339] Fix xss reported by Noccolo Picca relating to not sanitizing connkey --- web/skins/classic/views/download.php | 4 ++-- web/skins/classic/views/export.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/web/skins/classic/views/download.php b/web/skins/classic/views/download.php index 88bb0958b..3e504e5f4 100644 --- a/web/skins/classic/views/download.php +++ b/web/skins/classic/views/download.php @@ -62,7 +62,7 @@ if ( !empty($_REQUEST['eid']) ) { } $focusWindow = true; -$connkey = isset($_REQUEST['connkey']) ? $_REQUEST['connkey'] : generateConnKey(); +$connkey = isset($_REQUEST['connkey']) ? validInt($_REQUEST['connkey']) : generateConnKey(); xhtmlHeaders(__FILE__, translate('Download')); ?> @@ -75,7 +75,7 @@ xhtmlHeaders(__FILE__, translate('Download'));

-
+ From 6b2773ad8c0036ca74f8d284c3e38fdf3446f1aa Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 16 Sep 2020 14:21:03 -0400 Subject: [PATCH 0161/2339] Handle invalid eid more gracefully. --- web/skins/classic/views/download.php | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/web/skins/classic/views/download.php b/web/skins/classic/views/download.php index 3e504e5f4..a4e2aa757 100644 --- a/web/skins/classic/views/download.php +++ b/web/skins/classic/views/download.php @@ -54,13 +54,6 @@ if ( isset($_REQUEST['exportFormat']) ) { } } -if ( !empty($_REQUEST['eid']) ) { - $Event = new ZM\Event($_REQUEST['eid']); - if ( !$Event->Id ) { - Error('Invalid event id'); - } -} - $focusWindow = true; $connkey = isset($_REQUEST['connkey']) ? validInt($_REQUEST['connkey']) : generateConnKey(); @@ -83,7 +76,12 @@ if ( !empty($_REQUEST['eid']) ) { Id . '. Resulting file should be approximately ' . human_filesize( $Event->DiskSpace() ); + if ( !$Event->Id() ) { + ZM\Error('Invalid event id'); + echo '
Invalid event id
'; + } else { + echo 'Downloading event ' . $Event->Id . '. Resulting file should be approximately ' . human_filesize( $Event->DiskSpace() ); + } } else if ( !empty($_REQUEST['eids']) ) { $total_size = 0; foreach ( $_REQUEST['eids'] as $eid ) { From 89913adfa3d10cd67d4afb1bbf42197916fdf3c8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 16 Sep 2020 14:23:23 -0400 Subject: [PATCH 0162/2339] Bump version to 1.34.21 for release --- distros/redhat/zoneminder.spec | 2 +- version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index 637630324..d602ec855 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -28,7 +28,7 @@ %global _hardened_build 1 Name: zoneminder -Version: 1.34.20 +Version: 1.34.21 Release: 1%{?dist} Summary: A camera monitoring and analysis tool Group: System Environment/Daemons diff --git a/version b/version index f883b434e..63a880485 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.34.20 +1.34.21 From d2963fe28fb375ba604c54dc4962443c61bcca92 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 19 Sep 2020 08:55:08 -0500 Subject: [PATCH 0163/2339] convert donate modal to ajax request --- .../classic/views => ajax/modals}/donate.php | 37 +++++++++---------- web/includes/actions/donate.php | 2 +- web/skins/classic/views/console.php | 2 - web/skins/classic/views/js/console.js | 19 +++++++++- web/skins/classic/views/js/donate.js | 3 -- web/skins/classic/views/js/donate.js.php | 2 - 6 files changed, 36 insertions(+), 29 deletions(-) rename web/{skins/classic/views => ajax/modals}/donate.php (70%) delete mode 100644 web/skins/classic/views/js/donate.js delete mode 100644 web/skins/classic/views/js/donate.js.php diff --git a/web/skins/classic/views/donate.php b/web/ajax/modals/donate.php similarity index 70% rename from web/skins/classic/views/donate.php rename to web/ajax/modals/donate.php index 502377133..374d4e0d2 100644 --- a/web/skins/classic/views/donate.php +++ b/web/ajax/modals/donate.php @@ -18,10 +18,7 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // -if ( !canEdit('System') ) { - $view = 'error'; - return; -} +if ( !canEdit('System') ) return; $options = array( 'go' => translate('DonateYes'), @@ -45,25 +42,25 @@ $options = array(
+ diff --git a/web/includes/actions/donate.php b/web/includes/actions/donate.php index b8659b269..c85f4509e 100644 --- a/web/includes/actions/donate.php +++ b/web/includes/actions/donate.php @@ -49,6 +49,6 @@ if ( $action == 'donate' && isset($_REQUEST['option']) ) { Warning("Unknown value for option in donate: $option"); break; } // end switch option - $view = 'none'; + $redirect = '?view=console'; } ?> diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index 43523568c..e99f75321 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -438,7 +438,5 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { diff --git a/web/skins/classic/views/js/console.js b/web/skins/classic/views/js/console.js index 522a6910e..6e4b38242 100644 --- a/web/skins/classic/views/js/console.js +++ b/web/skins/classic/views/js/console.js @@ -133,7 +133,24 @@ function initPage() { window.location.assign('?view=version'); } if ( showDonatePopup ) { - $j('#donate').modal('show'); + $j.getJSON(thisUrl + '?request=modal&modal=donate') + .done(function(data) { + if ( $j('#donate').length ) { + $j('#donate').replaceWith(data.html); + } else { + $j("body").append(data.html); + } + $j('#donate').modal('show'); + // Manage the Apply button + $j('#donateApplyBtn').click(function(evt) { + evt.preventDefault(); + $j('#donateForm').submit(); + }); + }) + .fail(function(jqxhr, textStatus, error) { + console.log("Request Failed: " + textStatus + ", " + error); + console.log("Response Text: " + jqxhr.responseText); + }); } // Makes table sortable diff --git a/web/skins/classic/views/js/donate.js b/web/skins/classic/views/js/donate.js deleted file mode 100644 index eb3c25f50..000000000 --- a/web/skins/classic/views/js/donate.js +++ /dev/null @@ -1,3 +0,0 @@ -if ( action == 'donate' && option == 'go' ) { - zmWindow('/donate/'); -} diff --git a/web/skins/classic/views/js/donate.js.php b/web/skins/classic/views/js/donate.js.php deleted file mode 100644 index 4fc36d5bb..000000000 --- a/web/skins/classic/views/js/donate.js.php +++ /dev/null @@ -1,2 +0,0 @@ -var action = ''; -var option = ''; From f7cbc2f5e092cc509c78184f26c504100a2593ba Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 19 Sep 2020 09:10:16 -0500 Subject: [PATCH 0164/2339] remove uneeded setconfig options in redhat specfil --- distros/redhat/zoneminder.spec | 2 -- 1 file changed, 2 deletions(-) diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index 9e876324e..8a03de245 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -206,8 +206,6 @@ mv -f CakePHP-Enum-Behavior-%{ceb_version} ./web/api/app/Plugin/CakePHP-Enum-Beh ./utils/zmeditconfigdata.sh ZM_OPT_CAMBOZOLA yes ./utils/zmeditconfigdata.sh ZM_OPT_CONTROL yes ./utils/zmeditconfigdata.sh ZM_CHECK_FOR_UPDATES no -./utils/zmeditconfigdata.sh ZM_DYN_SHOW_DONATE_REMINDER no -./utils/zmeditconfigdata.sh ZM_OPT_FAST_DELETE no %build # Disable LTO due to top level asm From ec20fdf3ad3bff382c0c03d00f2cda7fff8f9427 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 19 Sep 2020 10:18:59 -0500 Subject: [PATCH 0165/2339] convert function modal to ajax request --- .../views => ajax/modals}/function.php | 17 +-- web/includes/actions/function.php | 4 +- web/skins/classic/views/console.php | 1 - web/skins/classic/views/js/console.js | 111 +++++++++++------- 4 files changed, 76 insertions(+), 57 deletions(-) rename web/{skins/classic/views => ajax/modals}/function.php (85%) diff --git a/web/skins/classic/views/function.php b/web/ajax/modals/function.php similarity index 85% rename from web/skins/classic/views/function.php rename to web/ajax/modals/function.php index 83d67d54a..e6bab2718 100644 --- a/web/skins/classic/views/function.php +++ b/web/ajax/modals/function.php @@ -18,17 +18,18 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // -if ( !canEdit('Monitors') ) { - $view = 'error'; - return; -} -?> +if ( !canEdit('Monitors') ) return; +?> diff --git a/web/includes/actions/function.php b/web/includes/actions/function.php index adf85de38..9667b8c24 100644 --- a/web/includes/actions/function.php +++ b/web/includes/actions/function.php @@ -51,11 +51,9 @@ if ( $action == 'function' ) { if ( $newFunction != 'None' && $newFunction != 'NoDect' ) zmaControl($monitor, 'start'); } - $refreshParent = true; } else { ZM\Logger::Debug('No change to function, not doing anything.'); } } // end if action -$view = 'none'; -$closePopup = true; +$view = 'console'; ?> diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index e99f75321..97da24f0f 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -437,6 +437,5 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { diff --git a/web/skins/classic/views/js/console.js b/web/skins/classic/views/js/console.js index 6e4b38242..368093591 100644 --- a/web/skins/classic/views/js/console.js +++ b/web/skins/classic/views/js/console.js @@ -127,6 +127,57 @@ function reloadWindow() { window.location.replace( thisUrl ); } +// Manage the the Function modal and its buttons +function manageFunctionModal() { + $j('.functionLnk').click(function(evt) { + evt.preventDefault(); + if ( !canEditEvents ) { + enoperm(); + return; + } + var mid = evt.currentTarget.getAttribute('data-mid'); + monitor = monitors[mid]; + if ( !monitor ) { + console.error("No monitor found for mid " + mid); + return; + } + + var function_form = document.getElementById('function_form'); + if ( !function_form ) { + console.error("Unable to find form with id function_form"); + return; + } + function_form.elements['newFunction'].value = monitor.Function; + function_form.elements['newEnabled'].checked = monitor.Enabled == '1'; + function_form.elements['mid'].value = mid; + document.getElementById('function_monitor_name').innerHTML = monitor.Name; + + $j('#modalFunction').modal('show'); + }); + + // Manage the CANCEL modal buttons + $j('.funcCancelBtn').click(function(evt) { + evt.preventDefault(); + $j('#modalFunction').modal('hide'); + }); + + // Manage the SAVE modal buttons + $j('.funcSaveBtn').click(function(evt) { + evt.preventDefault(); + $j('#function_form').submit(); + //var form = evt.currentTarget.form; + //var mid = form.elements['mid'].value; + //var newFunc = $j('#newFunction').val(); + //var newEnabled = $j('#newEnabled').is(':checked') ? 1 : 0; + //$j.getJSON(thisUrl + '?view=function&action=function&mid='+mid+'&newFunction='+newFunc+'&newEnabled='+newEnabled) + //.done(window.location.reload(true)) + //.fail(function(jqxhr, textStatus, error) { + //console.log("Request Failed: " + textStatus + ", " + error); + //console.log("Response Text: " + jqxhr.responseText); + //}); + }); +} + function initPage() { reloadWindow.periodical(consoleRefreshTimeout); if ( showVersionPopup ) { @@ -165,51 +216,21 @@ function initPage() { // Setup the thumbnail video animation initThumbAnimation(); - $j('.functionLnk').click(function(evt) { - evt.preventDefault(); - if ( !canEditEvents ) { - enoperm(); - return; - } - var mid = evt.currentTarget.getAttribute('data-mid'); - monitor = monitors[mid]; - if ( !monitor ) { - console.error("No monitor found for mid " + mid); - return; - } - - var function_form = document.getElementById('function_form'); - if ( !function_form ) { - console.error("Unable to find form with id function_form"); - return; - } - function_form.elements['newFunction'].value = monitor.Function; - function_form.elements['newEnabled'].checked = monitor.Enabled == '1'; - function_form.elements['mid'].value = mid; - document.getElementById('function_monitor_name').innerHTML = monitor.Name; - - $j('#modalFunction').modal('show'); - }); - // Manage the CANCEL modal buttons - $j('.funcCancelBtn').click(function(evt) { - evt.preventDefault(); - $j('#modalFunction').modal('hide'); - }); - - // Manage the SAVE modal buttons - $j('.funcSaveBtn').click(function(evt) { - evt.preventDefault(); - var form = evt.currentTarget.form; - var mid = form.elements['mid'].value; - var newFunc = $j('#newFunction').val(); - var newEnabled = $j('#newEnabled').is(':checked') ? 1 : 0; - $j.getJSON(thisUrl + '?view=function&action=function&mid='+mid+'&newFunction='+newFunc+'&newEnabled='+newEnabled) - .done(window.location.reload(true)) - .fail(function(jqxhr, textStatus, error) { - console.log("Request Failed: " + textStatus + ", " + error); - console.log("Response Text: " + jqxhr.responseText); - }); - }); + // Load the Function modal on page load + $j.getJSON(thisUrl + '?request=modal&modal=function') + .done(function(data) { + if ( $j('#modalFunction').length ) { + $j('#modalFunction').replaceWith(data.html); + } else { + $j("body").append(data.html); + } + // Manage the Function modal + manageFunctionModal(); + }) + .fail(function(jqxhr, textStatus, error) { + console.log("Request Failed: " + textStatus + ", " + error); + console.log("Response Text: " + jqxhr.responseText); + }); } function applySort(event, ui) { From 03a0e849b806df269afffdb410c6ac057c00d8f1 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 19 Sep 2020 10:24:28 -0500 Subject: [PATCH 0166/2339] remove unneeded js from console.js --- web/skins/classic/views/js/console.js | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/web/skins/classic/views/js/console.js b/web/skins/classic/views/js/console.js index 368093591..9085e11cc 100644 --- a/web/skins/classic/views/js/console.js +++ b/web/skins/classic/views/js/console.js @@ -165,16 +165,6 @@ function manageFunctionModal() { $j('.funcSaveBtn').click(function(evt) { evt.preventDefault(); $j('#function_form').submit(); - //var form = evt.currentTarget.form; - //var mid = form.elements['mid'].value; - //var newFunc = $j('#newFunction').val(); - //var newEnabled = $j('#newEnabled').is(':checked') ? 1 : 0; - //$j.getJSON(thisUrl + '?view=function&action=function&mid='+mid+'&newFunction='+newFunc+'&newEnabled='+newEnabled) - //.done(window.location.reload(true)) - //.fail(function(jqxhr, textStatus, error) { - //console.log("Request Failed: " + textStatus + ", " + error); - //console.log("Response Text: " + jqxhr.responseText); - //}); }); } From 7c1ec4f95709820edf715eaa559e9e39115ca1c0 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 19 Sep 2020 10:44:05 -0500 Subject: [PATCH 0167/2339] convert logout modal to ajax request --- .../classic/views => ajax/modals}/logout.php | 4 ++++ web/skins/classic/includes/functions.php | 2 -- web/skins/classic/js/skin.js | 18 ++++++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) rename web/{skins/classic/views => ajax/modals}/logout.php (91%) diff --git a/web/skins/classic/views/logout.php b/web/ajax/modals/logout.php similarity index 91% rename from web/skins/classic/views/logout.php rename to web/ajax/modals/logout.php index 86e07605a..565e80cc2 100644 --- a/web/skins/classic/views/logout.php +++ b/web/ajax/modals/logout.php @@ -33,6 +33,10 @@ global $CLANG; '; + } + $html[] = ''; // So we ge a trailing \n + return implode(PHP_EOL, $html); + } function output_cache_busted_stylesheet_links($files) { $html = array(); foreach ( $files as $file ) { $html[] = ''; } + if ( ! count($html) ) { + ZM\Warning("No files found for $files"); + } $html[] = ''; // So we ge a trailing \n return implode(PHP_EOL, $html); } @@ -109,6 +121,8 @@ if ( $css != 'base' ) echo output_link_if_exists(array('/css/base/views/control.css')); if ( $css != 'base' ) echo output_link_if_exists(array('/css/'.$css.'/views/control.css')); + } else if ( $basename == 'monitor' ) { + echo output_link_if_exists(array('/js/leaflet/leaflet.css')); } ?> - - -

'.translate('ZoneMinderLog').'

-

'.htmlspecialchars(preg_match('/%/', DATE_FMT_CONSOLE_LONG) ? strftime(DATE_FMT_CONSOLE_LONG) : date(DATE_FMT_CONSOLE_LONG)).'

-

'.count($logs).' '.translate('Logs').'

- - - - '); - foreach ( $logs as $log ) { - $classLevel = $log['Level']; - if ( $classLevel < ZM\Logger::FATAL ) { - $classLevel = ZM\Logger::FATAL; - } else if ( $classLevel > ZM\Logger::DEBUG ) { - $classLevel = ZM\Logger::DEBUG; - } - $logClass = 'log-'.strtolower(ZM\Logger::$codes[$classLevel]); - fprintf($exportFP, ' - ', $logClass, $log['DateTime'], $log['Component'], $log['Server'], $log['Pid'], $log['Code'], $log['Message'], $log['File'], $log['Line']); - } - fwrite($exportFP, - ' -
'.translate('DateTime').''.translate('Component').''.translate('Server').''.translate('Pid').''.translate('Level').''.translate('Message').''.translate('File').''.translate('Line').'
%s%s%s%d%s%s%s%s
- - '); - break; - } - case 'xml' : - { - fwrite($exportFP, - ' - - '.$_POST['selector'].''); - foreach ( $filter as $field=>$value ) - if ( $value != '' ) - fwrite( $exportFP, - ' - <'.strtolower($field).'>'.htmlspecialchars($value).' - ' ); - fwrite( $exportFP, - ' - - '.translate('DateTime').' - '.translate('Component').' - '.translate('Server').' - '.translate('Pid').' - '.translate('Level').' - '.translate('Message').' - '.translate('File').' - '.translate('Line').' - - - ' ); - foreach ( $logs as $log ) { - fprintf( $exportFP, - ' - %s - %s - %s - %d - %s - - %s - %d - -', $log['DateTime'], $log['Component'], $log['Server'], $log['Pid'], $log['Code'], utf8_decode( $log['Message'] ), $log['File'], $log['Line'] ); - } - fwrite( $exportFP, - ' - ' ); - break; - } - $exportExt = 'xml'; - break; - } - fclose( $exportFP ); - ajaxResponse( array( - 'key' => $exportKey, - 'format' => $format, - ) ); - break; - } - case 'download' : - { - if ( !canView('System') ) - ajaxError('Insufficient permissions to download logs'); - - if ( empty($_REQUEST['key']) ) - ZM\Fatal('No log export key given'); - $exportKey = $_REQUEST['key']; - if ( empty($_REQUEST['format']) ) - ZM\Fatal('No log export format given'); - $format = $_REQUEST['format']; - - switch ( $format ) { - case 'text' : - $exportExt = 'txt'; - break; - case 'tsv' : - $exportExt = 'tsv'; - break; - case 'html' : - $exportExt = 'html'; - break; - case 'xml' : - $exportExt = 'xml'; - break; - default : - ZM\Fatal("Unrecognised log export format '$format'"); - } - - $exportFile = 'zm-log.'.$exportExt; - $exportPath = ZM_DIR_EXPORTS.'/zm-log-'.$exportKey.$exportExt; - - header('Pragma: public'); - header('Expires: 0'); - header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); - header('Cache-Control: private', false); // required by certain browsers - header('Content-Description: File Transfer'); - header('Content-Disposition: attachment; filename="'.$exportFile.'"'); - header('Content-Transfer-Encoding: binary'); - header('Content-Type: application/force-download'); - header('Content-Length: '.filesize($exportPath)); - readfile($exportPath); - exit(0); - break; - } -} // end switch ( $_REQUEST['task'] ) -ajaxError('Unrecognised action or insufficient permissions'); -?> diff --git a/web/ajax/newlog.php b/web/ajax/newlog.php deleted file mode 100644 index 9e6bd9585..000000000 --- a/web/ajax/newlog.php +++ /dev/null @@ -1,132 +0,0 @@ - "search text" pairs -// Bootstrap table sends json_ecoded array, which we must decode -$advsearch = isset($_REQUEST['filter']) ? json_decode($_REQUEST['filter'], JSON_OBJECT_AS_ARRAY) : array(); - -// Sort specifies the name of the column to sort on -$sort = 'TimeKey'; -if ( isset($_REQUEST['sort']) ) { - if ( !in_array($_REQUEST['sort'], array_merge($columns, $col_alt)) ) { - ZM\Error('Invalid sort field: ' . $_REQUEST['sort']); - } else { - $sort = $_REQUEST['sort']; - if ( $sort == 'DateTime' ) $sort = 'TimeKey'; - } -} - -// Offset specifies the starting row to return, used for pagination -$offset = 0; -if ( isset($_REQUEST['offset']) ) { - if ( ( !is_int($_REQUEST['offset']) and !ctype_digit($_REQUEST['offset']) ) ) { - ZM\Error('Invalid value for offset: ' . $_REQUEST['offset']); - } else { - $offset = $_REQUEST['offset']; - } -} - -// Order specifies the sort direction, either asc or desc -$order = (isset($_REQUEST['order']) and (strtolower($_REQUEST['order']) == 'asc')) ? 'ASC' : 'DESC'; - -// Limit specifies the number of rows to return -$limit = 100; -if ( isset($_REQUEST['limit']) ) { - if ( ( !is_int($_REQUEST['limit']) and !ctype_digit($_REQUEST['limit']) ) ) { - ZM\Error('Invalid value for limit: ' . $_REQUEST['limit']); - } else { - $limit = $_REQUEST['limit']; - } -} - -$col_str = implode(', ', $columns); -$data = array(); -$query = array(); -$query['values'] = array(); -$likes = array(); -$where = ''; -// There are two search bars in the log view, normal and advanced -// Making an exuctive decision to ignore the normal search, when advanced search is in use -// Alternatively we could try to do both -if ( count($advsearch) ) { - - foreach ( $advsearch as $col=>$text ) { - if ( !in_array($col, array_merge($columns, $col_alt)) ) { - ZM\Error("'$col' is not a sortable column name"); - continue; - } - $text = '%' .$text. '%'; - array_push($likes, $col.' LIKE ?'); - array_push($query['values'], $text); - } - $wherevalues = $query['values']; - $where = ' WHERE (' .implode(' OR ', $likes). ')'; - -} else if ( $search != '' ) { - - $search = '%' .$search. '%'; - foreach ( $columns as $col ) { - array_push($likes, $col.' LIKE ?'); - array_push($query['values'], $search); - } - $wherevalues = $query['values']; - $where = ' WHERE (' .implode(' OR ', $likes). ')'; -} - -$query['sql'] = 'SELECT ' .$col_str. ' FROM `' .$table. '` ' .$where. ' ORDER BY ' .$sort. ' ' .$order. ' LIMIT ?, ?'; -array_push($query['values'], $offset, $limit); - -//ZM\Warning('Calling the following sql query: ' .$query['sql']); - -$data['totalNotFiltered'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table, 'Total'); -if ( $search != '' || count($advsearch) ) { - $data['total'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table.$where , 'Total', $wherevalues); -} else { - $data['total'] = $data['totalNotFiltered']; -} - -if ( !$Servers ) - $Servers = ZM\Server::find(); -$servers_by_Id = array(); -# There is probably a better way to do this. -foreach ( $Servers as $server ) { - $servers_by_Id[$server->Id()] = $server; -} - -$rows = array(); -foreach ( dbFetchAll($query['sql'], NULL, $query['values']) as $row ) { - $row['DateTime'] = strftime('%Y-%m-%d %H:%M:%S', intval($row['TimeKey'])); - $row['Server'] = ( $row['ServerId'] and isset($servers_by_Id[$row['ServerId']]) ) ? $servers_by_Id[$row['ServerId']]->Name() : ''; - // First strip out any html tags - // Second strip out all characters that are not ASCII 32-126 (yes, 126) - $row['Message'] = preg_replace('/[^\x20-\x7E]/', '', strip_tags($row['Message'])); - $rows[] = $row; -} -$data['rows'] = $rows; -$data['logstate'] = logState(); -$data['updated'] = preg_match('/%/', DATE_FMT_CONSOLE_LONG) ? strftime(DATE_FMT_CONSOLE_LONG) : date(DATE_FMT_CONSOLE_LONG); - -ajaxResponse($data); - diff --git a/web/skins/classic/views/js/log.js b/web/skins/classic/views/js/log.js index ddaabcfc8..cd645e244 100644 --- a/web/skins/classic/views/js/log.js +++ b/web/skins/classic/views/js/log.js @@ -27,7 +27,7 @@ var params = // Called by bootstrap-table to retrieve zm log data function ajaxRequest(params) { - $j.getJSON(thisUrl + '?view=request&request=newlog&task=query', params.data) + $j.getJSON(thisUrl + '?view=request&request=log&task=query', params.data) .done(function(data) { //console.log('Ajax parameters: ' + JSON.stringify(params)); // rearrange the result into what bootstrap-table expects From 6f45de04f82fd37c1cd88a39916da4c2e8cfda91 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Mon, 19 Oct 2020 07:50:11 -0500 Subject: [PATCH 0449/2339] partial roughin ajax event view server side pagination --- web/ajax/events.php | 219 +++++++++++++++++++++++---- web/skins/classic/views/js/events.js | 26 ++-- 2 files changed, 202 insertions(+), 43 deletions(-) diff --git a/web/ajax/events.php b/web/ajax/events.php index 16c777ebf..c54fddd06 100644 --- a/web/ajax/events.php +++ b/web/ajax/events.php @@ -1,41 +1,200 @@ "search text" pairs +// Bootstrap table sends json_ecoded array, which we must decode +$advsearch = isset($_REQUEST['filter']) ? json_decode($_REQUEST['filter'], JSON_OBJECT_AS_ARRAY) : array(); + +// Sort specifies the name of the column to sort on +$sort = 'AttrStartTime'; +if ( isset($_REQUEST['sort']) ) { + if ( !in_array($_REQUEST['sort'], array_merge($columns, $col_alt)) ) { + ZM\Error('Invalid sort field: ' . $_REQUEST['sort']); + } else { + $sort = $_REQUEST['sort']; + //if ( $sort == 'DateTime' ) $sort = 'TimeKey'; + } +} + +// Offset specifies the starting row to return, used for pagination +$offset = 0; +if ( isset($_REQUEST['offset']) ) { + if ( ( !is_int($_REQUEST['offset']) and !ctype_digit($_REQUEST['offset']) ) ) { + ZM\Error('Invalid value for offset: ' . $_REQUEST['offset']); + } else { + $offset = $_REQUEST['offset']; + } +} + +// Order specifies the sort direction, either asc or desc +$order = (isset($_REQUEST['order']) and (strtolower($_REQUEST['order']) == 'asc')) ? 'ASC' : 'DESC'; + +// Limit specifies the number of rows to return +$limit = 100; +if ( isset($_REQUEST['limit']) ) { + if ( ( !is_int($_REQUEST['limit']) and !ctype_digit($_REQUEST['limit']) ) ) { + ZM\Error('Invalid value for limit: ' . $_REQUEST['limit']); + } else { + $limit = $_REQUEST['limit']; + } +} + +// +// MAIN LOOP +// + +switch ( $task ) { + case 'archive' : + case 'unarchive' : + foreach ( $eids as $eid ) archiveRequest($task, $eid); + break; + case 'delete' : + foreach ( $eids as $eid ) $data[] = deleteRequest($eid); + break; + case 'query' : + $data = queryRequest($search, $advsearch, $sort, $offset, $order, $limit); + break; + default : + ZM\Fatal("Unrecognised task '$task'"); +} // end switch task + +ajaxResponse($data); + +// +// FUNCTION DEFINITIONS +// + +function archiveRequest($task, $eid) { + $archiveVal = ($task == 'archive') ? 1 : 0; + dbQuery( + 'UPDATE Events SET Archived = ? WHERE Id = ?', + array($archiveVal, $eid) + ); +} + +function deleteRequest($eid) { $message = array(); + $event = new ZM\Event($eid); + if ( !$event->Id() ) { + $message[] = array($eid=>'Event not found.'); + } else if ( $event->Archived() ) { + $message[] = array($eid=>'Event is archived, cannot delete it.'); + } else { + $event->delete(); + } + + return $message; +} - foreach ( $_REQUEST['eids'] as $eid ) { +function queryRequest($search, $advsearch, $sort, $offset, $order, $limit) { + // Put server pagination code here + // The table we want our data from + $table = 'Events'; - switch ( $_REQUEST['action'] ) { - case 'archive' : - case 'unarchive' : - $archiveVal = ($_REQUEST['action'] == 'archive') ? 1 : 0; - dbQuery( - 'UPDATE Events SET Archived = ? WHERE Id = ?', - array($archiveVal, $eid) - ); - break; - case 'delete' : - $event = new ZM\Event($eid); - if ( !$event->Id() ) { - $message[] = array($eid=>'Event not found.'); - } else if ( $event->Archived() ) { - $message[] = array($eid=>'Event is archived, cannot delete it.'); - } else { - $event->delete(); + // The names of the dB columns in the log table we are interested in + $columns = array('Id', 'MonitorId', 'StorageId', 'Name', 'Cause', 'StartTime', 'EndTime', 'Frames', 'AlarmFrames', 'TotScore', 'AvgScore', 'MaxScore', 'Archived', 'Emailed', 'DiskSpace'); + + // The names of columns shown in the log view that are NOT dB columns in the database + $col_alt = array('Monitor', 'Storage'); + + $col_str = implode(', ', $columns); + $data = array(); + $query = array(); + $query['values'] = array(); + $likes = array(); + $where = ''; + // There are two search bars in the log view, normal and advanced + // Making an exuctive decision to ignore the normal search, when advanced search is in use + // Alternatively we could try to do both + if ( count($advsearch) ) { + + foreach ( $advsearch as $col=>$text ) { + if ( !in_array($col, array_merge($columns, $col_alt)) ) { + ZM\Error("'$col' is not a sortable column name"); + continue; } - break; - } // end switch action - } // end foreach - ajaxResponse($message); -} // end if canEdit('Events') + $text = '%' .$text. '%'; + array_push($likes, $col.' LIKE ?'); + array_push($query['values'], $text); + } + $wherevalues = $query['values']; + $where = ' WHERE (' .implode(' OR ', $likes). ')'; -ajaxError('Unrecognised action '.$_REQUEST['action'].' or insufficient permissions for user '.$user['Username']); + } else if ( $search != '' ) { + + $search = '%' .$search. '%'; + foreach ( $columns as $col ) { + array_push($likes, $col.' LIKE ?'); + array_push($query['values'], $search); + } + $wherevalues = $query['values']; + $where = ' WHERE (' .implode(' OR ', $likes). ')'; + } + + $query['sql'] = 'SELECT ' .$col_str. ' FROM `' .$table. '` ' .$where. ' ORDER BY ' .$sort. ' ' .$order. ' LIMIT ?, ?'; + array_push($query['values'], $offset, $limit); + + //ZM\Warning('Calling the following sql query: ' .$query['sql']); + + $data['totalNotFiltered'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table, 'Total'); + if ( $search != '' || count($advsearch) ) { + $data['total'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table.$where , 'Total', $wherevalues); + } else { + $data['total'] = $data['totalNotFiltered']; + } + + $storage_areas = ZM\Storage::find(); + $StorageById = array(); + foreach ( $storage_areas as $S ) { + $StorageById[$S->Id()] = $S; + } + + $monitor_names = ZM\Monitor::find(); + $MonitorById = array(); + foreach ( $monitor_names as $S ) { + $MonitorById[$S->Id()] = $S; + } + + $rows = array(); + foreach ( dbFetchAll($query['sql'], NULL, $query['values']) as $row ) { + // Modify the row data as needed + $row['StartTime'] = strftime(STRF_FMT_DATETIME_SHORTER, strtotime($row['StartTime'])); + $row['EndTime'] = strftime(STRF_FMT_DATETIME_SHORTER, strtotime($row['StartTime'])); + $row['Storage'] = ( $row['StorageId'] and isset($StorageById[$row['StorageId']]) ) ? $StorageById[$row['StorageId']]->Name() : ''; + $row['Monitor'] = ( $row['MonitorId'] and isset($MonitorById[$row['MonitorId']]) ) ? $MonitorById[$row['MonitorId']]->Name() : ''; + $rows[] = $row; + } + $data['rows'] = $rows; + $data['updated'] = preg_match('/%/', DATE_FMT_CONSOLE_LONG) ? strftime(DATE_FMT_CONSOLE_LONG) : date(DATE_FMT_CONSOLE_LONG); + + return $data; +} ?> diff --git a/web/skins/classic/views/js/events.js b/web/skins/classic/views/js/events.js index 3710f7e80..015d41a01 100644 --- a/web/skins/classic/views/js/events.js +++ b/web/skins/classic/views/js/events.js @@ -1,3 +1,13 @@ +var backBtn = $j('#backBtn'); +var viewBtn = $j('#viewBtn'); +var archiveBtn = $j('#archiveBtn'); +var unarchiveBtn = $j('#unarchiveBtn'); +var editBtn = $j('#editBtn'); +var exportBtn = $j('#exportBtn'); +var downloadBtn = $j('#downloadBtn'); +var deleteBtn = $j('#deleteBtn'); +var table = $j('#eventTable'); + function thumbnail_onmouseover(event) { var img = event.target; img.src = ''; @@ -56,7 +66,7 @@ function manageDelConfirmModalBtns() { var selections = getIdSelections(); evt.preventDefault(); - $j.getJSON(thisUrl + '?request=events&action=delete&eids[]='+selections.join('&eids[]=')) + $j.getJSON(thisUrl + '?request=events&task=delete&eids[]='+selections.join('&eids[]=')) .done( function(data) { $j('#eventTable').bootstrapTable('refresh'); window.location.reload(true); @@ -85,16 +95,6 @@ function getEventDetailModal(eid) { } function initPage() { - var backBtn = $j('#backBtn'); - var viewBtn = $j('#viewBtn'); - var archiveBtn = $j('#archiveBtn'); - var unarchiveBtn = $j('#unarchiveBtn'); - var editBtn = $j('#editBtn'); - var exportBtn = $j('#exportBtn'); - var downloadBtn = $j('#downloadBtn'); - var deleteBtn = $j('#deleteBtn'); - var table = $j('#eventTable'); - // Load the delete confirmation modal into the DOM getDelConfirmModal(); @@ -169,7 +169,7 @@ function initPage() { var selections = getIdSelections(); evt.preventDefault(); - $j.getJSON(thisUrl + '?request=events&action=archive&eids[]='+selections.join('&eids[]=')) + $j.getJSON(thisUrl + '?request=events&task=archive&eids[]='+selections.join('&eids[]=')) .done( function(data) { $j('#eventTable').bootstrapTable('refresh'); window.location.reload(true); @@ -188,7 +188,7 @@ function initPage() { console.log(selections); evt.preventDefault(); - $j.getJSON(thisUrl + '?request=events&action=unarchive&eids[]='+selections.join('&eids[]=')) + $j.getJSON(thisUrl + '?request=events&task=unarchive&eids[]='+selections.join('&eids[]=')) .done( function(data) { $j('#eventTable').bootstrapTable('refresh'); window.location.reload(true); From 14894dfb0053f579802441c8e45cf1fa3cc09ff7 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 19 Oct 2020 09:08:25 -0400 Subject: [PATCH 0450/2339] remove extra comma --- web/skins/classic/views/event.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/event.php b/web/skins/classic/views/event.php index cb683adb8..b9c2d8f38 100644 --- a/web/skins/classic/views/event.php +++ b/web/skins/classic/views/event.php @@ -209,7 +209,7 @@ if ( ($codec == 'MP4' || $codec == 'auto' ) && $Event->DefaultVideo() ) { array_map(function($r){return $r/100;}, array_filter( array_keys($rates), - function($r){return $r >= 0 ? true : false;}, + function($r){return $r >= 0 ? true : false;} ))) ?>], "plugins": { "zoomrotate": { "zoom": ""}}}' > From 7ae7e05f14d283872ee5cda0ce1c5d0479aa7091 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Mon, 19 Oct 2020 09:29:39 -0500 Subject: [PATCH 0451/2339] roughin ajax call in event.js for server side pagination --- web/skins/classic/views/js/events.js | 43 ++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/web/skins/classic/views/js/events.js b/web/skins/classic/views/js/events.js index 015d41a01..848ba23c3 100644 --- a/web/skins/classic/views/js/events.js +++ b/web/skins/classic/views/js/events.js @@ -8,6 +8,49 @@ var downloadBtn = $j('#downloadBtn'); var deleteBtn = $j('#deleteBtn'); var table = $j('#eventTable'); +/* +This is the format of the json object sent by bootstrap-table + +var params = +{ +"type":"get", +"data": + { + "search":"some search text", + "sort":"StartTime", + "order":"asc", + "offset":0, + "limit":25 + "filter": + { + "Name":"some advanced search text" + "StartTime":"some more advanced search text" + } + }, +"cache":true, +"contentType":"application/json", +"dataType":"json" +}; +*/ + +// Called by bootstrap-table to retrieve zm event data +function ajaxRequest(params) { + $j.getJSON(thisUrl + '?view=request&request=events&task=query', params.data) + .done(function(data) { + //console.log('Ajax parameters: ' + JSON.stringify(params)); + // rearrange the result into what bootstrap-table expects + var rows = processRows(data.rows); + params.success({total: data.total, totalNotFiltered: data.totalNotFiltered, rows: rows}); + }) + .fail(logAjaxFail); +} + +function processRows(rows) { + // TO-DO: Inject desired html for the cells in each row + + return rows; +} + function thumbnail_onmouseover(event) { var img = event.target; img.src = ''; From cc24df95933ca22effad1e0ec56680109846b54c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 8 Oct 2020 16:46:30 -0400 Subject: [PATCH 0452/2339] init shared_data in the purpose=QUERY case to prevent crash. Also don't load zones if we don't need them --- src/zm_monitor.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 31ece8a0e..260e11ead 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -492,6 +492,8 @@ Monitor::Monitor( shared_data->last_read_time = 0; shared_data->alarm_x = -1; shared_data->alarm_y = -1; + } else { + shared_data = nullptr; } if ( ( ! mem_ptr ) || ! shared_data->valid ) { @@ -2103,7 +2105,6 @@ Monitor *Monitor::Load(MYSQL_ROW dbrow, bool load_zones, Purpose purpose) { } else { v4l_captures_per_frame = config.captures_per_frame; } - Debug(1, "Got %d for v4l_captures_per_frame", v4l_captures_per_frame); col++; std::string protocol = dbrow[col] ? dbrow[col] : ""; col++; @@ -2372,10 +2373,13 @@ Monitor *Monitor::Load(MYSQL_ROW dbrow, bool load_zones, Purpose purpose) { 0 ); camera->setMonitor(monitor); - Zone **zones = 0; - int n_zones = Zone::Load(monitor, zones); - monitor->AddZones(n_zones, zones); - monitor->AddPrivacyBitmask(zones); + int n_zones = 0; + if ( load_zones ) { + Zone **zones = 0; + n_zones = Zone::Load(monitor, zones); + monitor->AddZones(n_zones, zones); + monitor->AddPrivacyBitmask(zones); + } Debug(1, "Loaded monitor %d(%s), %d zones", id, name, n_zones); return monitor; } // end Monitor *Monitor::Load(MYSQL_ROW dbrow, bool load_zones, Purpose purpose) From df2f5f814b3bfb716f05c303b2fffb6d194124df Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 8 Oct 2020 15:50:12 -0400 Subject: [PATCH 0453/2339] fix case in mocord where cause would not contain motion --- src/zm_monitor.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 260e11ead..24a50488d 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1458,11 +1458,12 @@ bool Monitor::Analyse() { } if ( last_motion_score ) { score += last_motion_score; - if ( !event ) { + // cause is calculated every frame, + //if ( !event ) { if ( cause.length() ) cause += ", "; cause += MOTION_CAUSE; - } + //} noteSetMap[MOTION_CAUSE] = zoneSet; } // end if motion_score //shared_data->active = signal; // unneccessary active gets set on signal change @@ -1560,7 +1561,7 @@ bool Monitor::Analyse() { alarm_cause = alarm_cause + "," + std::string(zones[i]->Label()); } } - if ( !alarm_cause.empty() ) alarm_cause[0] = ' '; + if ( !alarm_cause.empty() ) alarm_cause[0] = ' '; // replace leading , with a space alarm_cause = cause + alarm_cause; strncpy(shared_data->alarm_cause, alarm_cause.c_str(), sizeof(shared_data->alarm_cause)-1); Info("%s: %03d - Gone into alarm state PreAlarmCount: %u > AlarmFrameCount:%u Cause:%s", From eefbed04c19c8d8bdea505a01c091be7d3c95869 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 5 Oct 2020 12:11:39 -0400 Subject: [PATCH 0454/2339] Add debugging for min_section_length keeping us in ALERT --- src/zm_monitor.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 24a50488d..0bc8a8ac0 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1451,8 +1451,8 @@ bool Monitor::Analyse() { int new_motion_score = DetectMotion(*snap_image, zoneSet); Debug(3, - "After motion detection, last_motion_score(%d), new motion score(%d)", - last_motion_score, new_motion_score + "After motion detection, score(%d), last_motion_score(%d), new motion score(%d)", + score, last_motion_score, new_motion_score ); last_motion_score = new_motion_score; } @@ -1668,6 +1668,8 @@ bool Monitor::Analyse() { } else { shared_data->state = state = TAPE; } + } else { + Debug(1, "Not leaving ALERT beacuse image_count(%d)-last_alarm_count(%d) > post_event_count(%d) and timestamp.tv_sec(%d) - recording.tv_src(%d) >= min_section_length(%d)", image_count, last_alarm_count, post_event_count, timestamp->tv_sec, video_store_data->recording.tv_sec, min_section_length); } } // end if ALARM or ALERT From 89f298771fb3689ee0167f2d011f38b18c9bd362 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Mon, 19 Oct 2020 12:25:13 -0500 Subject: [PATCH 0455/2339] server pagination backend improvements --- web/ajax/events.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/web/ajax/events.php b/web/ajax/events.php index c54fddd06..702d85a1f 100644 --- a/web/ajax/events.php +++ b/web/ajax/events.php @@ -34,7 +34,7 @@ $search = isset($_REQUEST['search']) ? $_REQUEST['search'] : ''; $advsearch = isset($_REQUEST['filter']) ? json_decode($_REQUEST['filter'], JSON_OBJECT_AS_ARRAY) : array(); // Sort specifies the name of the column to sort on -$sort = 'AttrStartTime'; +$sort = 'StartTime'; if ( isset($_REQUEST['sort']) ) { if ( !in_array($_REQUEST['sort'], array_merge($columns, $col_alt)) ) { ZM\Error('Invalid sort field: ' . $_REQUEST['sort']); @@ -120,7 +120,7 @@ function queryRequest($search, $advsearch, $sort, $offset, $order, $limit) { $table = 'Events'; // The names of the dB columns in the log table we are interested in - $columns = array('Id', 'MonitorId', 'StorageId', 'Name', 'Cause', 'StartTime', 'EndTime', 'Frames', 'AlarmFrames', 'TotScore', 'AvgScore', 'MaxScore', 'Archived', 'Emailed', 'DiskSpace'); + $columns = array('Id', 'MonitorId', 'StorageId', 'Name', 'Cause', 'StartTime', 'EndTime', 'Length', 'Frames', 'AlarmFrames', 'TotScore', 'AvgScore', 'MaxScore', 'Archived', 'Emailed', 'DiskSpace'); // The names of columns shown in the log view that are NOT dB columns in the database $col_alt = array('Monitor', 'Storage'); @@ -186,10 +186,14 @@ function queryRequest($search, $advsearch, $sort, $offset, $order, $limit) { $rows = array(); foreach ( dbFetchAll($query['sql'], NULL, $query['values']) as $row ) { // Modify the row data as needed + $row['Monitor'] = ( $row['MonitorId'] and isset($MonitorById[$row['MonitorId']]) ) ? $MonitorById[$row['MonitorId']]->Name() : ''; + $row['Archived'] = $row['Archived'] ? 'Yes' : 'No'; + $row['Emailed'] = $row['Emailed'] ? 'Yes' : 'No'; $row['StartTime'] = strftime(STRF_FMT_DATETIME_SHORTER, strtotime($row['StartTime'])); $row['EndTime'] = strftime(STRF_FMT_DATETIME_SHORTER, strtotime($row['StartTime'])); - $row['Storage'] = ( $row['StorageId'] and isset($StorageById[$row['StorageId']]) ) ? $StorageById[$row['StorageId']]->Name() : ''; - $row['Monitor'] = ( $row['MonitorId'] and isset($MonitorById[$row['MonitorId']]) ) ? $MonitorById[$row['MonitorId']]->Name() : ''; + $row['Length'] = gmdate('H:i:s', $row['Length'] ); + $row['Storage'] = ( $row['StorageId'] and isset($StorageById[$row['StorageId']]) ) ? $StorageById[$row['StorageId']]->Name() : 'Default'; + $row['DiskSpace'] = human_filesize($row['DiskSpace']); $rows[] = $row; } $data['rows'] = $rows; From 617a1faa99fdc1635ac6f1809d7c5fdbef28ba34 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 5 Oct 2020 09:19:48 -0400 Subject: [PATCH 0456/2339] Add pre-alarm frames when alarm_frame_count > 1 and prealarmcount=0 --- src/zm_monitor.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 0bc8a8ac0..b66341beb 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1633,8 +1633,17 @@ bool Monitor::Analyse() { } } event->AddFrames(pre_event_images, images, timestamps); - } - if ( alarm_frame_count ) { + } else if ( alarm_frame_count > 1 ) { + int temp_alarm_frame_count = alarm_frame_count; + while ( --temp_alarm_frame_count ) { + Debug(1, "Adding previous frame due to alarm_frame_count %d", pre_index); + event->AddFrame(image_buffer[pre_index].image, *image_buffer[pre_index].timestamp, 0, nullptr); + pre_index = (pre_index + 1)%image_buffer_count; + } + } // end if pre_event_images + + if ( ( alarm_frame_count > 1 ) && Event::PreAlarmCount() ) { + Debug(1, "alarm frame count so SavePreAlarmFrames"); event->SavePreAlarmFrames(); } } From 080557d580a9d22f81a7162f6f9bd0007eb7159a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 19 Oct 2020 14:27:43 -0400 Subject: [PATCH 0457/2339] add an id to buttons div so that we can use it when calling scaleToFit --- web/skins/classic/views/cycle.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/cycle.php b/web/skins/classic/views/cycle.php index dd12b0fa3..745cec755 100644 --- a/web/skins/classic/views/cycle.php +++ b/web/skins/classic/views/cycle.php @@ -170,7 +170,7 @@ xhtmlHeaders(__FILE__, translate('CycleWatch')); ?> -
+
From 127ef9a130861b52acc385bd7da3dfcbefb29baa Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 19 Oct 2020 14:28:02 -0400 Subject: [PATCH 0458/2339] Fix scaling when using ScaleToFit --- web/skins/classic/views/js/cycle.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/web/skins/classic/views/js/cycle.js b/web/skins/classic/views/js/cycle.js index 6d2c3bdd4..d4ae50d44 100644 --- a/web/skins/classic/views/js/cycle.js +++ b/web/skins/classic/views/js/cycle.js @@ -40,6 +40,8 @@ function cyclePrev() { function initCycle() { periodical_id = nextCycleView.periodical(cycleRefreshTimeout); + var scale = $j('#scale').val(); + if ( scale == '0' || scale == 'auto' ) changeScale(); } function changeSize() { @@ -89,8 +91,6 @@ function changeScale() { Cookie.write('zmCycleScale', scale, {duration: 10*365}); Cookie.write('zmCycleWidth', 'auto', {duration: 10*365}); Cookie.write('zmCycleHeight', 'auto', {duration: 10*365}); - var newWidth = ( monitorData[monIdx].width * scale ) / SCALE_BASE; - var newHeight = ( monitorData[monIdx].height * scale ) / SCALE_BASE; // Scale the frame monitor_frame = $j('#imageFeed'); @@ -100,6 +100,8 @@ function changeScale() { } if ( scale != '0' && scale != '' && scale != 'auto' ) { + var newWidth = ( monitorData[monIdx].width * scale ) / SCALE_BASE; + var newHeight = ( monitorData[monIdx].height * scale ) / SCALE_BASE; if ( newWidth ) { monitor_frame.css('width', newWidth+'px'); } @@ -107,8 +109,13 @@ function changeScale() { monitor_frame.css('height', newHeight+'px'); } } else { - monitor_frame.css('width', '100%'); - monitor_frame.css('height', 'auto'); + //var bottomEl = streamMode == 'stills' ? $j('#eventImageNav') : $j('#replayStatus'); + var newSize = scaleToFit(monitorData[monIdx].width, monitorData[monIdx].height, monitor_frame, $j('#buttons')); + newWidth = newSize.width; + newHeight = newSize.height; + autoScale = newSize.autoScale; + monitor_frame.width(newWidth); + monitor_frame.height(newHeight); } /*Stream could be an applet so can't use moo tools*/ @@ -124,6 +131,7 @@ function changeScale() { //src = src.replace(/rand=\d+/i,'rand='+Math.floor((Math.random() * 1000000) )); src = src.replace(/scale=[\.\d]+/i, 'scale='+scale); + // zms doesn't actually use width&height if ( scale != '0' && scale != '' && scale != 'auto' ) { src = src.replace(/width=[\.\d]+/i, 'width='+newWidth); src = src.replace(/height=[\.\d]+/i, 'height='+newHeight); From 0e638745332513412bbddeae9d98a963d1eaf89b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 19 Oct 2020 14:28:21 -0400 Subject: [PATCH 0459/2339] fix calling changeScale when scale is 0 instead of auto --- web/skins/classic/views/js/watch.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/views/js/watch.js b/web/skins/classic/views/js/watch.js index 19f74333b..ed4f370ae 100644 --- a/web/skins/classic/views/js/watch.js +++ b/web/skins/classic/views/js/watch.js @@ -848,7 +848,7 @@ function initPage() { if ( refreshApplet && appletRefreshTime ) { appletRefresh.delay(appletRefreshTime*1000); } - if ( scale == 'auto' ) changeScale(); + if ( scale == 'auto' || scale == '0' ) changeScale(); if ( window.history.length == 1 ) { $j('#closeControl').html(''); } @@ -858,7 +858,7 @@ function initPage() { } else if ( monitorRefresh > 0 ) { setInterval(reloadWebSite, monitorRefresh*1000); } -} +} // initPage // Kick everything off window.addEventListener('DOMContentLoaded', initPage); From 8a6aaa019f8abeb693fbeaa6b12a800911223c5d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 19 Oct 2020 14:29:18 -0400 Subject: [PATCH 0460/2339] Bump version for release to 1.34.22 --- distros/redhat/zoneminder.spec | 2 +- version | 2 +- web/skins/classic/css/base/views/cycle.css | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 web/skins/classic/css/base/views/cycle.css diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index d602ec855..e0de33c96 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -28,7 +28,7 @@ %global _hardened_build 1 Name: zoneminder -Version: 1.34.21 +Version: 1.34.22 Release: 1%{?dist} Summary: A camera monitoring and analysis tool Group: System Environment/Daemons diff --git a/version b/version index 63a880485..9bda6b214 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.34.21 +1.34.22 diff --git a/web/skins/classic/css/base/views/cycle.css b/web/skins/classic/css/base/views/cycle.css new file mode 100644 index 000000000..9d89bc4b3 --- /dev/null +++ b/web/skins/classic/css/base/views/cycle.css @@ -0,0 +1,3 @@ +#imageFeed { + margin: 0 auto; +} From 4e391708f1f5d0e1098fd57960b5e92958261087 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Mon, 19 Oct 2020 14:18:21 -0500 Subject: [PATCH 0461/2339] event view server pagination WIP --- web/ajax/events.php | 6 ++++-- web/skins/classic/views/js/events.js | 13 ++++++++++++- web/skins/classic/views/js/events.js.php | 4 ++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/web/ajax/events.php b/web/ajax/events.php index 702d85a1f..ab2ff6a44 100644 --- a/web/ajax/events.php +++ b/web/ajax/events.php @@ -186,9 +186,11 @@ function queryRequest($search, $advsearch, $sort, $offset, $order, $limit) { $rows = array(); foreach ( dbFetchAll($query['sql'], NULL, $query['values']) as $row ) { // Modify the row data as needed + $row['Name'] = validHtmlStr($row['Name']); + $row['Archived'] = $row['Archived'] ? translate('Yes') : translate('No'); + $row['Emailed'] = $row['Emailed'] ? translate('Yes') : translate('No'); $row['Monitor'] = ( $row['MonitorId'] and isset($MonitorById[$row['MonitorId']]) ) ? $MonitorById[$row['MonitorId']]->Name() : ''; - $row['Archived'] = $row['Archived'] ? 'Yes' : 'No'; - $row['Emailed'] = $row['Emailed'] ? 'Yes' : 'No'; + $row['Cause'] = validHtmlStr($row['Cause']); $row['StartTime'] = strftime(STRF_FMT_DATETIME_SHORTER, strtotime($row['StartTime'])); $row['EndTime'] = strftime(STRF_FMT_DATETIME_SHORTER, strtotime($row['StartTime'])); $row['Length'] = gmdate('H:i:s', $row['Length'] ); diff --git a/web/skins/classic/views/js/events.js b/web/skins/classic/views/js/events.js index 848ba23c3..2c2ce3d17 100644 --- a/web/skins/classic/views/js/events.js +++ b/web/skins/classic/views/js/events.js @@ -46,7 +46,18 @@ function ajaxRequest(params) { } function processRows(rows) { - // TO-DO: Inject desired html for the cells in each row + // WIP: Inject desired html and formatting for the cells in each row + $j.each(rows, function(ndx, row) { + var eid = row.Id; + var mid = row.MonitorId; + var archived = row.Archived == yesString ? archivedString : ''; + var emailed = row.Emailed == yesString ? emailedString : ''; + + row.Id = '' + eid + ''; + row.Name = '' + row.Name + '' + + '
' + archived + emailed + '
'; + row.Monitor = '' + row.Monitor + ''; + }); return rows; } diff --git a/web/skins/classic/views/js/events.js.php b/web/skins/classic/views/js/events.js.php index 3a60a97ba..48f405dd7 100644 --- a/web/skins/classic/views/js/events.js.php +++ b/web/skins/classic/views/js/events.js.php @@ -7,3 +7,7 @@ var filterQuery = ''; var confirmDeleteEventsString = ""; +var archivedString = ""; +var emailedString = ""; +var yesString = ""; +var noString = ""; From bfa45b0c431adc623d80c217e732b1666cb5bb48 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Tue, 20 Oct 2020 08:10:43 -0500 Subject: [PATCH 0462/2339] continue work on event view server pagination --- web/ajax/events.php | 3 ++- web/skins/classic/views/js/events.js | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/web/ajax/events.php b/web/ajax/events.php index ab2ff6a44..e241067ad 100644 --- a/web/ajax/events.php +++ b/web/ajax/events.php @@ -120,7 +120,7 @@ function queryRequest($search, $advsearch, $sort, $offset, $order, $limit) { $table = 'Events'; // The names of the dB columns in the log table we are interested in - $columns = array('Id', 'MonitorId', 'StorageId', 'Name', 'Cause', 'StartTime', 'EndTime', 'Length', 'Frames', 'AlarmFrames', 'TotScore', 'AvgScore', 'MaxScore', 'Archived', 'Emailed', 'DiskSpace'); + $columns = array('Id', 'MonitorId', 'StorageId', 'Name', 'Cause', 'StartTime', 'EndTime', 'Length', 'Frames', 'AlarmFrames', 'TotScore', 'AvgScore', 'MaxScore', 'Archived', 'Emailed', 'Notes', 'DiskSpace'); // The names of columns shown in the log view that are NOT dB columns in the database $col_alt = array('Monitor', 'Storage'); @@ -195,6 +195,7 @@ function queryRequest($search, $advsearch, $sort, $offset, $order, $limit) { $row['EndTime'] = strftime(STRF_FMT_DATETIME_SHORTER, strtotime($row['StartTime'])); $row['Length'] = gmdate('H:i:s', $row['Length'] ); $row['Storage'] = ( $row['StorageId'] and isset($StorageById[$row['StorageId']]) ) ? $StorageById[$row['StorageId']]->Name() : 'Default'; + $row['Notes'] = htmlspecialchars($row['Notes']); $row['DiskSpace'] = human_filesize($row['DiskSpace']); $rows[] = $row; } diff --git a/web/skins/classic/views/js/events.js b/web/skins/classic/views/js/events.js index 2c2ce3d17..b24f65e5f 100644 --- a/web/skins/classic/views/js/events.js +++ b/web/skins/classic/views/js/events.js @@ -47,6 +47,7 @@ function ajaxRequest(params) { function processRows(rows) { // WIP: Inject desired html and formatting for the cells in each row + // REMINDER: Make these lines dependent on user permissions e.g. canEditEvents $j.each(rows, function(ndx, row) { var eid = row.Id; var mid = row.MonitorId; @@ -57,6 +58,15 @@ function processRows(rows) { row.Name = '' + row.Name + '' + '
' + archived + emailed + '
'; row.Monitor = '' + row.Monitor + ''; + row.Cause = '' + row.Cause + ''; + if ( row.Notes.indexOf('detected:') >= 0 ) { + row.Cause = row.Cause + '
' + row.Notes + '
'; + } else if ( row.Notes != 'Forced Web: ' ) { + row.Cause = row.Cause + '
' + row.Notes + '
'; + } + row.Frames = '' + row.Frames + ''; + row.AlarmFrames = '' + row.AlarmFrames + ''; + row.MaxScore = '' + row.MaxScore + ''; }); return rows; @@ -316,6 +326,16 @@ function initPage() { getEventDetailModal(eid); }); + // Update table links each time after new data is loaded + table.on('post-body.bs.table', function(data) { + // Manage the eventdetail links in the events list + $j(".eDetailLink").click(function(evt) { + evt.preventDefault(); + var eid = $j(this).data('eid'); + getEventDetailModal(eid); + }); + }); + // The table is initially given a hidden style, so now that we are done rendering, show it table.show(); } From 1a779585486bd05e09a39a1bd2dc8c4ed0524e20 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 20 Oct 2020 11:52:18 -0400 Subject: [PATCH 0463/2339] Make loading the function modal happen on click instead of every page load. --- web/skins/classic/views/js/console.js | 91 ++++++++++++++------------- 1 file changed, 47 insertions(+), 44 deletions(-) diff --git a/web/skins/classic/views/js/console.js b/web/skins/classic/views/js/console.js index 7e5e43840..52b7aedc2 100644 --- a/web/skins/classic/views/js/console.js +++ b/web/skins/classic/views/js/console.js @@ -128,45 +128,55 @@ function reloadWindow() { } // Manage the the Function modal and its buttons -function manageFunctionModal() { - $j('.functionLnk').click(function(evt) { - evt.preventDefault(); - if ( !canEditEvents ) { - enoperm(); - return; - } - var mid = evt.currentTarget.getAttribute('data-mid'); - monitor = monitors[mid]; - if ( !monitor ) { - console.error("No monitor found for mid " + mid); - return; - } +function manageFunctionModal(evt) { + evt.preventDefault(); - var function_form = document.getElementById('function_form'); - if ( !function_form ) { - console.error("Unable to find form with id function_form"); - return; - } - function_form.elements['newFunction'].value = monitor.Function; - function_form.elements['newEnabled'].checked = monitor.Enabled == '1'; - function_form.elements['mid'].value = mid; - document.getElementById('function_monitor_name').innerHTML = monitor.Name; + if ( !canEditEvents ) { + enoperm(); + return; + } - $j('#modalFunction').modal('show'); - }); + if ( ! $j('#modalFunction').length ) { + // Load the Function modal on page load + $j.getJSON(thisUrl + '?request=modal&modal=function') + .done(function(data) { + insertModalHtml('modalFunction', data.html); + // Manage the CANCEL modal buttons + $j('.funcCancelBtn').click(function(evt) { + evt.preventDefault(); + $j('#modalFunction').modal('hide'); + }); + // Manage the SAVE modal buttons + $j('.funcSaveBtn').click(function(evt) { + evt.preventDefault(); + $j('#function_form').submit(); + }); - // Manage the CANCEL modal buttons - $j('.funcCancelBtn').click(function(evt) { - evt.preventDefault(); - $j('#modalFunction').modal('hide'); - }); + manageFunctionModal(evt); + }) + .fail(logAjaxFail); + return; + } - // Manage the SAVE modal buttons - $j('.funcSaveBtn').click(function(evt) { - evt.preventDefault(); - $j('#function_form').submit(); - }); -} + var mid = evt.currentTarget.getAttribute('data-mid'); + monitor = monitors[mid]; + if ( !monitor ) { + console.error("No monitor found for mid " + mid); + return; + } + + var function_form = document.getElementById('function_form'); + if ( !function_form ) { + console.error("Unable to find form with id function_form"); + return; + } + function_form.elements['newFunction'].value = monitor.Function; + function_form.elements['newEnabled'].checked = monitor.Enabled == '1'; + function_form.elements['mid'].value = mid; + document.getElementById('function_monitor_name').innerHTML = monitor.Name; + + $j('#modalFunction').modal('show'); +} // end function manageFunctionModal function initPage() { reloadWindow.periodical(consoleRefreshTimeout); @@ -196,15 +206,8 @@ function initPage() { // Setup the thumbnail video animation initThumbAnimation(); - // Load the Function modal on page load - $j.getJSON(thisUrl + '?request=modal&modal=function') - .done(function(data) { - insertModalHtml('modalFunction', data.html); - // Manage the Function modal - manageFunctionModal(); - }) - .fail(logAjaxFail); -} + $j('.functionLnk').click(manageFunctionModal); +} // end function initPage function applySort(event, ui) { var monitor_ids = $j(this).sortable('toArray'); From bb5646baace75536cc25ecac9242c3e9b275df09 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 20 Oct 2020 12:31:06 -0400 Subject: [PATCH 0464/2339] Load Logout modal content on click instead of every page load --- web/skins/classic/js/skin.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/js/skin.js b/web/skins/classic/js/skin.js index 595da9788..b33d1bb7d 100644 --- a/web/skins/classic/js/skin.js +++ b/web/skins/classic/js/skin.js @@ -240,7 +240,7 @@ if ( currentView != 'none' && currentView != 'login' ) { $j(document).ready(function() { // Load the Logout and State modals into the dom - $j('#logoutButton').click(getLogoutModal()); + $j('#logoutButton').click(clickLogout); if ( canEditSystem ) $j('#stateModalBtn').click(getStateModal); // Trigger autorefresh of the widget bar stats on the navbar @@ -665,9 +665,18 @@ function getLogoutModal() { $j.getJSON(thisUrl + '?request=modal&modal=logout') .done(function(data) { insertModalHtml('modalLogout', data.html); + manageModalBtns('modalLogout'); + clickLogout(); }) .fail(logAjaxFail); } +function clickLogout() { + if ( ! $j('#modalLogout').length ) { + getLogoutModal(); + return; + } + $j('#modalLogout').modal('show'); +} function getStateModal() { $j.getJSON(thisUrl + '?request=modal&modal=state') @@ -769,13 +778,14 @@ function getModal(id) { } function manageModalBtns(id) { - // Manage the CANCEL modal button + // Manage the CANCEL modal button, note data-dismiss="modal" would work better var cancelBtn = document.getElementById(id+"CancelBtn"); if ( cancelBtn ) { document.getElementById(id+"CancelBtn").addEventListener('click', function onCancelClick(evt) { $j('#'+id).modal('hide'); }); } + // 'data-on-click-this' calls the global function in the attribute value with the element when a click happens. document.querySelectorAll('#'+id+'Modal button[data-on-click]').forEach(function attachOnClick(el) { var fnName = el.getAttribute('data-on-click'); From 41ed267b71aac4f3ef1f87e6f2eb4ff5a63f8ddd Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 20 Oct 2020 12:31:38 -0400 Subject: [PATCH 0465/2339] move view to the form action so that it is part of get request instead of post --- web/ajax/modals/logout.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/ajax/modals/logout.php b/web/ajax/modals/logout.php index e1c1053c3..a0648a70c 100644 --- a/web/ajax/modals/logout.php +++ b/web/ajax/modals/logout.php @@ -56,6 +56,7 @@ while ( $row = $result->fetch(PDO::FETCH_ASSOC) ) { ZM\Warning('Failed to decode ' . $row['data']); continue; } + ZM\Debug(print_r($_SESSION, true)); if ( isset($_SESSION['last_time']) ) { # This is a dead session continue; @@ -91,12 +92,11 @@ $_SESSION = $current_session;
diff --git a/web/skins/classic/views/js/events.js b/web/skins/classic/views/js/events.js index b51c679a3..d98d51f4f 100644 --- a/web/skins/classic/views/js/events.js +++ b/web/skins/classic/views/js/events.js @@ -321,13 +321,6 @@ function initPage() { $j('#deleteConfirm').modal('show'); }); - // Manage the eventdetail links in the events list - $j(".eDetailLink").click(function(evt) { - evt.preventDefault(); - var eid = $j(this).data('eid'); - getEventDetailModal(eid); - }); - // Update table links each time after new data is loaded table.on('post-body.bs.table', function(data) { // Manage the eventdetail links in the events list diff --git a/web/skins/classic/views/newevents.php b/web/skins/classic/views/newevents.php deleted file mode 100644 index 555f13f51..000000000 --- a/web/skins/classic/views/newevents.php +++ /dev/null @@ -1,128 +0,0 @@ -set($_REQUEST['filter']); -} - -parseSort(); - -$filterQuery = $filter->querystring(); - -xhtmlHeaders(__FILE__, translate('Events')); -getBodyTopHTML(); - -?> - -
- -
- - - - - - - - - - - -
- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- From e5563dc901d4563e76109793b4acf51a5c169b7d Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sun, 25 Oct 2020 16:06:37 -0500 Subject: [PATCH 0503/2339] remove unwanted # --- web/skins/classic/views/js/events.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/events.js b/web/skins/classic/views/js/events.js index d98d51f4f..b657c50cf 100644 --- a/web/skins/classic/views/js/events.js +++ b/web/skins/classic/views/js/events.js @@ -61,7 +61,7 @@ function processRows(rows) { if ( canEditMonitors ) row.Monitor = '' + row.Monitor + ''; if ( canEditEvents ) row.Cause = '' + row.Cause + ''; if ( row.Notes.indexOf('detected:') >= 0 ) { - row.Cause = row.Cause + '
' + row.Notes + '
'; + row.Cause = row.Cause + '
' + row.Notes + '
'; } else if ( row.Notes != 'Forced Web: ' ) { row.Cause = row.Cause + '
' + row.Notes + '
'; } From 706bf085f4b4ab63d8823acad56edf6bef79bd80 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 26 Oct 2020 09:58:47 -0400 Subject: [PATCH 0504/2339] Add pre and post sql conditions and pre-populate the return --- web/ajax/events.php | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/web/ajax/events.php b/web/ajax/events.php index d224b8742..8a2d735ca 100644 --- a/web/ajax/events.php +++ b/web/ajax/events.php @@ -115,6 +115,19 @@ function deleteRequest($eid) { } function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $limit) { + $data = array( + 'total' => 0, + 'totalNotFiltered' => 0, + 'rows' => array(), + 'updated' => preg_match('/%/', DATE_FMT_CONSOLE_LONG) ? strftime(DATE_FMT_CONSOLE_LONG) : date(DATE_FMT_CONSOLE_LONG) + ); + + $failed = !$filter->test_pre_sql_conditions(); + if ( $failed ) { + ZM\Debug('Pre conditions failed, not doing sql'); + return $data; + } + // Put server pagination code here // The table we want our data from $table = 'Events'; @@ -138,7 +151,6 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim } } $col_str = implode(', ', $columns); - $data = array(); $query = array(); $query['values'] = array(); $likes = array(); @@ -177,14 +189,8 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim $query['sql'] = 'SELECT ' .$col_str. ' FROM `' .$table. '` AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id'.$where.' ORDER BY LENGTH(' .$sort. '), ' .$sort. ' ' .$order. ' LIMIT ?, ?'; array_push($query['values'], $offset, $limit); - ZM\Warning('Calling the following sql query: ' .$query['sql']); + ZM\Debug('Calling the following sql query: ' .$query['sql']); - $data['totalNotFiltered'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table . ' AS E'. ($filter->sql() ? ' WHERE '.$filter->sql():''), 'Total'); - if ( $search != '' || count($advsearch) ) { - $data['total'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table . ' AS E'.$where , 'Total', $wherevalues); - } else { - $data['total'] = $data['totalNotFiltered']; - } $storage_areas = ZM\Storage::find(); $StorageById = array(); @@ -202,6 +208,10 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim foreach ( dbFetchAll($query['sql'], NULL, $query['values']) as $row ) { ZM\Debug("row".print_r($row,true)); $event = new ZM\Event($row); + if ( !$filter->test_post_sql_conditions($event) ) { + $event->remove_from_cache(); + continue; + } $scale = intval(5*100*ZM_WEB_LIST_THUMB_WIDTH / $event->Width()); $imgSrc = $event->getThumbnailSrc(array(),'&'); $streamSrc = $event->getStreamSrc(array( @@ -223,8 +233,9 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim $rows[] = $row; } $data['rows'] = $rows; - $data['updated'] = preg_match('/%/', DATE_FMT_CONSOLE_LONG) ? strftime(DATE_FMT_CONSOLE_LONG) : date(DATE_FMT_CONSOLE_LONG); + $data['totalNotFiltered'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table. ' AS E'. ($filter->sql() ? ' WHERE '.$filter->sql():''), 'Total'); + $data['total'] = count($rows); return $data; } ?> From 4c791b390f73ea5a538569c88c5d46d2a28654b1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 26 Oct 2020 09:59:15 -0400 Subject: [PATCH 0505/2339] fix warning due to undefined vars being used --- web/ajax/log.php | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/web/ajax/log.php b/web/ajax/log.php index bde07ed65..22897fd04 100644 --- a/web/ajax/log.php +++ b/web/ajax/log.php @@ -66,7 +66,7 @@ if ( isset($_REQUEST['limit']) ) { switch ( $task ) { case 'create' : - createRequest($task, $eid); + createRequest(); break; case 'query' : $data = queryRequest($search, $advsearch, $sort, $offset, $order, $limit); @@ -82,27 +82,27 @@ ajaxResponse($data); // function createRequest() { - if ( !empty($_POST['level']) && !empty($_POST['message']) ) { - ZM\logInit(array('id'=>'web_js')); + if ( !empty($_POST['level']) && !empty($_POST['message']) ) { + ZM\logInit(array('id'=>'web_js')); - $string = $_POST['message']; + $string = $_POST['message']; - $file = !empty($_POST['file']) ? preg_replace('/\w+:\/\/[\w.:]+\//', '', $_POST['file']) : ''; - if ( !empty($_POST['line']) ) { - $line = validInt($_POST['line']); - } else { - $line = NULL; - } - - $levels = array_flip(ZM\Logger::$codes); - if ( !isset($levels[$_POST['level']]) ) { - ZM\Panic('Unexpected logger level '.$_POST['level']); - } - $level = $levels[$_POST['level']]; - ZM\Logger::fetch()->logPrint($level, $string, $file, $line); + $file = !empty($_POST['file']) ? preg_replace('/\w+:\/\/[\w.:]+\//', '', $_POST['file']) : ''; + if ( !empty($_POST['line']) ) { + $line = validInt($_POST['line']); } else { - ZM\Error('Invalid log create: '.print_r($_POST, true)); + $line = NULL; } + + $levels = array_flip(ZM\Logger::$codes); + if ( !isset($levels[$_POST['level']]) ) { + ZM\Panic('Unexpected logger level '.$_POST['level']); + } + $level = $levels[$_POST['level']]; + ZM\Logger::fetch()->logPrint($level, $string, $file, $line); + } else { + ZM\Error('Invalid log create: '.print_r($_POST, true)); + } } function queryRequest($search, $advsearch, $sort, $offset, $order, $limit) { From 27b39a0258d58480c2ec6c6371bd75aade341710 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Mon, 26 Oct 2020 09:19:08 -0500 Subject: [PATCH 0506/2339] comment out warning used for debug --- web/ajax/events.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/ajax/events.php b/web/ajax/events.php index c27817be3..ff2c5b426 100644 --- a/web/ajax/events.php +++ b/web/ajax/events.php @@ -169,7 +169,7 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim $query['sql'] = 'SELECT ' .$col_str. ' FROM `' .$table. '` AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id'.$where.' ORDER BY ' .$sort. ' ' .$order. ' LIMIT ?, ?'; array_push($query['values'], $offset, $limit); - ZM\Warning('Calling the following sql query: ' .$query['sql']); + //ZM\Warning('Calling the following sql query: ' .$query['sql']); $data['totalNotFiltered'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table . ' AS E'. ($filter->sql() ? ' WHERE '.$filter->sql():''), 'Total'); if ( $search != '' || count($advsearch) ) { From 97573122bc090e0a9f88c8b0d54a73d9337739b6 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Mon, 26 Oct 2020 09:33:11 -0500 Subject: [PATCH 0507/2339] fix EndTime --- web/ajax/events.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/ajax/events.php b/web/ajax/events.php index ff2c5b426..c13be849d 100644 --- a/web/ajax/events.php +++ b/web/ajax/events.php @@ -200,7 +200,7 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim $row['Emailed'] = $row['Emailed'] ? translate('Yes') : translate('No'); $row['Cause'] = validHtmlStr($row['Cause']); $row['StartTime'] = strftime(STRF_FMT_DATETIME_SHORTER, strtotime($row['StartTime'])); - $row['EndTime'] = strftime(STRF_FMT_DATETIME_SHORTER, strtotime($row['StartTime'])); + $row['EndTime'] = strftime(STRF_FMT_DATETIME_SHORTER, strtotime($row['EndTime'])); $row['Length'] = gmdate('H:i:s', $row['Length'] ); $row['Storage'] = ( $row['StorageId'] and isset($StorageById[$row['StorageId']]) ) ? $StorageById[$row['StorageId']]->Name() : 'Default'; $row['Notes'] = htmlspecialchars($row['Notes']); From da87b5b475145bbda71d57f8ae1717e676dfd514 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 26 Oct 2020 13:06:05 -0400 Subject: [PATCH 0508/2339] Make invalid sort field non-fatal. Fix column specification in search and advscearch and fix resulting sql due to = instead of .= --- web/ajax/events.php | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/web/ajax/events.php b/web/ajax/events.php index 51df45035..4046c69f1 100644 --- a/web/ajax/events.php +++ b/web/ajax/events.php @@ -139,7 +139,8 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim $col_alt = array('Monitor', 'Storage'); if ( !in_array($sort, array_merge($columns, $col_alt)) ) { - ZM\Fatal('Invalid sort field: ' . $sort); + ZM\Error('Invalid sort field: ' . $sort); + $sort = 'Id'; } $data = array(); @@ -153,26 +154,31 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim if ( count($advsearch) ) { foreach ( $advsearch as $col=>$text ) { - if ( !in_array($col, array_merge($columns, $col_alt)) ) { + if ( in_array($col, $columns) ) { + $text = '%' .$text. '%'; + array_push($likes, 'E.'.$col.' LIKE ?'); + array_push($query['values'], $text); + } else if ( in_array($col, $col_alt) ) { + $text = '%' .$text. '%'; + array_push($likes, 'M.'.$col.' LIKE ?'); + array_push($query['values'], $text); + } else { ZM\Error("'$col' is not a sortable column name"); continue; } - $text = '%' .$text. '%'; - array_push($likes, $col.' LIKE ?'); - array_push($query['values'], $text); - } + } # end foreach col in advsearch $wherevalues = $query['values']; - $where = ' AND (' .implode(' OR ', $likes). ')'; + $where .= ($where != '') ? ' AND (' .implode(' OR ', $likes). ')' : implode(' OR ', $likes); } else if ( $search != '' ) { $search = '%' .$search. '%'; foreach ( $columns as $col ) { - array_push($likes, $col.' LIKE ?'); + array_push($likes, 'E.'.$col.' LIKE ?'); array_push($query['values'], $search); } $wherevalues = $query['values']; - $where = ' AND (' .implode(' OR ', $likes). ')'; + $where .= ( $where != '') ? ' AND (' .implode(' OR ', $likes). ')' : implode(' OR ', $likes); } if ( $where ) $where = ' WHERE '.$where; From 59cf5c33c24991c3aeee39b65df9a549228c45a6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 26 Oct 2020 13:06:22 -0400 Subject: [PATCH 0509/2339] reset search on events load --- web/skins/classic/views/js/events.js | 1 + 1 file changed, 1 insertion(+) diff --git a/web/skins/classic/views/js/events.js b/web/skins/classic/views/js/events.js index b657c50cf..ed591e510 100644 --- a/web/skins/classic/views/js/events.js +++ b/web/skins/classic/views/js/events.js @@ -336,6 +336,7 @@ function initPage() { table.find("tr td:nth-child(" + (thumb_ndx+1) + ")").addClass('colThumbnail zoom'); }); + table.bootstrapTable('resetSearch'); // The table is initially given a hidden style, so now that we are done rendering, show it table.show(); } From 1f64a263eb3da2d007bbf6b72c84d4eba1364857 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 26 Oct 2020 13:06:41 -0400 Subject: [PATCH 0510/2339] give better log when jqxhr is empty --- web/skins/classic/js/skin.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/web/skins/classic/js/skin.js b/web/skins/classic/js/skin.js index aec9ee1d5..f6cbb328a 100644 --- a/web/skins/classic/js/skin.js +++ b/web/skins/classic/js/skin.js @@ -351,6 +351,11 @@ if ( currentView != 'none' && currentView != 'login' ) { .done(setNavBar) .fail(function(jqxhr, textStatus, error) { console.log("Request Failed: " + textStatus + ", " + error); + if ( ! jqxhr.responseText ) { + console.log("No responseText in jqxhr"); + console.log(jqxhr); + return; + } console.log("Response Text: " + jqxhr.responseText.replace(/(<([^>]+)>)/gi, '')); if ( textStatus != "timeout" ) { // The idea is that this should only fail due to auth, so reload the page From fad4339713fe5ae8709f5a78d500429a42828f2a Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Mon, 26 Oct 2020 12:12:50 -0500 Subject: [PATCH 0511/2339] no need for full page reload with server pagination --- web/skins/classic/views/js/events.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/web/skins/classic/views/js/events.js b/web/skins/classic/views/js/events.js index ed591e510..f0bd0b3ac 100644 --- a/web/skins/classic/views/js/events.js +++ b/web/skins/classic/views/js/events.js @@ -135,7 +135,7 @@ function manageDelConfirmModalBtns() { $j.getJSON(thisUrl + '?request=events&task=delete&eids[]='+selections.join('&eids[]=')) .done( function(data) { $j('#eventTable').bootstrapTable('refresh'); - window.location.reload(true); + $j('#deleteConfirm').modal('hide'); }) .fail(logAjaxFail); }); @@ -238,7 +238,6 @@ function initPage() { $j.getJSON(thisUrl + '?request=events&task=archive&eids[]='+selections.join('&eids[]=')) .done( function(data) { $j('#eventTable').bootstrapTable('refresh'); - window.location.reload(true); }) .fail(logAjaxFail); }); @@ -257,11 +256,8 @@ function initPage() { $j.getJSON(thisUrl + '?request=events&task=unarchive&eids[]='+selections.join('&eids[]=')) .done( function(data) { $j('#eventTable').bootstrapTable('refresh'); - window.location.reload(true); }) .fail(logAjaxFail); - - //window.location.reload(true); }); // Manage the EDIT button From 7b106e2522eaa0289391d17e5de45de85fa6ce78 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Mon, 26 Oct 2020 12:20:26 -0500 Subject: [PATCH 0512/2339] don't use wildcards in advanced search --- web/ajax/events.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/ajax/events.php b/web/ajax/events.php index 32e8f7ce9..850628109 100644 --- a/web/ajax/events.php +++ b/web/ajax/events.php @@ -155,11 +155,11 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim foreach ( $advsearch as $col=>$text ) { if ( in_array($col, $columns) ) { - $text = '%' .$text. '%'; + //$text = '%' .$text. '%'; array_push($likes, 'E.'.$col.' LIKE ?'); array_push($query['values'], $text); } else if ( in_array($col, $col_alt) ) { - $text = '%' .$text. '%'; + //$text = '%' .$text. '%'; array_push($likes, 'M.'.$col.' LIKE ?'); array_push($query['values'], $text); } else { From 1fde123ebc9f03de0bf31df5728435716f15a0e0 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 26 Oct 2020 18:47:03 -0400 Subject: [PATCH 0513/2339] add LockRows to Filters --- db/zm_create.sql.in | 1 + 1 file changed, 1 insertion(+) diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index 71d07ad07..a8b83826f 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -303,6 +303,7 @@ CREATE TABLE `Filters` ( `UpdateDiskSpace` tinyint(3) unsigned NOT NULL default '0', `Background` tinyint(1) unsigned NOT NULL default '0', `Concurrent` tinyint(1) unsigned NOT NULL default '0', + `LockRows` tinyint(1) unsigned NOT NULL default '0', PRIMARY KEY (`Id`), KEY `Name` (`Name`) ) ENGINE=@ZM_MYSQL_ENGINE@; From a2596505e9ccd604b280af01c346bf89c6761bf7 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 26 Oct 2020 18:47:17 -0400 Subject: [PATCH 0514/2339] add LockRows to Filters --- web/includes/Filter.php | 1 + web/skins/classic/views/filter.php | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/web/includes/Filter.php b/web/includes/Filter.php index b6c163f91..bd22f3b89 100644 --- a/web/includes/Filter.php +++ b/web/includes/Filter.php @@ -29,6 +29,7 @@ class Filter extends ZM_Object { 'Background' => 0, 'Concurrent' => 0, 'Query_json' => '', + 'LockRows' => 0, ); protected $_querystring; diff --git a/web/skins/classic/views/filter.php b/web/skins/classic/views/filter.php index 96e0b9728..d53fff02a 100644 --- a/web/skins/classic/views/filter.php +++ b/web/skins/classic/views/filter.php @@ -485,6 +485,10 @@ if ( ZM_OPT_MESSAGE ) { Concurrent() ) { ?> checked="checked" data-on-click-this="updateButtons"/>

+

+ + LockRows() ) { ?> checked="checked" data-on-click-this="updateButtons"/> +


From 7a65a6464458a307861139417324faf65518a7c6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 26 Oct 2020 18:47:40 -0400 Subject: [PATCH 0515/2339] add LockRows to Filters --- scripts/ZoneMinder/lib/ZoneMinder/Filter.pm | 3 +++ scripts/zmfilter.pl.in | 2 ++ 2 files changed, 5 insertions(+) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm index 9bb13132c..85c09b141 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm @@ -77,6 +77,7 @@ UpdateDiskSpace UserId Background Concurrent +LockRows ); sub Execute { @@ -103,6 +104,8 @@ sub Execute { $sql =~ s/zmSystemLoad/$load/g; } + $sql .= ' FOR UPDATE' if $$self{LockRows}; + Debug("Filter::Execute SQL ($sql)"); my $sth = $ZoneMinder::Database::dbh->prepare_cached($sql) or Fatal("Can't prepare '$sql': ".$ZoneMinder::Database::dbh->errstr()); diff --git a/scripts/zmfilter.pl.in b/scripts/zmfilter.pl.in index 9a93c8953..5540e6944 100644 --- a/scripts/zmfilter.pl.in +++ b/scripts/zmfilter.pl.in @@ -277,6 +277,7 @@ FILTER: while( my $db_filter = $sth->fetchrow_hashref() ) { sub checkFilter { my $filter = shift; + my $in_transaction = ZoneMinder::Database::start_transaction($dbh) if $$filter{LockRows}; my @Events = $filter->Execute(); Debug( join(' ', @@ -396,6 +397,7 @@ sub checkFilter { $ZoneMinder::Database::dbh->commit(); } # end if UpdateDiskSpace } # end foreach event + ZoneMinder::Database::end_transaction($dbh, $in_transaction) if $$filter{LockRows}; } # end sub checkFilter sub generateVideo { From ffc5249a665edaa1d5bacbe9081d0f1593574a95 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 26 Oct 2020 18:47:55 -0400 Subject: [PATCH 0516/2339] add LockRows to Filters --- web/lang/en_gb.php | 1 + 1 file changed, 1 insertion(+) diff --git a/web/lang/en_gb.php b/web/lang/en_gb.php index b80121bed..0877f7399 100644 --- a/web/lang/en_gb.php +++ b/web/lang/en_gb.php @@ -371,6 +371,7 @@ $SLANG = array( 'FilterUpdateDiskSpace' => 'Update used disk space', 'FilterDeleteEvents' => 'Delete all matches', 'FilterCopyEvents' => 'Copy all matches', + 'FilterLockRows' => 'Lock Rows', 'FilterMoveEvents' => 'Move all matches', 'FilterEmailEvents' => 'Email details of all matches', 'FilterEmailTo' => 'Email To', From cd9b16a467da7c3ccb6fe2a1453a6d67a51080c9 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 26 Oct 2020 18:48:16 -0400 Subject: [PATCH 0517/2339] add LockRows to Filters --- db/zm_update-1.35.11.sql | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 db/zm_update-1.35.11.sql diff --git a/db/zm_update-1.35.11.sql b/db/zm_update-1.35.11.sql new file mode 100644 index 000000000..b8c54f713 --- /dev/null +++ b/db/zm_update-1.35.11.sql @@ -0,0 +1,18 @@ +-- +-- Update Filters table to have a LockRows Column +-- + +SELECT 'Checking for LockRows in Filters'; +SET @s = (SELECT IF( + (SELECT COUNT(*) + FROM INFORMATION_SCHEMA.COLUMNS + WHERE table_name = 'Filters' + AND table_schema = DATABASE() + AND column_name = 'LockRows' + ) > 0, +"SELECT 'Column LockRows already exists in Filters'", +"ALTER TABLE Filters ADD COLUMN `LockRows` tinyint(1) unsigned NOT NULL default '0' AFTER `Concurrent`" +)); + +PREPARE stmt FROM @s; +EXECUTE stmt; From f3f0a6baff2de703928a23ef2362d5fd4b053cfa Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 26 Oct 2020 18:48:43 -0400 Subject: [PATCH 0518/2339] remove debug --- src/zm_ffmpeg_camera.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index e04f5e8ca..7d990bcd2 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -664,7 +664,6 @@ int FfmpegCamera::OpenFfmpeg() { } // int FfmpegCamera::OpenFfmpeg() int FfmpegCamera::Close() { - Debug(2, "CloseFfmpeg called."); mCanCapture = false; From a5bb2365b54d09fcc983e72a77a28582a961ab8f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 26 Oct 2020 18:49:03 -0400 Subject: [PATCH 0519/2339] update auth_relay when we update auth_hash --- web/skins/classic/js/skin.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/web/skins/classic/js/skin.js b/web/skins/classic/js/skin.js index f6cbb328a..85449927c 100644 --- a/web/skins/classic/js/skin.js +++ b/web/skins/classic/js/skin.js @@ -372,10 +372,14 @@ if ( currentView != 'none' && currentView != 'login' ) { } if ( data.auth ) { if ( data.auth != auth_hash ) { + console.log("Update auth_hash to "+data.auth); // Update authentication token. auth_hash = data.auth; } } + if ( data.auth_relay ) { + auth_relay = data.auth_relay; + } // iterate through all the keys then update each element id with the same name for (var key of Object.keys(data)) { if ( key == "auth" ) continue; From 1690bcbd381a4f461bbbf5ac72c091212037c116 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 26 Oct 2020 18:49:14 -0400 Subject: [PATCH 0520/2339] update auth_relay when we update auth_hash --- web/ajax/status.php | 1 + 1 file changed, 1 insertion(+) diff --git a/web/ajax/status.php b/web/ajax/status.php index 0bafe16e4..190d239ad 100644 --- a/web/ajax/status.php +++ b/web/ajax/status.php @@ -6,6 +6,7 @@ if ( $_REQUEST['entity'] == 'navBar' ) { $auth_hash = generateAuthHash(ZM_AUTH_HASH_IPS); if ( isset($_REQUEST['auth']) and ($_REQUEST['auth'] != $auth_hash) ) { $data['auth'] = $auth_hash; + $data['auth_relay'] = get_auth_relay(); } } // Each widget on the navbar has its own function From c67b3c5a1f1189e41f2cf617481a7874785378b8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 26 Oct 2020 18:49:41 -0400 Subject: [PATCH 0521/2339] fix button disabled status. We now have checkboxes that aren't actions so we need to be more explicit --- web/skins/classic/views/js/filter.js | 53 +++++++++++++--------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/web/skins/classic/views/js/filter.js b/web/skins/classic/views/js/filter.js index fd7ee94ca..707fb06e1 100644 --- a/web/skins/classic/views/js/filter.js +++ b/web/skins/classic/views/js/filter.js @@ -74,35 +74,32 @@ function validateForm(form) { function updateButtons(element) { var form = element.form; - if ( element.type == 'checkbox' && element.checked ) { - form.elements['executeButton'].disabled = false; - } else { - var canExecute = false; - if ( form.elements['filter[AutoArchive]'] && form.elements['filter[AutoArchive]'].checked ) { - canExecute = true; - } else if ( form.elements['filter[AutoUnarchive]'] && form.elements['filter[AutoUnarchive]'].checked ) { - canExecute = true; - } else if ( form.elements['filter[AutoCopy]'] && form.elements['filter[AutoCopy]'].checked ) { - canExecute = true; - } else if ( form.elements['filter[AutoMove]'] && form.elements['filter[AutoMove]'].checked ) { - canExecute = true; - } else if ( form.elements['filter[AutoVideo]'] && form.elements['filter[AutoVideo]'].checked ) { - canExecute = true; - } else if ( form.elements['filter[AutoUpload]'] && form.elements['filter[AutoUpload]'].checked ) { - canExecute = true; - } else if ( form.elements['filter[AutoEmail]'] && form.elements['filter[AutoEmail]'].checked ) { - canExecute = true; - } else if ( form.elements['filter[AutoMessage]'] && form.elements['filter[AutoMessage]'].checked ) { - canExecute = true; - } else if ( form.elements['filter[AutoExecute]'].checked && form.elements['filter[AutoExecuteCmd]'].value != '' ) { - canExecute = true; - } else if ( form.elements['filter[AutoDelete]'].checked ) { - canExecute = true; - } else if ( form.elements['filter[UpdateDiskSpace]'].checked ) { - canExecute = true; - } - form.elements['executeButton'].disabled = !canExecute; + + var canExecute = false; + if ( form.elements['filter[AutoArchive]'] && form.elements['filter[AutoArchive]'].checked ) { + canExecute = true; + } else if ( form.elements['filter[AutoUnarchive]'] && form.elements['filter[AutoUnarchive]'].checked ) { + canExecute = true; + } else if ( form.elements['filter[AutoCopy]'] && form.elements['filter[AutoCopy]'].checked ) { + canExecute = true; + } else if ( form.elements['filter[AutoMove]'] && form.elements['filter[AutoMove]'].checked ) { + canExecute = true; + } else if ( form.elements['filter[AutoVideo]'] && form.elements['filter[AutoVideo]'].checked ) { + canExecute = true; + } else if ( form.elements['filter[AutoUpload]'] && form.elements['filter[AutoUpload]'].checked ) { + canExecute = true; + } else if ( form.elements['filter[AutoEmail]'] && form.elements['filter[AutoEmail]'].checked ) { + canExecute = true; + } else if ( form.elements['filter[AutoMessage]'] && form.elements['filter[AutoMessage]'].checked ) { + canExecute = true; + } else if ( form.elements['filter[AutoExecute]'].checked && form.elements['filter[AutoExecuteCmd]'].value != '' ) { + canExecute = true; + } else if ( form.elements['filter[AutoDelete]'].checked ) { + canExecute = true; + } else if ( form.elements['filter[UpdateDiskSpace]'].checked ) { + canExecute = true; } + form.elements['executeButton'].disabled = !canExecute; if ( form.elements['filter[Name]'].value ) { form.elements['Save'].disabled = false; form.elements['SaveAs'].disabled = false; From 3825af8243e997eaec725aa2a967ba422a3bf652 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 28 Oct 2020 09:19:54 -0400 Subject: [PATCH 0522/2339] Add FOREIGN KEYS for EventId in Frames, Stats. MonitorId, ZoneId in Stats. MonitorId in Zones. --- db/zm_create.sql.in | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index 71d07ad07..940ba2a82 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -315,6 +315,7 @@ DROP TABLE IF EXISTS `Frames`; CREATE TABLE `Frames` ( `Id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `EventId` BIGINT UNSIGNED NOT NULL default '0', + FOREIGN KEY (`EventId`) REFERENCES `Events` (`Id`) ON DELETE CASCADE, `FrameId` int(10) unsigned NOT NULL default '0', `Type` enum('Normal','Bulk','Alarm') NOT NULL default 'Normal', `TimeStamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, @@ -608,8 +609,11 @@ DROP TABLE IF EXISTS `Stats`; CREATE TABLE `Stats` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT, `MonitorId` int(10) unsigned NOT NULL default '0', + FOREIGN KEY (`MonitorId`) REFERENCES `Monitors` (`Id`) ON DELETE CASCADE, `ZoneId` int(10) unsigned NOT NULL default '0', + FOREIGN KEY (`ZoneId`) REFERENCES `Zones` (`Id`) ON DELETE CASCADE, `EventId` BIGINT UNSIGNED NOT NULL, + FOREIGN KEY (`EventId`) REFERENCES `Events` (`Id`) ON DELETE CASCADE, `FrameId` int(10) unsigned NOT NULL default '0', `PixelDiff` tinyint(3) unsigned NOT NULL default '0', `AlarmPixels` int(10) unsigned NOT NULL default '0', @@ -704,6 +708,7 @@ DROP TABLE IF EXISTS `Zones`; CREATE TABLE `Zones` ( `Id` int(10) unsigned NOT NULL auto_increment, `MonitorId` int(10) unsigned NOT NULL default '0', + FOREIGN KEY (`MonitorId`) REFERENCES `Monitors` (`Id`) ON DELETE CASCADE, `Name` varchar(64) NOT NULL default '', `Type` enum('Active','Inclusive','Exclusive','Preclusive','Inactive','Privacy') NOT NULL default 'Active', `Units` enum('Pixels','Percent') NOT NULL default 'Pixels', From 59884375fa5df340daa1cb9dbf245111aadda7bc Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 28 Oct 2020 09:23:46 -0400 Subject: [PATCH 0523/2339] Add references permission so that our zmupdate can add foreign keys --- distros/beowulf/zoneminder.postinst | 4 ++-- distros/ubuntu1604/zoneminder.postinst | 2 +- distros/ubuntu2004/zoneminder.postinst | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/distros/beowulf/zoneminder.postinst b/distros/beowulf/zoneminder.postinst index 603786ff6..032595355 100644 --- a/distros/beowulf/zoneminder.postinst +++ b/distros/beowulf/zoneminder.postinst @@ -39,9 +39,9 @@ if [ "$1" = "configure" ]; then exit 1; fi # This creates the user. - echo "grant lock tables, alter,drop,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost identified by \"${ZM_DB_PASS}\";" | mysql --defaults-file=/etc/mysql/debian.cnf mysql + echo "grant lock tables, alter,drop,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute, REFERENCES 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,drop,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql + echo "grant lock tables, alter,drop,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute, REFERENCES on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql fi zmupdate.pl --nointeractive diff --git a/distros/ubuntu1604/zoneminder.postinst b/distros/ubuntu1604/zoneminder.postinst index 7b7af708b..d89ccf531 100644 --- a/distros/ubuntu1604/zoneminder.postinst +++ b/distros/ubuntu1604/zoneminder.postinst @@ -68,7 +68,7 @@ if [ "$1" = "configure" ]; then echo "CREATE USER '${ZM_DB_USER}'@localhost IDENTIFIED BY '${ZM_DB_PASS}';" | mysql --defaults-file=/etc/mysql/debian.cnf mysql fi echo "Updating permissions" - echo "grant lock tables,alter,drop,select,insert,update,delete,create,index,alter routine,create routine, trigger,execute on ${ZM_DB_NAME}.* to '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql + echo "GRANT LOCK TABLES,ALTER,DROP,SELECT,INSERT,UPDATE,DELETE,CREATE,INDEX,ALTER ROUTINE,CREATE ROUTINE, TRIGGER,EXECUTE,REFERENCES ON ${ZM_DB_NAME}.* TO '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql zmupdate.pl --nointeractive zmupdate.pl --nointeractive -f diff --git a/distros/ubuntu2004/zoneminder.postinst b/distros/ubuntu2004/zoneminder.postinst index a8b8eaf51..a50d7cf2e 100644 --- a/distros/ubuntu2004/zoneminder.postinst +++ b/distros/ubuntu2004/zoneminder.postinst @@ -26,7 +26,7 @@ create_update_user () { echo "CREATE USER '${ZM_DB_USER}'@${ZM_DB_HOST} IDENTIFIED BY '${ZM_DB_PASS}';" | mysql --defaults-file=/etc/mysql/debian.cnf mysql fi echo "Updating permissions" - echo "GRANT LOCK tables,alter,drop,select,insert,update,delete,create,index,alter routine,create routine,trigger,execute ON ${ZM_DB_NAME}.* TO '${ZM_DB_USER}'@${ZM_DB_HOST};" | mysql --defaults-file=/etc/mysql/debian.cnf mysql + echo "GRANT LOCK tables,alter,drop,select,insert,update,delete,create,index,alter routine,create routine,trigger,execute,REFERENCES ON ${ZM_DB_NAME}.* TO '${ZM_DB_USER}'@${ZM_DB_HOST};" | mysql --defaults-file=/etc/mysql/debian.cnf mysql } update_db () { From 43b7021f9cd3a0b719c721cb9f4c95e7827e55b6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 28 Oct 2020 12:38:44 -0400 Subject: [PATCH 0524/2339] ALTER Events.Id to BIGINT. This update got lost at somepoint. Add FOREIGN KEYS to Frames, Stats and Zones tables --- db/zm_update-1.35.11.sql | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 db/zm_update-1.35.11.sql diff --git a/db/zm_update-1.35.11.sql b/db/zm_update-1.35.11.sql new file mode 100644 index 000000000..e0257c184 --- /dev/null +++ b/db/zm_update-1.35.11.sql @@ -0,0 +1,22 @@ + +/* Change Id type to BIGINT. */ +ALTER TABLE Events MODIFY Id bigint unsigned NOT NULL auto_increment; + +/* Add FOREIGN KEYS After deleting lost records */ +DELETE FROM Frames WHERE EventId NOT IN (SELECT Id FROM Events); +ALTER TABLE Frames ADD FOREIGN KEY (EventId) REFERENCES Events (Id) ON DELETE CASCADE; + +/* Add FOREIGN KEYS After deleting lost records */ +DELETE FROM Stats WHERE EventId NOT IN (SELECT Id FROM Events); +ALTER TABLE Stats ADD FOREIGN KEY (EventId) REFERENCES Events (Id) ON DELETE CASCADE; + +DELETE FROM Stats WHERE MonitorId NOT IN (SELECT Id FROM Monitors); +ALTER TABLE Stats ADD FOREIGN KEY (`MonitorId`) REFERENCES `Monitors` (`Id`) ON DELETE CASCADE; + +DELETE FROM Stats WHERE ZoneId NOT IN (SELECT Id FROM Zones); +ALTER TABLE Stats ADD FOREIGN KEY (`ZoneId`) REFERENCES `Zones` (`Id`) ON DELETE CASCADE; + +/* Add FOREIGN KEYS After deleting lost records */ +DELETE FROM Zones WHERE MonitorId NOT IN (SELECT Id FROM Monitors); +ALTER TABLE Zones ADD FOREIGN KEY (`MonitorId`) REFERENCES `Monitors` (`Id`) ON DELETE CASCADE; + From 4c92c99ba17e3b4107c8d40230a69214e926dc26 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 28 Oct 2020 12:39:50 -0400 Subject: [PATCH 0525/2339] bump version for 1.35.11 db updates --- distros/redhat/zoneminder.spec | 2 +- version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index 5c19dd0c0..3a4d45de8 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -28,7 +28,7 @@ %global _hardened_build 1 Name: zoneminder -Version: 1.35.10 +Version: 1.35.11 Release: 1%{?dist} Summary: A camera monitoring and analysis tool Group: System Environment/Daemons diff --git a/version b/version index a0b71b46f..5f1e3b58b 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.35.10 +1.35.11 From b3a28b2ba20b858eea71be965bbdeae8662a3cb8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 28 Oct 2020 12:49:03 -0400 Subject: [PATCH 0526/2339] fix confusion in syslog reporting web_php when the error was actually web_js --- web/includes/logger.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/includes/logger.php b/web/includes/logger.php index fb7d58f93..ab59b412b 100644 --- a/web/includes/logger.php +++ b/web/includes/logger.php @@ -408,10 +408,10 @@ class Logger { } } - $message = $code.' ['.$string.']'; if ( $level <= $this->syslogLevel ) - syslog( self::$syslogPriorities[$level], $message ); + syslog(self::$syslogPriorities[$level], $message); + $message = $code.' ['.$string.']'; if ( $level <= $this->databaseLevel ) { try { global $dbConn; From 686f793d097973c15f62d89a670c9cf2fb1d648c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 28 Oct 2020 12:49:39 -0400 Subject: [PATCH 0527/2339] fix truth value for ZM_OPT_USE_GEOLOCATION --- web/skins/classic/views/js/monitor.js.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/monitor.js.php b/web/skins/classic/views/js/monitor.js.php index cc61270d0..bdcc17554 100644 --- a/web/skins/classic/views/js/monitor.js.php +++ b/web/skins/classic/views/js/monitor.js.php @@ -1,4 +1,4 @@ -var ZM_OPT_USE_GEOLOCATION = ''; +var ZM_OPT_USE_GEOLOCATION = '' == '1' ? true : false; Date: Wed, 28 Oct 2020 12:55:32 -0400 Subject: [PATCH 0528/2339] Add Locking to filters, bump db to 1.35.12. --- db/zm_update-1.35.12.sql | 18 ++++++++++++++++++ distros/redhat/zoneminder.spec | 2 +- version | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 db/zm_update-1.35.12.sql diff --git a/db/zm_update-1.35.12.sql b/db/zm_update-1.35.12.sql new file mode 100644 index 000000000..b8c54f713 --- /dev/null +++ b/db/zm_update-1.35.12.sql @@ -0,0 +1,18 @@ +-- +-- Update Filters table to have a LockRows Column +-- + +SELECT 'Checking for LockRows in Filters'; +SET @s = (SELECT IF( + (SELECT COUNT(*) + FROM INFORMATION_SCHEMA.COLUMNS + WHERE table_name = 'Filters' + AND table_schema = DATABASE() + AND column_name = 'LockRows' + ) > 0, +"SELECT 'Column LockRows already exists in Filters'", +"ALTER TABLE Filters ADD COLUMN `LockRows` tinyint(1) unsigned NOT NULL default '0' AFTER `Concurrent`" +)); + +PREPARE stmt FROM @s; +EXECUTE stmt; diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index 3a4d45de8..eefba559d 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -28,7 +28,7 @@ %global _hardened_build 1 Name: zoneminder -Version: 1.35.11 +Version: 1.35.12 Release: 1%{?dist} Summary: A camera monitoring and analysis tool Group: System Environment/Daemons diff --git a/version b/version index 5f1e3b58b..7d872edd4 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.35.11 +1.35.12 From 9a9f80c15c00a050b991355d9edaf85abcfcae4d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 28 Oct 2020 14:07:29 -0400 Subject: [PATCH 0529/2339] show which user we are updating permissions for --- distros/ubuntu1604/zoneminder.postinst | 2 +- distros/ubuntu2004/zoneminder.postinst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/distros/ubuntu1604/zoneminder.postinst b/distros/ubuntu1604/zoneminder.postinst index d89ccf531..d4010008a 100644 --- a/distros/ubuntu1604/zoneminder.postinst +++ b/distros/ubuntu1604/zoneminder.postinst @@ -67,7 +67,7 @@ if [ "$1" = "configure" ]; then # This creates the user. echo "CREATE USER '${ZM_DB_USER}'@localhost IDENTIFIED BY '${ZM_DB_PASS}';" | mysql --defaults-file=/etc/mysql/debian.cnf mysql fi - echo "Updating permissions" + echo "Updating permissions for user ${ZM_DB_USER}@localhost" echo "GRANT LOCK TABLES,ALTER,DROP,SELECT,INSERT,UPDATE,DELETE,CREATE,INDEX,ALTER ROUTINE,CREATE ROUTINE, TRIGGER,EXECUTE,REFERENCES ON ${ZM_DB_NAME}.* TO '${ZM_DB_USER}'@localhost;" | mysql --defaults-file=/etc/mysql/debian.cnf mysql zmupdate.pl --nointeractive diff --git a/distros/ubuntu2004/zoneminder.postinst b/distros/ubuntu2004/zoneminder.postinst index a50d7cf2e..cd147a0e2 100644 --- a/distros/ubuntu2004/zoneminder.postinst +++ b/distros/ubuntu2004/zoneminder.postinst @@ -25,7 +25,7 @@ create_update_user () { # This creates the user. echo "CREATE USER '${ZM_DB_USER}'@${ZM_DB_HOST} IDENTIFIED BY '${ZM_DB_PASS}';" | mysql --defaults-file=/etc/mysql/debian.cnf mysql fi - echo "Updating permissions" + echo "Updating permissions for user ${ZM_DB_USER}@${ZM_DB_HOST}" echo "GRANT LOCK tables,alter,drop,select,insert,update,delete,create,index,alter routine,create routine,trigger,execute,REFERENCES ON ${ZM_DB_NAME}.* TO '${ZM_DB_USER}'@${ZM_DB_HOST};" | mysql --defaults-file=/etc/mysql/debian.cnf mysql } From a35c143094aabc0f515281bf47e0137913bcdd02 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 28 Oct 2020 15:01:14 -0400 Subject: [PATCH 0530/2339] Prevent extra foreign keys from being created and fix we can't delete from Zones. Must be done manually --- db/zm_update-1.35.11.sql | 78 +++++++++++++++++++++++++++++++++------- 1 file changed, 66 insertions(+), 12 deletions(-) diff --git a/db/zm_update-1.35.11.sql b/db/zm_update-1.35.11.sql index c1e9aad64..0b51f2ef5 100644 --- a/db/zm_update-1.35.11.sql +++ b/db/zm_update-1.35.11.sql @@ -1,20 +1,74 @@ /* Change Id type to BIGINT. */ +SELECT 'Updating Events.Id to BIGINT'; ALTER TABLE Events MODIFY Id bigint unsigned NOT NULL auto_increment; /* Add FOREIGN KEYS After deleting lost records */ -DELETE FROM Frames WHERE EventId NOT IN (SELECT Id FROM Events); -ALTER TABLE Frames ADD FOREIGN KEY (EventId) REFERENCES Events (Id) ON DELETE CASCADE; +SELECT 'Adding foreign key for EventId to Frames'; +set @exist := (select count(*) FROM information_schema.key_column_usage where table_name='Frames' and column_name='EventId' and referenced_table_name='Events' and referenced_column_name='Id'); +set @sqlstmt := if( @exist > 1, "SELECT 'You have more than 1 FOREIGN KEY. Please do manual cleanup'", "SELECT 'Ok'"); +PREPARE stmt FROM @sqlstmt; +EXECUTE stmt; -/* Add FOREIGN KEYS After deleting lost records */ -DELETE FROM Stats WHERE EventId NOT IN (SELECT Id FROM Events); -ALTER TABLE Stats ADD FOREIGN KEY (EventId) REFERENCES Events (Id) ON DELETE CASCADE; +set @sqlstmt := if( @exist > 0, "SELECT 'FOREIGN KEY for EventId in Frames already exists'", "DELETE FROM Frames WHERE EventId NOT IN (SELECT Id FROM Events)"); +PREPARE stmt FROM @sqlstmt; +EXECUTE stmt; -DELETE FROM Stats WHERE MonitorId NOT IN (SELECT Id FROM Monitors); -ALTER TABLE Stats ADD FOREIGN KEY (`MonitorId`) REFERENCES `Monitors` (`Id`) ON DELETE CASCADE; +set @sqlstmt := if( @exist > 0, "SELECT 'Ok'", "ALTER TABLE Frames ADD FOREIGN KEY (EventId) REFERENCES Events (Id) ON DELETE CASCADE"); +PREPARE stmt FROM @sqlstmt; +EXECUTE stmt; -DELETE FROM Stats WHERE ZoneId NOT IN (SELECT Id FROM Zones); -ALTER TABLE Stats ADD FOREIGN KEY (`ZoneId`) REFERENCES `Zones` (`Id`) ON DELETE CASCADE; -/* Add FOREIGN KEYS After deleting lost records */ -DELETE FROM Zones WHERE MonitorId NOT IN (SELECT Id FROM Monitors); -ALTER TABLE Zones ADD FOREIGN KEY (`MonitorId`) REFERENCES `Monitors` (`Id`) ON DELETE CASCADE; +SELECT 'Adding foreign key for EventId to Stats'; +set @exist := (select count(*) FROM information_schema.key_column_usage where table_name='Stats' and column_name='EventId' and referenced_table_name='Events' and referenced_column_name='Id'); +set @sqlstmt := if( @exist > 1, "SELECT 'You have more than 1 FOREIGN KEY. Please do manual cleanup'", "SELECT 'Ok'"); +PREPARE stmt FROM @sqlstmt; +EXECUTE stmt; + +set @sqlstmt := if( @exist > 0, "SELECT 'FOREIGN KEY for EventId in Stats already exists'", "DELETE FROM Stats WHERE EventId NOT IN (SELECT Id FROM Events);"); +PREPARE stmt FROM @sqlstmt; +EXECUTE stmt; + +set @sqlstmt := if( @exist > 0, "SELECT 'Ok'", "ALTER TABLE Stats ADD FOREIGN KEY (EventId) REFERENCES Events (Id) ON DELETE CASCADE"); +PREPARE stmt FROM @sqlstmt; +EXECUTE stmt; + + +SELECT 'Adding foreign key for MonitorId to Stats'; +set @exist := (select count(*) FROM information_schema.key_column_usage where table_name='Stats' and column_name='MonitorId' and referenced_table_name='Monitors' and referenced_column_name='Id'); +set @sqlstmt := if( @exist > 1, "SELECT 'You have more than 1 FOREIGN KEY. Please do manual cleanup'", "SELECT 'Ok'"); +PREPARE stmt FROM @sqlstmt; +EXECUTE stmt; + +set @sqlstmt := if( @exist > 0, "SELECT 'FOREIGN KEY for MonitorId in Stats already exists'", "DELETE FROM Stats WHERE MonitorId NOT IN (SELECT Id FROM Monitors);"); +PREPARE stmt FROM @sqlstmt; +EXECUTE stmt; + +set @sqlstmt := if( @exist > 0, "SELECT 'Ok'", "ALTER TABLE Stats ADD FOREIGN KEY (MonitorId) REFERENCES Monitors (Id) ON DELETE CASCADE"); +PREPARE stmt FROM @sqlstmt; +EXECUTE stmt; + +SELECT 'Adding foreign key for ZoneId to Stats'; +set @exist := (select count(*) FROM information_schema.key_column_usage where table_name='Stats' and column_name='ZoneId' and referenced_table_name='Zones' and referenced_column_name='Id'); +set @sqlstmt := if( @exist > 1, "SELECT 'You have more than 1 FOREIGN KEY. Please do manual cleanup'", "SELECT 'Ok'"); +PREPARE stmt FROM @sqlstmt; +EXECUTE stmt; + +set @sqlstmt := if( @exist > 0, "SELECT 'FOREIGN KEY for ZoneId in Stats already exists'", "DELETE FROM Stats WHERE ZoneId NOT IN (SELECT Id FROM Zones);"); +PREPARE stmt FROM @sqlstmt; +EXECUTE stmt; + +set @sqlstmt := if( @exist > 0, "SELECT 'Ok'", "ALTER TABLE Stats ADD FOREIGN KEY (ZoneId) REFERENCES Zones (Id) ON DELETE CASCADE"); +PREPARE stmt FROM @sqlstmt; +EXECUTE stmt; + +SELECT 'Adding foreign key for MonitorId to Zones'; +set @exist := (select count(*) FROM information_schema.key_column_usage where table_name='Zones' and column_name='MonitorId' and referenced_table_name='Monitors' and referenced_column_name='Id'); +set @sqlstmt := if( @exist > 1, "SELECT 'You have more than 1 FOREIGN KEY. Please do manual cleanup'", "SELECT 'Ok'"); +PREPARE stmt FROM @sqlstmt; +EXECUTE stmt; + +set @sqlstmt := if( @exist > 0, "SELECT 'FOREIGN KEY for MonitorId in Zones already exists'", "SELECT 'FOREIGN KEY for MonitorId in Zones does not already exist'"); +set @badzones := (select count(*) FROM Zones WHERE MonitorId NOT IN (SELECT Id FROM Monitors)); +set @sqlstmt := if ( @badzones > 0, "SELECT 'You have Zones with no Monitor record in the Monitors table. Please delete them manually'", "ALTER TABLE Zones ADD FOREIGN KEY (MonitorId) REFERENCES Monitors (Id)"); +PREPARE stmt FROM @sqlstmt; +EXECUTE stmt; From 638a05b2079a5787858f67ee7fb686cab0dc7901 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 29 Oct 2020 09:39:48 -0400 Subject: [PATCH 0531/2339] Fix totalrows in pagination. Still figuring this out. --- web/ajax/events.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/web/ajax/events.php b/web/ajax/events.php index 850628109..d5eb80d24 100644 --- a/web/ajax/events.php +++ b/web/ajax/events.php @@ -155,11 +155,9 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim foreach ( $advsearch as $col=>$text ) { if ( in_array($col, $columns) ) { - //$text = '%' .$text. '%'; array_push($likes, 'E.'.$col.' LIKE ?'); array_push($query['values'], $text); } else if ( in_array($col, $col_alt) ) { - //$text = '%' .$text. '%'; array_push($likes, 'M.'.$col.' LIKE ?'); array_push($query['values'], $text); } else { @@ -198,7 +196,6 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim $rows = array(); foreach ( dbFetchAll($query['sql'], NULL, $query['values']) as $row ) { - ZM\Debug("row".print_r($row,true)); $event = new ZM\Event($row); if ( !$filter->test_post_sql_conditions($event) ) { $event->remove_from_cache(); @@ -207,7 +204,7 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim $scale = intval(5*100*ZM_WEB_LIST_THUMB_WIDTH / $event->Width()); $imgSrc = $event->getThumbnailSrc(array(),'&'); $streamSrc = $event->getStreamSrc(array( - 'mode'=>'jpeg', 'scale'=>$scale, 'maxfps'=>ZM_WEB_VIDEO_MAXFPS, 'replay'=>'single', 'rate'=>'400'), '&'); + 'mode'=>'jpeg', 'scale'=>$scale, 'maxfps'=>ZM_WEB_VIDEO_MAXFPS, 'replay'=>'single', 'rate'=>'400'), '&'); // Modify the row data as needed $row['imgHtml'] = '' .validHtmlStr('Event ' .$event->Id()). ''; @@ -225,8 +222,9 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim } $data['rows'] = $rows; - $data['totalNotFiltered'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table. ' AS E'. ($filter->sql() ? ' WHERE '.$filter->sql():''), 'Total'); - $data['total'] = count($rows); + # total has to be the # of available rows. Not sure what totalNotFiltered is actually used for yet. + $data['totalNotFiltered'] = $data['total'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table. ' AS E'. ($filter->sql() ? ' WHERE '.$filter->sql():''), 'Total'); + #$data['total'] = count($rows); return $data; } ?> From 97f4d9e7a2edbbb54602c8da5ab3e2ea45535137 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 29 Oct 2020 09:40:14 -0400 Subject: [PATCH 0532/2339] Make the event count and diskspace in the storage row be a link to events for that storage area. --- web/skins/classic/views/options.php | 31 +++++++++++++++++------------ 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/web/skins/classic/views/options.php b/web/skins/classic/views/options.php index cc8b0b568..a52aca15d 100644 --- a/web/skins/classic/views/options.php +++ b/web/skins/classic/views/options.php @@ -279,17 +279,23 @@ foreach ( array_map('basename', glob('skins/'.$skin.'/css/*', GLOB_ONLYDIR)) as 'lower(Name)') ) as $Storage ) { + $filter = new ZM\Filter(); + $filter->addTerm(array('attr'=>'StorageId','op'=>'=','val'=>$Storage->Id())); + if ( $user['MonitorIds'] ) { + $filter = $filter->addTerm(array('cnj'=>'and', 'attr'=>'MonitorId', 'op'=>'IN', 'val'=>$user['MonitorIds'])); + } + $str_opt = 'class="storageCol" data-sid="'.$Storage->Id().'"'; ?> - Id()), $canEdit, $str_opt ) ?> - Name()), $canEdit, $str_opt ) ?> - Path()), $canEdit, $str_opt ) ?> - Type()), $canEdit, $str_opt ) ?> - Scheme()), $canEdit, $str_opt ) ?> - Server()->Name()), $canEdit, $str_opt ) ?> + Id()), $canEdit, $str_opt) ?> + Name()), $canEdit, $str_opt) ?> + Path()), $canEdit, $str_opt) ?> + Type()), $canEdit, $str_opt) ?> + Scheme()), $canEdit, $str_opt) ?> + Server()->Name()), $canEdit, $str_opt) ?> disk_used_space()) . ' of ' . human_filesize($Storage->disk_total_space()) ?> - EventCount().' using '.human_filesize($Storage->event_disk_space()) ?> + querystring(), $Storage->EventCount().' using '.human_filesize($Storage->event_disk_space()) ); ?> EventCount() or !$canEdit ) { ?> disabled="disabled"EventCount() ? ' title="Can\'t delete as long as there are events stored here."' : ''?>/> @@ -302,13 +308,12 @@ foreach ( array_map('basename', glob('skins/'.$skin.'/css/*', GLOB_ONLYDIR)) as APIs are disabled. To enable, please turn on OPT_USE_API in Options->System
"; - } - else { + $apiEnabled = dbFetchOne('SELECT Value FROM Config WHERE Name=\'ZM_OPT_USE_API\''); + if ( $apiEnabled['Value'] != '1' ) { + echo '
APIs are disabled. To enable, please turn on OPT_USE_API in Options->System
'; + } else { ?>
From 41e88fad6eb79761429c9971860a2883c7ebc250 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 29 Oct 2020 15:08:14 -0400 Subject: [PATCH 0533/2339] translate \n to
. Fixes #3064 --- web/ajax/events.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/ajax/events.php b/web/ajax/events.php index d5eb80d24..200416f92 100644 --- a/web/ajax/events.php +++ b/web/ajax/events.php @@ -216,7 +216,7 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim $row['EndTime'] = strftime(STRF_FMT_DATETIME_SHORTER, strtotime($row['EndTime'])); $row['Length'] = gmdate('H:i:s', $row['Length'] ); $row['Storage'] = ( $row['StorageId'] and isset($StorageById[$row['StorageId']]) ) ? $StorageById[$row['StorageId']]->Name() : 'Default'; - $row['Notes'] = htmlspecialchars($row['Notes']); + $row['Notes'] = nl2br(htmlspecialchars($row['Notes'])); $row['DiskSpace'] = human_filesize($event->DiskSpace()); $rows[] = $row; } From e4a585eaa328ad85c108efc1bcc8fb9714f7c1a6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 30 Oct 2020 09:18:53 -0400 Subject: [PATCH 0534/2339] improvements to 1.35.11 db updates --- db/zm_update-1.35.11.sql | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/db/zm_update-1.35.11.sql b/db/zm_update-1.35.11.sql index 0b51f2ef5..3906d8c04 100644 --- a/db/zm_update-1.35.11.sql +++ b/db/zm_update-1.35.11.sql @@ -1,19 +1,26 @@ /* Change Id type to BIGINT. */ -SELECT 'Updating Events.Id to BIGINT'; -ALTER TABLE Events MODIFY Id bigint unsigned NOT NULL auto_increment; +set @exist := (SELECT count(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = 'Events' AND COLUMN_NAME = 'Id' and DATA_TYPE='bigint'); + +set @sqlstmt := if( @exist = 0, "ALTER TABLE Events MODIFY Id bigint unsigned NOT NULL auto_increment", "SELECT 'Ok'"); +PREPARE stmt FROM @sqlstmt; +EXECUTE stmt; /* Add FOREIGN KEYS After deleting lost records */ -SELECT 'Adding foreign key for EventId to Frames'; set @exist := (select count(*) FROM information_schema.key_column_usage where table_name='Frames' and column_name='EventId' and referenced_table_name='Events' and referenced_column_name='Id'); + set @sqlstmt := if( @exist > 1, "SELECT 'You have more than 1 FOREIGN KEY. Please do manual cleanup'", "SELECT 'Ok'"); +set @sqlstmt := if( @exist = 1, "SELECT 'FOREIGN KEY EventId in Frames already exists'", @sqlstmt); +set @sqlstmt := if( @exist = 0, "SELECT 'Adding foreign key for EventId to Frames", @sqlstmt); PREPARE stmt FROM @sqlstmt; EXECUTE stmt; -set @sqlstmt := if( @exist > 0, "SELECT 'FOREIGN KEY for EventId in Frames already exists'", "DELETE FROM Frames WHERE EventId NOT IN (SELECT Id FROM Events)"); +set @sqlstmt := if( @exist != 0, "SELECT '.'", "SELECT 'Deleting unlinked Frames'"); PREPARE stmt FROM @sqlstmt; EXECUTE stmt; - -set @sqlstmt := if( @exist > 0, "SELECT 'Ok'", "ALTER TABLE Frames ADD FOREIGN KEY (EventId) REFERENCES Events (Id) ON DELETE CASCADE"); +set @sqlstmt := if( @exist != 0, "SELECT '.'", "DELETE FROM Frames WHERE EventId NOT IN (SELECT Id FROM Events)"); +PREPARE stmt FROM @sqlstmt; +EXECUTE stmt; +set @sqlstmt := if( @exist != 0, "SELECT 'Ok'", "ALTER TABLE Frames ADD FOREIGN KEY (EventId) REFERENCES Events (Id) ON DELETE CASCADE"); PREPARE stmt FROM @sqlstmt; EXECUTE stmt; @@ -21,6 +28,8 @@ EXECUTE stmt; SELECT 'Adding foreign key for EventId to Stats'; set @exist := (select count(*) FROM information_schema.key_column_usage where table_name='Stats' and column_name='EventId' and referenced_table_name='Events' and referenced_column_name='Id'); set @sqlstmt := if( @exist > 1, "SELECT 'You have more than 1 FOREIGN KEY. Please do manual cleanup'", "SELECT 'Ok'"); +set @sqlstmt := if( @exist = 1, "SELECT 'FOREIGN KEY already EventId in Stats already exists'", @sqlstmt); +set @sqlstmt := if( @exist = 0, "SELECT 'Adding FOREIGN KEY for EventId to Stats'", @sqlstmt); PREPARE stmt FROM @sqlstmt; EXECUTE stmt; From 65df84ef7efe0bad794ad5cdc99145da4a901f48 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 30 Oct 2020 11:49:00 -0400 Subject: [PATCH 0535/2339] Make ZoneMinder::Event::delete aware of transactions --- scripts/ZoneMinder/lib/ZoneMinder/Event.pm | 24 ++++++++++++++-------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm index 0af41b2ca..985ac71f3 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm @@ -349,6 +349,10 @@ sub GenerateVideo { return; } # end sub GenerateVideo +# Note about transactions, this function may be called with rows locked and hence in a transaction. +# So we will detect if we are in a transaction, and if not, start one. We will NOT do rollback or +# commits unless we started the transaction. + sub delete { my $event = $_[0]; @@ -378,23 +382,25 @@ sub delete { Info("Deleting event $event->{Id} from Monitor $event->{MonitorId} StartTime:$event->{StartTime} from ".$event->Path()); $ZoneMinder::Database::dbh->ping(); - $ZoneMinder::Database::dbh->begin_work(); - #$event->lock_and_load(); + my $in_transaction = $ZoneMinder::Database::dbh->{AutoCommit} ? 0 : 1; - ZoneMinder::Database::zmDbDo('DELETE FROM Frames WHERE EventId=?', $$event{Id}); - if ( $ZoneMinder::Database::dbh->errstr() ) { - $ZoneMinder::Database::dbh->commit(); - return; - } + $ZoneMinder::Database::dbh->begin_work() if ! $in_transaction; + + # Going to delete in order of least value to greatest value. Stats is least and references Frames ZoneMinder::Database::zmDbDo('DELETE FROM Stats WHERE EventId=?', $$event{Id}); if ( $ZoneMinder::Database::dbh->errstr() ) { - $ZoneMinder::Database::dbh->commit(); + $ZoneMinder::Database::dbh->commit() if ! $in_transaction; + return; + } + ZoneMinder::Database::zmDbDo('DELETE FROM Frames WHERE EventId=?', $$event{Id}); + if ( $ZoneMinder::Database::dbh->errstr() ) { + $ZoneMinder::Database::dbh->commit() if ! $in_transaction; return; } # Do it individually to avoid locking up the table for new events ZoneMinder::Database::zmDbDo('DELETE FROM Events WHERE Id=?', $$event{Id}); - $ZoneMinder::Database::dbh->commit(); + $ZoneMinder::Database::dbh->commit() if ! $in_transaction; } if ( ( $in_zmaudit or (!$Config{ZM_OPT_FAST_DELETE})) and $event->Storage()->DoDelete() ) { From 5fadd366e7f00596835c020c1f09a62a2ee7cfe9 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 30 Oct 2020 11:50:03 -0400 Subject: [PATCH 0536/2339] Always setup Logging SIG handlers. Implement SIGUSR1 and SIGUSR2 handling to match c++ side behaviour. Fixes #3057 --- scripts/ZoneMinder/lib/ZoneMinder/Logger.pm | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm index 801dcf199..cf5a0b508 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm @@ -504,9 +504,9 @@ sub openFile { $LOGFILE->autoflush() if $this->{autoFlush}; my $webUid = (getpwnam($ZoneMinder::Config::Config{ZM_WEB_USER}))[2]; - Error("Can't get uid for $ZoneMinder::Config::Config{ZM_WEB_USER}") if ! defined $webUid; + Error('Can\'t get uid for '.$ZoneMinder::Config::Config{ZM_WEB_USER}) if ! defined $webUid; my $webGid = (getgrnam($ZoneMinder::Config::Config{ZM_WEB_GROUP}))[2]; - Error("Can't get gid for $ZoneMinder::Config::Config{ZM_WEB_USER}") if ! defined $webGid; + Error('Can\'t get gid for '.$ZoneMinder::Config::Config{ZM_WEB_USER}) if ! defined $webGid; if ( $> == 0 ) { # If we are root, we want to make sure that www-data or whatever owns the file chown($webUid, $webGid, $this->{logFile} ) or @@ -610,6 +610,7 @@ sub logInit( ;@ ) { my %options = @_ ? @_ : (); $logger = ZoneMinder::Logger->new() if !$logger; $logger->initialise(%options); + logSetSignal(); } sub logReinit { @@ -626,12 +627,26 @@ sub logHupHandler { $do_log_rotate = 1; } +sub logUSR1Handler { + $logger->level($logger->level()+1); + Info('Logger - Level changed to '. $logger->level() . '=>'.$codes{$logger->level()}); +} + +sub logUSR2Handler { + $logger->level($logger->level()-1); + Info('Logger - Level changed to '. $logger->level() . '=>'.$codes{$logger->level()}); +} + sub logSetSignal { $SIG{HUP} = \&logHupHandler; + $SIG{USR1} = \&logUSR1Handler; + $SIG{USR2} = \&logUSR2Handler; } sub logClearSignal { $SIG{HUP} = 'DEFAULT'; + $SIG{USR1} = 'DEFAULT'; + $SIG{USR2} = 'DEFAULT'; } sub logLevel { From e5097d9466150334476f55d2e3517609dd526c40 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 30 Oct 2020 11:50:16 -0400 Subject: [PATCH 0537/2339] code style --- src/zm_signal.cpp | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/src/zm_signal.cpp b/src/zm_signal.cpp index 81012c07e..2756802a3 100644 --- a/src/zm_signal.cpp +++ b/src/zm_signal.cpp @@ -29,15 +29,13 @@ bool zm_reload = false; bool zm_terminate = false; -RETSIGTYPE zm_hup_handler(int signal) -{ +RETSIGTYPE zm_hup_handler(int signal) { // Shouldn't do complex things in signal handlers, logging is complex and can block due to mutexes. //Info("Got signal %d (%s), reloading", signal, strsignal(signal)); zm_reload = true; } -RETSIGTYPE zm_term_handler(int signal) -{ +RETSIGTYPE zm_term_handler(int signal) { // Shouldn't do complex things in signal handlers, logging is complex and can block due to mutexes. //Info("Got signal %d (%s), exiting", signal, strsignal(signal)); zm_terminate = true; @@ -55,8 +53,7 @@ RETSIGTYPE zm_die_handler(int signal) #if ( HAVE_SIGINFO_T && HAVE_UCONTEXT_T ) void *ip = nullptr; void *cr2 = nullptr; - if (info && context) { - + if ( info && context ) { Debug(1, "Signal information: number %d code %d errno %d pid %d uid %d status %d", signal, info->si_code, info->si_errno, info->si_pid, @@ -79,7 +76,7 @@ RETSIGTYPE zm_die_handler(int signal) #endif // defined(__x86_64__) // Print the signal address and instruction pointer if available - if (ip) { + if ( ip ) { Error("Signal address is %p, from %p", cr2, ip); } else { Error("Signal address is %p, no instruction pointer", cr2); @@ -115,8 +112,7 @@ RETSIGTYPE zm_die_handler(int signal) exit(signal); } -void zmSetHupHandler(SigHandler * handler) -{ +void zmSetHupHandler(SigHandler * handler) { sigset_t block_set; sigemptyset(&block_set); struct sigaction action, old_action; @@ -127,8 +123,7 @@ void zmSetHupHandler(SigHandler * handler) sigaction(SIGHUP, &action, &old_action); } -void zmSetTermHandler(SigHandler * handler) -{ +void zmSetTermHandler(SigHandler * handler) { sigset_t block_set; sigemptyset(&block_set); struct sigaction action, old_action; @@ -141,8 +136,7 @@ void zmSetTermHandler(SigHandler * handler) sigaction(SIGQUIT, &action, &old_action); } -void zmSetDieHandler(SigHandler * handler) -{ +void zmSetDieHandler(SigHandler * handler) { sigset_t block_set; sigemptyset(&block_set); struct sigaction action, old_action; @@ -163,19 +157,16 @@ void zmSetDieHandler(SigHandler * handler) sigaction(SIGFPE, &action, &old_action); } -void zmSetDefaultHupHandler() -{ +void zmSetDefaultHupHandler() { zmSetHupHandler((SigHandler *) zm_hup_handler); } -void zmSetDefaultTermHandler() -{ +void zmSetDefaultTermHandler() { zmSetTermHandler((SigHandler *) zm_term_handler); } -void zmSetDefaultDieHandler() -{ - if (config.dump_cores) { +void zmSetDefaultDieHandler() { + if ( config.dump_cores ) { // Do nothing } else { zmSetDieHandler((SigHandler *) zm_die_handler); From f7d23ce23bc4523d1a7d3658e124243e42379729 Mon Sep 17 00:00:00 2001 From: jahegu Date: Fri, 30 Oct 2020 17:57:28 +0100 Subject: [PATCH 0538/2339] Update zm_update-1.35.11.sql Missing " ' " simbol that generates a MariaDB problem: ERROR 1064 (42000) at line 14: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''Adding foreign key for EventId to Frames' at line 1 --- db/zm_update-1.35.11.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/zm_update-1.35.11.sql b/db/zm_update-1.35.11.sql index 3906d8c04..ad73b7bf4 100644 --- a/db/zm_update-1.35.11.sql +++ b/db/zm_update-1.35.11.sql @@ -10,7 +10,7 @@ set @exist := (select count(*) FROM information_schema.key_column_usage where ta set @sqlstmt := if( @exist > 1, "SELECT 'You have more than 1 FOREIGN KEY. Please do manual cleanup'", "SELECT 'Ok'"); set @sqlstmt := if( @exist = 1, "SELECT 'FOREIGN KEY EventId in Frames already exists'", @sqlstmt); -set @sqlstmt := if( @exist = 0, "SELECT 'Adding foreign key for EventId to Frames", @sqlstmt); +set @sqlstmt := if( @exist = 0, "SELECT 'Adding foreign key for EventId to Frames'", @sqlstmt); PREPARE stmt FROM @sqlstmt; EXECUTE stmt; From a63600ccefdec8652ec213c3e2b85aea7fedbd04 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 30 Oct 2020 16:09:24 -0400 Subject: [PATCH 0539/2339] remove dead code --- src/zm_logger.cpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/zm_logger.cpp b/src/zm_logger.cpp index 29361b5a9..006eacbf4 100644 --- a/src/zm_logger.cpp +++ b/src/zm_logger.cpp @@ -43,18 +43,6 @@ Logger *Logger::smInstance = nullptr; Logger::StringMap Logger::smCodes; Logger::IntMap Logger::smSyslogPriorities; -#if 0 -static void subtractTime( struct timeval * const tp1, struct timeval * const tp2 ) { - tp1->tv_sec -= tp2->tv_sec; - if ( tp1->tv_usec <= tp2->tv_usec ) { - tp1->tv_sec--; - tp1->tv_usec = 1000000 - (tp2->tv_usec - tp1->tv_usec); - } else { - tp1->tv_usec = tp1->tv_usec - tp2->tv_usec; - } -} -#endif - void Logger::usrHandler(int sig) { Logger *logger = fetch(); if ( sig == SIGUSR1 ) From 5047c28157fef1581609acd74f2af0db4cebf9dd Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 31 Oct 2020 11:26:29 -0500 Subject: [PATCH 0540/2339] attempt to fix totalnotfiltered --- web/ajax/events.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/web/ajax/events.php b/web/ajax/events.php index 200416f92..1f8e71f1a 100644 --- a/web/ajax/events.php +++ b/web/ajax/events.php @@ -222,9 +222,14 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim } $data['rows'] = $rows; - # total has to be the # of available rows. Not sure what totalNotFiltered is actually used for yet. - $data['totalNotFiltered'] = $data['total'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table. ' AS E'. ($filter->sql() ? ' WHERE '.$filter->sql():''), 'Total'); - #$data['total'] = count($rows); + # totalNotFiltered must equal total, except when either search bar has been used + $data['totalNotFiltered'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table. ' AS E'. ($filter->sql() ? ' WHERE '.$filter->sql():''), 'Total'); + if ( $search != '' || count($advsearch) ) { + $data['total'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table. ' AS E'.$where , 'Total', $wherevalues); + } else { + $data['total'] = $data['totalNotFiltered']; + } + return $data; } ?> From 30e0e49ee73423742dfe49dcf0cec3611dc5bf0b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 31 Oct 2020 14:09:47 -0400 Subject: [PATCH 0541/2339] Fix total rows when using search --- web/ajax/events.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/web/ajax/events.php b/web/ajax/events.php index 200416f92..c8008e8a2 100644 --- a/web/ajax/events.php +++ b/web/ajax/events.php @@ -181,6 +181,9 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim if ( $where ) $where = ' WHERE '.$where; + # total has to be the # of available rows. Not sure what totalNotFiltered is actually used for yet. + $data['totalNotFiltered'] = $data['total'] = dbFetchOne('SELECT count(*) AS Total FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id'. $where, 'Total', $query['values']); + $sort = $sort == 'Monitor' ? 'M.Name' : 'E.'.$sort; $col_str = 'E.*, M.Name AS Monitor'; $query['sql'] = 'SELECT ' .$col_str. ' FROM `' .$table. '` AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id'.$where.' ORDER BY ' .$sort. ' ' .$order. ' LIMIT ?, ?'; @@ -195,6 +198,10 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim } $rows = array(); + $results = dbFetchAll($query['sql'], NULL, $query['values']); + if ( ! $results ) { + return $data; + } foreach ( dbFetchAll($query['sql'], NULL, $query['values']) as $row ) { $event = new ZM\Event($row); if ( !$filter->test_post_sql_conditions($event) ) { @@ -222,8 +229,6 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim } $data['rows'] = $rows; - # total has to be the # of available rows. Not sure what totalNotFiltered is actually used for yet. - $data['totalNotFiltered'] = $data['total'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table. ' AS E'. ($filter->sql() ? ' WHERE '.$filter->sql():''), 'Total'); #$data['total'] = count($rows); return $data; } From 824f38c74671f0fe3bf9d3ec102c13003b39484e Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sun, 1 Nov 2020 08:05:53 -0600 Subject: [PATCH 0542/2339] hide settings buttons rather than disable for non Local monitors --- web/skins/classic/views/js/watch.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/watch.js b/web/skins/classic/views/js/watch.js index 176c85822..23629514e 100644 --- a/web/skins/classic/views/js/watch.js +++ b/web/skins/classic/views/js/watch.js @@ -946,7 +946,8 @@ function initPage() { }); // Only enable the settings button for local cameras - settingsBtn.prop('disabled', !(monitorType == 'Local' && canViewControl)); + settingsBtn.prop('disabled', !canViewControl); + if ( monitorType != 'Local' ) settingsBtn.hide(); } // initPage // Kick everything off From 1257a7ea374c81a78bbeda13e2db6c1e2d7d5e20 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 1 Nov 2020 16:11:19 -0500 Subject: [PATCH 0543/2339] improvements reported by cppcheck --- src/zm_comms.h | 6 +++--- src/zm_config.h | 5 +++-- src/zm_coord.h | 12 ++++++------ src/zm_db.h | 2 +- src/zm_event.cpp | 4 +++- src/zm_event.h | 8 ++++---- src/zm_exception.h | 32 +++++++++++++------------------- src/zm_fifo.h | 13 ++++++++++--- src/zm_local_camera.h | 20 ++++++++++---------- src/zm_logger.h | 4 ++-- src/zm_mem_utils.h | 4 ++-- src/zm_monitor.h | 12 ++++++------ src/zm_packetqueue.h | 2 +- src/zm_time.h | 2 ++ src/zm_user.h | 2 +- src/zmu.cpp | 30 +++++++++++++++--------------- 16 files changed, 82 insertions(+), 76 deletions(-) diff --git a/src/zm_comms.h b/src/zm_comms.h index 46face33c..a5af97dd5 100644 --- a/src/zm_comms.h +++ b/src/zm_comms.h @@ -49,7 +49,7 @@ protected: const int &mWd; protected: - CommsBase( int &rd, int &wd ) : mRd( rd ), mWd( wd ) { + CommsBase(const int &rd, const int &wd) : mRd(rd), mWd(wd) { } virtual ~CommsBase() { } @@ -62,10 +62,10 @@ public: public: int getReadDesc() const { - return( mRd ); + return mRd; } int getWriteDesc() const { - return( mWd ); + return mWd; } int getMaxDesc() const { return( mRd>mWd?mRd:mWd ); diff --git a/src/zm_config.h b/src/zm_config.h index d348f38e9..687ac430c 100644 --- a/src/zm_config.h +++ b/src/zm_config.h @@ -112,8 +112,9 @@ public: double DecimalValue() const; const char *StringValue() const; - ConfigItem &operator=(const ConfigItem item) { - Copy(item);return *this; + ConfigItem &operator=(const ConfigItem &item) { + Copy(item); + return *this; } inline operator bool() const { return BooleanValue(); diff --git a/src/zm_coord.h b/src/zm_coord.h index c6234fb1c..bb49c2f8b 100644 --- a/src/zm_coord.h +++ b/src/zm_coord.h @@ -48,12 +48,12 @@ public: return( result ); } - inline bool operator==( const Coord &coord ) { return( x == coord.x && y == coord.y ); } - inline bool operator!=( const Coord &coord ) { return( x != coord.x || y != coord.y ); } - inline bool operator>( const Coord &coord ) { return( x > coord.x && y > coord.y ); } - inline bool operator>=( const Coord &coord ) { return( !(operator<(coord)) ); } - inline bool operator<( const Coord &coord ) { return( x < coord.x && y < coord.y ); } - inline bool operator<=( const Coord &coord ) { return( !(operator>(coord)) ); } + inline bool operator==( const Coord &coord ) const { return( x == coord.x && y == coord.y ); } + inline bool operator!=( const Coord &coord ) const { return( x != coord.x || y != coord.y ); } + inline bool operator>( const Coord &coord ) const { return( x > coord.x && y > coord.y ); } + inline bool operator>=( const Coord &coord ) const { return( !(operator<(coord)) ); } + inline bool operator<( const Coord &coord ) const { return( x < coord.x && y < coord.y ); } + inline bool operator<=( const Coord &coord ) const { return( !(operator>(coord)) ); } inline Coord &operator+=( const Coord &coord ) { x += coord.x; y += coord.y; return( *this ); } inline Coord &operator-=( const Coord &coord ) { x -= coord.x; y -= coord.y; return( *this ); } diff --git a/src/zm_db.h b/src/zm_db.h index 11fc9faaa..f9f168cd0 100644 --- a/src/zm_db.h +++ b/src/zm_db.h @@ -28,7 +28,7 @@ class zmDbRow { MYSQL_RES *result_set; MYSQL_ROW row; public: - zmDbRow() { result_set = nullptr; row = nullptr; }; + zmDbRow() : result_set(nullptr), row(nullptr) { }; MYSQL_RES *fetch( const char *query ); zmDbRow( MYSQL_RES *, MYSQL_ROW *row ); ~zmDbRow(); diff --git a/src/zm_event.cpp b/src/zm_event.cpp index b201f5c86..a342d91a7 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -571,6 +571,7 @@ void Event::AddFramesInternal(int n_frames, int start_frame, Image **images, str void Event::WriteDbFrames() { char *frame_insert_values_ptr = (char *)&frame_insert_sql + 90; // 90 == strlen(frame_insert_sql); + Debug(1, "Inserting %d frames", frame_data.size()); while ( frame_data.size() ) { Frame *frame = frame_data.front(); frame_data.pop(); @@ -586,8 +587,9 @@ void Event::WriteDbFrames() { frame->score); delete frame; } - *(frame_insert_values_ptr-1) = '\0'; // The -2 is for the extra , added for values above + *(frame_insert_values_ptr-1) = '\0'; // The -1 is for the extra , added for values above db_mutex.lock(); + Debug(1, "SQL: %s", frame_insert_sql); int rc = mysql_query(&dbconn, frame_insert_sql); db_mutex.unlock(); diff --git a/src/zm_event.h b/src/zm_event.h index 8c44af1f2..ff709e5c6 100644 --- a/src/zm_event.h +++ b/src/zm_event.h @@ -113,14 +113,14 @@ class Event { ~Event(); uint64_t Id() const { return id; } - const std::string &Cause() { return cause; } + const std::string &Cause() const { return cause; } int Frames() const { return frames; } int AlarmFrames() const { return alarm_frames; } const struct timeval &StartTime() const { return start_time; } const struct timeval &EndTime() const { return end_time; } - struct timeval &StartTime() { return start_time; } - struct timeval &EndTime() { return end_time; } + struct timeval &StartTime() const { return start_time; } + struct timeval &EndTime() const { return end_time; } bool SendFrameImage( const Image *image, bool alarm_frame=false ); bool WriteFrameImage( Image *image, struct timeval timestamp, const char *event_file, bool alarm_frame=false ); @@ -146,7 +146,7 @@ class Event { return Event::getSubPath( localtime( time ) ); } - const char* getEventFile(void) { + const char* getEventFile(void) const { return video_file.c_str(); } diff --git a/src/zm_exception.h b/src/zm_exception.h index a02653b88..1bceeed8a 100644 --- a/src/zm_exception.h +++ b/src/zm_exception.h @@ -22,8 +22,7 @@ #include -class Exception -{ +class Exception { protected: typedef enum { INFO, WARNING, ERROR, FATAL } Severity; @@ -32,33 +31,28 @@ protected: Severity mSeverity; public: - Exception( const std::string &message, Severity severity=ERROR ) : mMessage( message ), mSeverity( severity ) + explicit Exception(const std::string &message, const Severity severity=ERROR) : + mMessage(message), + mSeverity(severity) { } -public: - const std::string &getMessage() const - { - return( mMessage ); + const std::string &getMessage() const { + return mMessage; } - Severity getSeverity() const - { - return( mSeverity ); + Severity getSeverity() const { + return mSeverity; } - bool isInfo() const - { - return( mSeverity == INFO ); + bool isInfo() const { + return mSeverity == INFO; } - bool isWarning() const - { + bool isWarning() const { return( mSeverity == WARNING ); } - bool isError() const - { + bool isError() const { return( mSeverity == ERROR ); } - bool isFatal() const - { + bool isFatal() const { return( mSeverity == FATAL ); } }; diff --git a/src/zm_fifo.h b/src/zm_fifo.h index 065fd569c..abd666891 100644 --- a/src/zm_fifo.h +++ b/src/zm_fifo.h @@ -68,19 +68,26 @@ class FifoStream : public StreamBase { ); protected: - typedef enum { MJPEG, RAW } StreamType; + typedef enum { UNKNOWN, MJPEG, RAW } StreamType; StreamType stream_type; bool sendMJEGFrames(); bool sendRAWFrames(); void processCommand(const CmdMsg *msg) {} public: - FifoStream() {} + FifoStream() : + stream_path(nullptr), + fd(0), + total_read(0), + bytes_read(0), + frame_count(0), + stream_type(UNKNOWN) + {} static void fifo_create_if_missing( const char * path, bool delete_fake_fifo = true); void setStreamStart(const char * path); void setStreamStart(int monitor_id, const char * format); - void runStream(); + void runStream() override; }; #endif // ZM_FIFO_H diff --git a/src/zm_local_camera.h b/src/zm_local_camera.h index d06631c23..f4fb8bd36 100644 --- a/src/zm_local_camera.h +++ b/src/zm_local_camera.h @@ -153,17 +153,17 @@ public: int Palette() const { return( palette ); } int Extras() const { return( extras ); } - int Brightness( int p_brightness=-1 ); - int Hue( int p_hue=-1 ); - int Colour( int p_colour=-1 ); - int Contrast( int p_contrast=-1 ); + int Brightness( int p_brightness=-1 ) override; + int Hue( int p_hue=-1 ) override; + int Colour( int p_colour=-1 ) override; + int Contrast( int p_contrast=-1 ) override; - int PrimeCapture(); - int PreCapture(); - int Capture( Image &image ); - int PostCapture(); - int CaptureAndRecord( Image &image, timeval recording, char* event_directory ) {return(0);}; - int Close() { return 0; }; + int PrimeCapture()override ; + int PreCapture()override ; + int Capture( Image &image )override ; + int PostCapture()override ; + int CaptureAndRecord( Image &image, timeval recording, char* event_directory ) override {return(0);}; + int Close() override { return 0; }; static bool GetCurrentSettings( const char *device, char *output, int version, bool verbose ); }; diff --git a/src/zm_logger.h b/src/zm_logger.h index 82144a1c9..ad1ac398b 100644 --- a/src/zm_logger.h +++ b/src/zm_logger.h @@ -121,7 +121,7 @@ private: Logger(); ~Logger(); - int limit(int level) { + int limit(const int level) const { if ( level > DEBUG9 ) return DEBUG9; if ( level < NOLOG ) @@ -163,7 +163,7 @@ public: } Level level(Level=NOOPT); - bool debugOn() { + bool debugOn() const { return mEffectiveLevel >= DEBUG1; } diff --git a/src/zm_mem_utils.h b/src/zm_mem_utils.h index 6ef1bdac5..a9e1ab097 100644 --- a/src/zm_mem_utils.h +++ b/src/zm_mem_utils.h @@ -26,7 +26,7 @@ inline void* zm_mallocaligned(unsigned int reqalignment, size_t reqsize) { uint8_t* retptr; #if HAVE_POSIX_MEMALIGN - if ( posix_memalign((void**)&retptr,reqalignment,reqsize) != 0 ) + if ( posix_memalign((void**)&retptr, reqalignment, reqsize) != 0 ) return nullptr; return retptr; @@ -39,7 +39,7 @@ inline void* zm_mallocaligned(unsigned int reqalignment, size_t reqsize) { alloc = retptr + sizeof(void*); - if(((long)alloc % reqalignment) != 0) + if ( ((long)alloc % reqalignment) != 0 ) alloc = alloc + (reqalignment - ((long)alloc % reqalignment)); /* Store a pointer before to the start of the block, just before returned aligned memory */ diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 4b6ec5088..a6d5084bb 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -444,7 +444,7 @@ public: inline Function GetFunction() const { return( function ); } - inline bool Enabled() { + inline bool Enabled() const { if ( function <= MONITOR ) return false; return enabled; @@ -452,17 +452,17 @@ public: inline const char *EventPrefix() const { return event_prefix; } - inline bool Ready() { + inline bool Ready() const { if ( function <= MONITOR ) return false; return( image_count > ready_count ); } - inline bool Active() { + inline bool Active() const { if ( function <= MONITOR ) return false; return( enabled && shared_data->active ); } - inline bool Exif() { + inline bool Exif() const { return embed_exif; } Orientation getOrientation() const; @@ -479,7 +479,7 @@ public: uint64_t GetVideoWriterEventId() const { return video_store_data->current_event; } void SetVideoWriterEventId( unsigned long long p_event_id ) { video_store_data->current_event = p_event_id; } struct timeval GetVideoWriterStartTime() const { return video_store_data->recording; } - void SetVideoWriterStartTime(struct timeval &t) { video_store_data->recording = t; } + void SetVideoWriterStartTime(const struct timeval &t) { video_store_data->recording = t; } unsigned int GetPreEventCount() const { return pre_event_count; }; struct timeval GetVideoBufferDuration() const { return video_buffer_duration; }; @@ -505,7 +505,7 @@ public: inline time_t getStartupTime() const { return shared_data->startup_time; } inline void setStartupTime( time_t p_time ) { shared_data->startup_time = p_time; } - int LabelSize() { return label_size; } + int LabelSize() const { return label_size; } void actionReload(); void actionEnable(); diff --git a/src/zm_packetqueue.h b/src/zm_packetqueue.h index 31fe321cb..cbdf556b4 100644 --- a/src/zm_packetqueue.h +++ b/src/zm_packetqueue.h @@ -31,7 +31,7 @@ extern "C" { } class zm_packetqueue { public: - zm_packetqueue(int max_stream_id); + explicit zm_packetqueue(int max_stream_id); virtual ~zm_packetqueue(); bool queuePacket(AVPacket* packet, struct timeval *timestamp); bool queuePacket(ZMPacket* packet); diff --git a/src/zm_time.h b/src/zm_time.h index 0f7dbc794..490ca1e2c 100644 --- a/src/zm_time.h +++ b/src/zm_time.h @@ -76,7 +76,9 @@ struct DeltaTimeval #define USEC_PER_SEC 1000000 #define MSEC_PER_SEC 1000 +/* extern struct timeval tv; +*/ inline int tvDiffUsec( struct timeval first, struct timeval last ) { diff --git a/src/zm_user.h b/src/zm_user.h index 42fe07554..519ea13de 100644 --- a/src/zm_user.h +++ b/src/zm_user.h @@ -46,7 +46,7 @@ class User { User(); explicit User(const MYSQL_ROW &dbrow); ~User(); - User(User &u) { Copy(u); } + User(const User &u) { Copy(u); } void Copy(const User &u); User& operator=(const User &u) { Copy(u); return *this; diff --git a/src/zmu.cpp b/src/zmu.cpp index bdc467812..30a2a0ce7 100644 --- a/src/zmu.cpp +++ b/src/zmu.cpp @@ -482,7 +482,7 @@ int main(int argc, char *argv[]) { } // end if ! MONITOR if ( verbose ) { - printf("Monitor %d(%s)\n", monitor->Id(), monitor->Name()); + printf("Monitor %u(%s)\n", monitor->Id(), monitor->Name()); } if ( !monitor->connect() ) { Error("Can't connect to capture daemon: %d %s", monitor->Id(), monitor->Name()); @@ -521,19 +521,19 @@ int main(int argc, char *argv[]) { } if ( function & ZMU_READ_IDX ) { if ( verbose ) - printf("Last read index: %d\n", monitor->GetLastReadIndex()); + printf("Last read index: %u\n", monitor->GetLastReadIndex()); else { if ( have_output ) fputc(separator, stdout); - printf("%d", monitor->GetLastReadIndex()); + printf("%u", monitor->GetLastReadIndex()); have_output = true; } } if ( function & ZMU_WRITE_IDX ) { if ( verbose ) { - printf("Last write index: %d\n", monitor->GetLastWriteIndex()); + printf("Last write index: %u\n", monitor->GetLastWriteIndex()); } else { if ( have_output ) fputc(separator, stdout); - printf("%d", monitor->GetLastWriteIndex()); + printf("%u", monitor->GetLastWriteIndex()); have_output = true; } } @@ -558,9 +558,9 @@ int main(int argc, char *argv[]) { if ( function & ZMU_IMAGE ) { if ( verbose ) { if ( image_idx == -1 ) - printf("Dumping last image captured to Monitor%d.jpg", monitor->Id()); + printf("Dumping last image captured to Monitor%u.jpg", monitor->Id()); else - printf("Dumping buffer image %d to Monitor%d.jpg", image_idx, monitor->Id()); + printf("Dumping buffer image %d to Monitor%u.jpg", image_idx, monitor->Id()); if ( scale != -1 ) printf(", scaling by %d%%", scale); printf("\n"); @@ -569,7 +569,7 @@ int main(int argc, char *argv[]) { } if ( function & ZMU_ZONES ) { if ( verbose ) - printf("Dumping zone image to Zones%d.jpg\n", monitor->Id()); + printf("Dumping zone image to Zones%u.jpg\n", monitor->Id()); monitor->DumpZoneImage(zoneString); } if ( function & ZMU_ALARM ) { @@ -735,17 +735,17 @@ int main(int argc, char *argv[]) { Debug(1, "Got %d monitors", mysql_num_rows(result)); printf("%4s%5s%6s%9s%14s%6s%6s%8s%8s\n", "Id", "Func", "State", "TrgState", "LastImgTim", "RdIdx", "WrIdx", "LastEvt", "FrmRate"); - for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++ ) { - int mon_id = atoi(dbrow[0]); - int function = atoi(dbrow[1]); - if ( !user || user->canAccess(mon_id) ) { - if ( function > 1 ) { - Monitor *monitor = Monitor::Load(mon_id, false, Monitor::QUERY); + for ( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++ ) { + int monitor_id = atoi(dbrow[0]); + int monitor_function = atoi(dbrow[1]); + if ( !user || user->canAccess(monitor_id) ) { + if ( monitor_function > 1 ) { + Monitor *monitor = Monitor::Load(monitor_id, false, Monitor::QUERY); if ( monitor && monitor->connect() ) { struct timeval tv = monitor->GetTimestamp(); printf( "%4d%5d%6d%9d%11ld.%02ld%6d%6d%8" PRIu64 "%8.2f\n", monitor->Id(), - function, + monitor_function, monitor->GetState(), monitor->GetTriggerState(), tv.tv_sec, tv.tv_usec/10000, From 3d795be8640be57c9ed545a39520dddddaa0715a Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sun, 1 Nov 2020 15:46:43 -0600 Subject: [PATCH 0544/2339] remove the thumbnail col if WEB_LIST_THUMBS is off --- web/skins/classic/views/js/events.js | 5 ++++- web/skins/classic/views/js/events.js.php | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/events.js b/web/skins/classic/views/js/events.js index f0bd0b3ac..20bf6b87f 100644 --- a/web/skins/classic/views/js/events.js +++ b/web/skins/classic/views/js/events.js @@ -68,7 +68,7 @@ function processRows(rows) { row.Frames = '' + row.Frames + ''; row.AlarmFrames = '' + row.AlarmFrames + ''; row.MaxScore = '' + row.MaxScore + ''; - row.Thumbnail = '' + row.imgHtml + ''; + if ( WEB_LIST_THUMBS ) row.Thumbnail = '' + row.imgHtml + ''; }); return rows; @@ -161,6 +161,9 @@ function getEventDetailModal(eid) { } function initPage() { + // Remove the thumbnail column from the DOM if thumbnails are off globally + if ( !WEB_LIST_THUMBS ) $j('th[data-field="Thumbnail"]').remove(); + // Load the delete confirmation modal into the DOM getDelConfirmModal(); diff --git a/web/skins/classic/views/js/events.js.php b/web/skins/classic/views/js/events.js.php index 48f405dd7..207a6745e 100644 --- a/web/skins/classic/views/js/events.js.php +++ b/web/skins/classic/views/js/events.js.php @@ -11,3 +11,4 @@ var archivedString = ""; var emailedString = ""; var yesString = ""; var noString = ""; +var WEB_LIST_THUMBS = ; From f79602d638ae1f4b472fe3c7bf66a499afac9181 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 1 Nov 2020 17:14:04 -0500 Subject: [PATCH 0545/2339] cppcheck improvements. Use %u instead of %d where appropriate. Move sql def to block where it is used --- src/zm_event.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index a342d91a7..730d23b98 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -88,7 +88,9 @@ Event::Event( char sql[ZM_SQL_MED_BUFSIZ]; struct tm *stime = localtime(&start_time.tv_sec); - snprintf(sql, sizeof(sql), "INSERT INTO Events ( MonitorId, StorageId, Name, StartTime, Width, Height, Cause, Notes, StateId, Orientation, Videoed, DefaultVideo, SaveJPEGs, Scheme ) VALUES ( %d, %d, 'New Event', from_unixtime( %ld ), %d, %d, '%s', '%s', %d, %d, %d, '%s', %d, '%s' )", + snprintf(sql, sizeof(sql), "INSERT INTO Events " + "( MonitorId, StorageId, Name, StartTime, Width, Height, Cause, Notes, StateId, Orientation, Videoed, DefaultVideo, SaveJPEGs, Scheme )" + " VALUES ( %u, %u, 'New Event', from_unixtime( %ld ), %u, %u, '%s', '%s', %u, %d, %d, '%s', %d, '%s' )", monitor->Id(), storage->Id(), start_time.tv_sec, @@ -684,7 +686,6 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a bool db_frame = ( frame_type != BULK ) || (frames==1) || ((frames%config.bulk_frame_interval)==0) ; if ( db_frame ) { - static char sql[ZM_SQL_MED_BUFSIZ]; // The idea is to write out 1/sec frame_data.push(new Frame(id, frames, frame_type, timestamp, delta_time, score)); @@ -694,6 +695,7 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a WriteDbFrames(); last_db_frame = frames; + static char sql[ZM_SQL_MED_BUFSIZ]; snprintf(sql, sizeof(sql), "UPDATE Events SET Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d WHERE Id = %" PRIu64, ( delta_time.positive?"":"-" ), From 82c34361550ab0c388446df89e698d591d27bb62 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 1 Nov 2020 17:14:44 -0500 Subject: [PATCH 0546/2339] cppcheck improvements. Remove non-const StartTime and EndTime. We will remove the dirty hack use in zm_monitor. --- src/zm_event.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/zm_event.h b/src/zm_event.h index ff709e5c6..ab837658e 100644 --- a/src/zm_event.h +++ b/src/zm_event.h @@ -119,17 +119,15 @@ class Event { const struct timeval &StartTime() const { return start_time; } const struct timeval &EndTime() const { return end_time; } - struct timeval &StartTime() const { return start_time; } - struct timeval &EndTime() const { return end_time; } 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 WriteFrameImage( Image *image, struct timeval timestamp, const char *event_file, bool alarm_frame=false ) const; bool WriteFrameVideo( const Image *image, const struct timeval timestamp, VideoWriter* videow ); void updateNotes( const StringSetMap &stringSetMap ); void AddFrames( int n_frames, Image **images, struct timeval **timestamps ); - void AddFrame( Image *image, struct timeval timestamp, int score=0, Image *alarm_frame=nullptr ); + void AddFrame( Image *image, struct timeval timestamp, int score=0, Image *alarm_image=nullptr ); private: void AddFramesInternal( int n_frames, int start_frame, Image **images, struct timeval **timestamps ); From 80e54aee663254b9d5bedb1028a2e0b98450b7f1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 1 Nov 2020 17:15:17 -0500 Subject: [PATCH 0547/2339] cppcheck improvements. Add const and override where we can --- src/zm_eventstream.h | 2 +- src/zm_ffmpeg_input.h | 4 ++-- src/zm_monitorstream.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/zm_eventstream.h b/src/zm_eventstream.h index 5013e5487..be8488486 100644 --- a/src/zm_eventstream.h +++ b/src/zm_eventstream.h @@ -133,7 +133,7 @@ class EventStream : public StreamBase { void setStreamMode( StreamMode p_mode ) { mode = p_mode; } - void runStream(); + void runStream() override; Image *getImage(); private: bool send_file( const char *file_path ); diff --git a/src/zm_ffmpeg_input.h b/src/zm_ffmpeg_input.h index 900f14d4a..35de5edf9 100644 --- a/src/zm_ffmpeg_input.h +++ b/src/zm_ffmpeg_input.h @@ -23,10 +23,10 @@ class FFmpeg_Input { int Close(); AVFrame *get_frame( int stream_id=-1 ); AVFrame *get_frame( int stream_id, double at ); - int get_video_stream_id() { + int get_video_stream_id() const { return video_stream_id; } - int get_audio_stream_id() { + int get_audio_stream_id() const { return audio_stream_id; } diff --git a/src/zm_monitorstream.h b/src/zm_monitorstream.h index 24655b636..20842fa55 100644 --- a/src/zm_monitorstream.h +++ b/src/zm_monitorstream.h @@ -71,7 +71,7 @@ class MonitorStream : public StreamBase { bool setStreamStart(int monitor_id) { return loadMonitor(monitor_id); } - void runStream(); + void runStream() override; }; #endif // ZM_MONITORSTREAM_H From 296f6af7fb707bfc5a81105c9f14656568c8f0ea Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 1 Nov 2020 17:15:42 -0500 Subject: [PATCH 0548/2339] Remove dirty hack that sets EndTime from monitor. It can get set in event destructor --- src/zm_monitor.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 7a1677d7b..231b02916 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -2654,10 +2654,6 @@ bool Monitor::closeEvent() { if ( !event ) return false; - if ( function == RECORD || function == MOCORD ) { - //FIXME Is this neccessary? ENdTime should be set in the destructor - gettimeofday(&(event->EndTime()), nullptr); - } if ( event_delete_thread ) { event_delete_thread->join(); delete event_delete_thread; From 033e749a5756f6246008fb792a99ad455c872982 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 1 Nov 2020 17:16:07 -0500 Subject: [PATCH 0549/2339] improve code logic/spacing --- src/zms.cpp | 165 ++++++++++++++++++++++++++-------------------------- 1 file changed, 83 insertions(+), 82 deletions(-) diff --git a/src/zms.cpp b/src/zms.cpp index 9b661c564..4e77ea4c1 100644 --- a/src/zms.cpp +++ b/src/zms.cpp @@ -95,91 +95,92 @@ int main(int argc, const char *argv[], char **envp) { } const char *query = getenv("QUERY_STRING"); - if ( query ) { - Debug(1, "Query: %s", query); - - char temp_query[1024]; - strncpy(temp_query, query, sizeof(temp_query)-1); - char *q_ptr = temp_query; - char *parms[16]; // Shouldn't be more than this - int parm_no = 0; - while ( (parm_no < 16) && (parms[parm_no] = strtok(q_ptr, "&")) ) { - parm_no++; - q_ptr = nullptr; - } - - for ( int p = 0; p < parm_no; p++ ) { - char *name = strtok(parms[p], "="); - char const *value = strtok(nullptr, "="); - if ( !value ) - value = ""; - if ( !strcmp(name, "source") ) { - source = !strcmp(value, "event")?ZMS_EVENT:ZMS_MONITOR; - if ( !strcmp(value, "fifo") ) - source = ZMS_FIFO; - } else if ( !strcmp(name, "mode") ) { - mode = !strcmp(value, "jpeg")?ZMS_JPEG:ZMS_MPEG; - mode = !strcmp(value, "raw")?ZMS_RAW:mode; - mode = !strcmp(value, "zip")?ZMS_ZIP:mode; - mode = !strcmp(value, "single")?ZMS_SINGLE:mode; - } else if ( !strcmp(name, "format") ) { - strncpy( format, value, sizeof(format) ); - } else if ( !strcmp(name, "monitor") ) { - monitor_id = atoi(value); - if ( source == ZMS_UNKNOWN ) - source = ZMS_MONITOR; - } else if ( !strcmp(name, "time") ) { - event_time = atoi(value); - } else if ( !strcmp(name, "event") ) { - event_id = strtoull(value, nullptr, 10); - source = ZMS_EVENT; - } else if ( !strcmp(name, "frame") ) { - frame_id = strtoull(value, nullptr, 10); - source = ZMS_EVENT; - } else if ( !strcmp(name, "scale") ) { - scale = atoi(value); - } else if ( !strcmp(name, "rate") ) { - rate = atoi(value); - } else if ( !strcmp(name, "maxfps") ) { - maxfps = atof(value); - } else if ( !strcmp(name, "bitrate") ) { - bitrate = atoi(value); - } else if ( !strcmp(name, "ttl") ) { - ttl = atoi(value); - } else if ( !strcmp(name, "replay") ) { - if ( !strcmp(value, "gapless") ) { - replay = EventStream::MODE_ALL_GAPLESS; - } else if ( !strcmp(value, "all") ) { - replay = EventStream::MODE_ALL; - } else if ( !strcmp(value, "none") ) { - replay = EventStream::MODE_NONE; - } else if ( !strcmp(value, "single") ) { - replay = EventStream::MODE_SINGLE; - } else { - Error("Unsupported value %s for replay, defaulting to none", value); - } - } else if ( !strcmp(name, "connkey") ) { - connkey = atoi(value); - } else if ( !strcmp(name, "buffer") ) { - playback_buffer = atoi(value); - } else if ( !strcmp(name, "auth") ) { - strncpy(auth, value, sizeof(auth)-1); - } else if ( !strcmp(name, "token") ) { - jwt_token_str = value; - Debug(1, "ZMS: JWT token found: %s", jwt_token_str.c_str()); - } else if ( !strcmp(name, "user") ) { - username = UriDecode(value); - } else if ( !strcmp(name, "pass") ) { - password = UriDecode(value); - Debug(1, "Have %s for password", password.c_str()); - } else { - Debug(1, "Unknown parameter passed to zms %s=%s", name, value); - } // end if possible parameter names - } // end foreach parm - } else { + if ( query == nullptr ) { Fatal("No query string."); + return 0; } // end if query + Debug(1, "Query: %s", query); + + char temp_query[1024]; + strncpy(temp_query, query, sizeof(temp_query)-1); + char *q_ptr = temp_query; + char *parms[16]; // Shouldn't be more than this + int parm_no = 0; + while ( (parm_no < 16) && (parms[parm_no] = strtok(q_ptr, "&")) ) { + parm_no++; + q_ptr = nullptr; + } + + for ( int p = 0; p < parm_no; p++ ) { + char *name = strtok(parms[p], "="); + char const *value = strtok(nullptr, "="); + if ( !value ) + value = ""; + if ( !strcmp(name, "source") ) { + source = !strcmp(value, "event")?ZMS_EVENT:ZMS_MONITOR; + if ( !strcmp(value, "fifo") ) + source = ZMS_FIFO; + } else if ( !strcmp(name, "mode") ) { + mode = !strcmp(value, "jpeg")?ZMS_JPEG:ZMS_MPEG; + mode = !strcmp(value, "raw")?ZMS_RAW:mode; + mode = !strcmp(value, "zip")?ZMS_ZIP:mode; + mode = !strcmp(value, "single")?ZMS_SINGLE:mode; + } else if ( !strcmp(name, "format") ) { + strncpy(format, value, sizeof(format)-1); + } else if ( !strcmp(name, "monitor") ) { + monitor_id = atoi(value); + if ( source == ZMS_UNKNOWN ) + source = ZMS_MONITOR; + } else if ( !strcmp(name, "time") ) { + event_time = atoi(value); + } else if ( !strcmp(name, "event") ) { + event_id = strtoull(value, nullptr, 10); + source = ZMS_EVENT; + } else if ( !strcmp(name, "frame") ) { + frame_id = strtoull(value, nullptr, 10); + source = ZMS_EVENT; + } else if ( !strcmp(name, "scale") ) { + scale = atoi(value); + } else if ( !strcmp(name, "rate") ) { + rate = atoi(value); + } else if ( !strcmp(name, "maxfps") ) { + maxfps = atof(value); + } else if ( !strcmp(name, "bitrate") ) { + bitrate = atoi(value); + } else if ( !strcmp(name, "ttl") ) { + ttl = atoi(value); + } else if ( !strcmp(name, "replay") ) { + if ( !strcmp(value, "gapless") ) { + replay = EventStream::MODE_ALL_GAPLESS; + } else if ( !strcmp(value, "all") ) { + replay = EventStream::MODE_ALL; + } else if ( !strcmp(value, "none") ) { + replay = EventStream::MODE_NONE; + } else if ( !strcmp(value, "single") ) { + replay = EventStream::MODE_SINGLE; + } else { + Error("Unsupported value %s for replay, defaulting to none", value); + } + } else if ( !strcmp(name, "connkey") ) { + connkey = atoi(value); + } else if ( !strcmp(name, "buffer") ) { + playback_buffer = atoi(value); + } else if ( !strcmp(name, "auth") ) { + strncpy(auth, value, sizeof(auth)-1); + } else if ( !strcmp(name, "token") ) { + jwt_token_str = value; + Debug(1, "ZMS: JWT token found: %s", jwt_token_str.c_str()); + } else if ( !strcmp(name, "user") ) { + username = UriDecode(value); + } else if ( !strcmp(name, "pass") ) { + password = UriDecode(value); + Debug(1, "Have %s for password", password.c_str()); + } else { + Debug(1, "Unknown parameter passed to zms %s=%s", name, value); + } // end if possible parameter names + } // end foreach parm + if ( monitor_id ) { snprintf(log_id_string, sizeof(log_id_string), "zms_m%d", monitor_id); } else { From 5b918e69f14b243a59fc8a9de049827c6a420502 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 1 Nov 2020 17:16:19 -0500 Subject: [PATCH 0550/2339] spacing --- src/zm_video.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/zm_video.cpp b/src/zm_video.cpp index d97c75167..b24905ece 100644 --- a/src/zm_video.cpp +++ b/src/zm_video.cpp @@ -216,7 +216,7 @@ int X264MP4Writer::Open() { int X264MP4Writer::Close() { /* Flush all pending frames */ for ( int i = (x264_encoder_delayed_frames(x264enc) + 1); i > 0; i-- ) { -Debug(1,"Encoding delayed frame"); + Debug(1, "Encoding delayed frame"); if ( x264encodeloop(true) < 0 ) break; } @@ -227,7 +227,7 @@ Debug(1,"Encoding delayed frame"); /* Close MP4 handle */ MP4Close(mp4h); - Debug(1,"Optimising"); + Debug(1, "Optimising"); /* Required for proper HTTP streaming */ MP4Optimize((path + ".incomplete").c_str(), path.c_str()); From 6e3eb922e02287d9b190e1a28fb8e22fb550ccbd Mon Sep 17 00:00:00 2001 From: Matt N Date: Sun, 1 Nov 2020 14:55:08 -0800 Subject: [PATCH 0551/2339] Use relative symlinks for monitor event directories This way the link continues to work from backups and after the user moves ZM data to a new directory. --- web/includes/actions/monitor.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web/includes/actions/monitor.php b/web/includes/actions/monitor.php index 140957046..be17578cf 100644 --- a/web/includes/actions/monitor.php +++ b/web/includes/actions/monitor.php @@ -121,7 +121,8 @@ if ( $action == 'save' ) { } $saferNewName = basename($_REQUEST['newMonitor']['Name']); $link_path = $NewStorage->Path().'/'.$saferNewName; - if ( !symlink($NewStorage->Path().'/'.$mid, $link_path) ) { + // Use a relative path for the target so the link continues to work from backups or directory changes. + if ( !symlink($mid, $link_path) ) { if ( ! ( file_exists($link_path) and is_link($link_path) ) ) { ZM\Warning('Unable to symlink ' . $NewStorage->Path().'/'.$mid . ' to ' . $NewStorage->Path().'/'.$saferNewName); } From 4e80c04d230d082500f29dc2bbac5b27a1f736e0 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 1 Nov 2020 18:48:13 -0500 Subject: [PATCH 0552/2339] fix lack of const to match def --- src/zm_event.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 730d23b98..f5d93f151 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -336,7 +336,7 @@ bool Event::WriteFrameImage( Image *image, struct timeval timestamp, const char *event_file, - bool alarm_frame) { + bool alarm_frame) const { int thisquality = (alarm_frame && (config.jpeg_alarm_file_quality > config.jpeg_file_quality)) ? From ea4d3ccd7a589cf347bcd3050c60b0fe582c18ba Mon Sep 17 00:00:00 2001 From: Esteban Flores Date: Mon, 2 Nov 2020 01:05:57 -0600 Subject: [PATCH 0553/2339] Changed "Purge By Age" filter Changed "Purge By Age" filter, the "date" option is not available in v1.34.22. Using "End Date" as the filter parameter works just fine. --- docs/faq.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/faq.rst b/docs/faq.rst index 56b67d082..1db30e05f 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -27,7 +27,7 @@ After you've done that, you changes will automatically be loaded into zmfilter w Check the ``zmfilter.log`` file to make sure it is running as sometimes missing perl modules mean that it never runs but people don't always realize. **Purge By Age** -To delete events that are older than 7 days, create a new filter with "Date" set to "less than" and a value of "-7 days", sort by "date/time" in "asc"ending order, then enable the checkbox "delete all matches". You can also use a value of week or week and days: "-2 week" or "-2 week 4 day" +To delete events that are older than 7 days, create a new filter with "End Date" set to "less than" and a value of "-7 days", sort by "date/time" in "asc"ending order, then enable the checkbox "delete all matches". You can also use a value of week or week and days: "-2 week" or "-2 week 4 day" Save with 'Run Filter In Background' enabled to have it run automatically. Optional skip archived events: click on the plus sign next to -7 days to add another condition. "and" "archive status" equal to "unarchived only". @@ -534,4 +534,4 @@ The GPL license allows you produce systems based on GPL software provided your s I am having issues with zmNinja and/or Event Notification Server ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -zmNinja and the Event Notification Server are 3rd party solutions. The developer maintains exhaustive `documentation and FAQs `__. Please direct your questions there. \ No newline at end of file +zmNinja and the Event Notification Server are 3rd party solutions. The developer maintains exhaustive `documentation and FAQs `__. Please direct your questions there. From ed87ad36b318739e45663f077fe6b984aa66b508 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 2 Nov 2020 12:09:25 -0500 Subject: [PATCH 0554/2339] missing break --- src/zm_eventstream.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/zm_eventstream.cpp b/src/zm_eventstream.cpp index b8de60e46..05fa647ae 100644 --- a/src/zm_eventstream.cpp +++ b/src/zm_eventstream.cpp @@ -424,6 +424,7 @@ void EventStream::processCommand(const CmdMsg *msg) { switch ( replay_rate ) { case -1 * ZM_RATE_BASE : replay_rate = -2 * ZM_RATE_BASE; + break; case -2 * ZM_RATE_BASE : replay_rate = -5 * ZM_RATE_BASE; break; From 492e65c2fdd697bece9e4c196ff7f729a682b7bc Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 2 Nov 2020 12:42:30 -0500 Subject: [PATCH 0555/2339] Add missing PathToAPI --- web/skins/classic/views/options.php | 1 + 1 file changed, 1 insertion(+) diff --git a/web/skins/classic/views/options.php b/web/skins/classic/views/options.php index a52aca15d..2be9e9b52 100644 --- a/web/skins/classic/views/options.php +++ b/web/skins/classic/views/options.php @@ -231,6 +231,7 @@ foreach ( array_map('basename', glob('skins/'.$skin.'/css/*', GLOB_ONLYDIR)) as Url()), $canEdit, $svr_opt ) ?> PathToIndex()), $canEdit, $svr_opt ) ?> PathToZMS()), $canEdit, $svr_opt ) ?> + PathToAPI()), $canEdit, $svr_opt ) ?> Status()), $canEdit, $svr_opt) ?> Id()]), $canEdit, $svr_opt) ?> From 7650e0bf5174180409fcc997e77e08cef40cde59 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 2 Nov 2020 12:43:45 -0500 Subject: [PATCH 0556/2339] cleanup my totalNotFiltered code. Join Monitors as well as they can be referenced by the filter --- web/ajax/events.php | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/web/ajax/events.php b/web/ajax/events.php index 769bd29d9..e6ec9ec0b 100644 --- a/web/ajax/events.php +++ b/web/ajax/events.php @@ -181,8 +181,6 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim if ( $where ) $where = ' WHERE '.$where; - # total has to be the # of available rows. Not sure what totalNotFiltered is actually used for yet. - $data['totalNotFiltered'] = $data['total'] = dbFetchOne('SELECT count(*) AS Total FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id'. $where, 'Total', $query['values']); $sort = $sort == 'Monitor' ? 'M.Name' : 'E.'.$sort; $col_str = 'E.*, M.Name AS Monitor'; @@ -229,15 +227,14 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim } $data['rows'] = $rows; - if ( 0 ) { # totalNotFiltered must equal total, except when either search bar has been used - $data['totalNotFiltered'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table. ' AS E'. ($filter->sql() ? ' WHERE '.$filter->sql():''), 'Total'); + $data['totalNotFiltered'] = dbFetchOne( + 'SELECT count(*) AS Total FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id'. ($filter->sql() ? ' WHERE '.$filter->sql():''), 'Total'); if ( $search != '' || count($advsearch) ) { - $data['total'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table. ' AS E'.$where , 'Total', $wherevalues); + $data['total'] = dbFetchOne('SELECT count(*) AS Total FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id'.$where , 'Total', $wherevalues); } else { $data['total'] = $data['totalNotFiltered']; } - } return $data; } ?> From 5d32e0faf0865734ab572d143eb32e1fbf279caa Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 2 Nov 2020 12:45:19 -0500 Subject: [PATCH 0557/2339] cppcheck fixes. Make curr_frame_id signed as we may subtract from it and go < 0 --- src/zm_eventstream.cpp | 31 +++++++++++++++---------------- src/zm_eventstream.h | 6 +++--- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/zm_eventstream.cpp b/src/zm_eventstream.cpp index 05fa647ae..6f2ba4197 100644 --- a/src/zm_eventstream.cpp +++ b/src/zm_eventstream.cpp @@ -189,13 +189,13 @@ bool EventStream::loadEventData(uint64_t event_id) { if ( storage_path[0] == '/' ) snprintf(event_data->path, sizeof(event_data->path), - "%s/%d/%02d/%02d/%02d/%02d/%02d/%02d", + "%s/%u/%02d/%02d/%02d/%02d/%02d/%02d", storage_path, event_data->monitor_id, event_time->tm_year-100, event_time->tm_mon+1, event_time->tm_mday, event_time->tm_hour, event_time->tm_min, event_time->tm_sec); else snprintf(event_data->path, sizeof(event_data->path), - "%s/%s/%d/%02d/%02d/%02d/%02d/%02d/%02d", + "%s/%s/%u/%02d/%02d/%02d/%02d/%02d/%02d", staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id, event_time->tm_year-100, event_time->tm_mon+1, event_time->tm_mday, event_time->tm_hour, event_time->tm_min, event_time->tm_sec); @@ -203,23 +203,23 @@ bool EventStream::loadEventData(uint64_t event_id) { struct tm *event_time = localtime(&event_data->start_time); if ( storage_path[0] == '/' ) snprintf(event_data->path, sizeof(event_data->path), - "%s/%d/%04d-%02d-%02d/%" PRIu64, + "%s/%u/%04d-%02d-%02d/%" PRIu64, storage_path, event_data->monitor_id, event_time->tm_year+1900, event_time->tm_mon+1, event_time->tm_mday, event_data->event_id); else snprintf(event_data->path, sizeof(event_data->path), - "%s/%s/%d/%04d-%02d-%02d/%" PRIu64, + "%s/%s/%u/%04d-%02d-%02d/%" PRIu64, staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id, - event_time->tm_year+1900, event_time->tm_mon+1, event_time->tm_mday, + event_time->tm_year+1900, event_time->tm_mon+1, event_time->tm_mday, event_data->event_id); } else { if ( storage_path[0] == '/' ) - snprintf(event_data->path, sizeof(event_data->path), "%s/%d/%" PRIu64, + snprintf(event_data->path, sizeof(event_data->path), "%s/%u/%" PRIu64, storage_path, event_data->monitor_id, event_data->event_id); else - snprintf(event_data->path, sizeof(event_data->path), "%s/%s/%d/%" PRIu64, + snprintf(event_data->path, sizeof(event_data->path), "%s/%s/%u/%" PRIu64, staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id, event_data->event_id); } @@ -527,7 +527,7 @@ void EventStream::processCommand(const CmdMsg *msg) { if ( offset < 0.0 ) { Warning("Invalid offset, not seeking"); break; - } + } // This should get us close, but not all frames will have the same duration curr_frame_id = (int)(event_data->frame_count*offset/event_data->duration)+1; if ( event_data->frames[curr_frame_id-1].offset > offset ) { @@ -539,10 +539,10 @@ void EventStream::processCommand(const CmdMsg *msg) { } if ( curr_frame_id < 1 ) { curr_frame_id = 1; - } else if ( curr_frame_id > event_data->last_frame_id ) { + } else if ( (unsigned long)curr_frame_id > event_data->last_frame_id ) { curr_frame_id = event_data->last_frame_id; } - + curr_stream_time = event_data->frames[curr_frame_id-1].timestamp; Debug(1, "Got SEEK command, to %f (new current frame id: %d offset %f)", offset, curr_frame_id, event_data->frames[curr_frame_id-1].offset); @@ -795,7 +795,7 @@ bool EventStream::sendFrame(int delta_us) { Error("Unable to get a frame"); return false; } - + Image *send_image = prepareImage(image); static unsigned char temp_img_buffer[ZM_MAX_IMAGE_SIZE]; int img_buffer_size = 0; @@ -882,7 +882,7 @@ void EventStream::runStream() { // If we are streaming and this frame is due to be sent // frame mod defaults to 1 and if we are going faster than max_fps will get multiplied by 2 // so if it is 2, then we send every other frame, if is it 4 then every fourth frame, etc. - + if ( (frame_mod == 1) || (((curr_frame_id-1)%frame_mod) == 0) ) { send_frame = true; } @@ -964,7 +964,7 @@ void EventStream::runStream() { if ( (mode == MODE_SINGLE) && ( (curr_frame_id < 1 ) || - ((unsigned int)curr_frame_id >= event_data->frame_count) + ((unsigned int)curr_frame_id >= event_data->frame_count) ) ) { Debug(2, "Have mode==MODE_SINGLE and at end of event, looping back to start"); @@ -1055,9 +1055,8 @@ void EventStream::runStream() { closeComms(); } // end void EventStream::runStream() -bool EventStream::send_file(const char * filepath) { +bool EventStream::send_file(const char *filepath) { static unsigned char temp_img_buffer[ZM_MAX_IMAGE_SIZE]; - int rc; int img_buffer_size = 0; uint8_t *img_buffer = temp_img_buffer; @@ -1085,7 +1084,7 @@ bool EventStream::send_file(const char * filepath) { Info("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno)); return false; } - rc = zm_sendfile(fileno(stdout), fileno(fdj), 0, (int)filestat.st_size); + int rc = zm_sendfile(fileno(stdout), fileno(fdj), 0, (int)filestat.st_size); if ( rc == (int)filestat.st_size ) { // Success fclose(fdj); /* Close the file handle */ diff --git a/src/zm_eventstream.h b/src/zm_eventstream.h index be8488486..39daf23d0 100644 --- a/src/zm_eventstream.h +++ b/src/zm_eventstream.h @@ -76,7 +76,7 @@ class EventStream : public StreamBase { StreamMode mode; bool forceEventChange; - unsigned long curr_frame_id; + long curr_frame_id; double curr_stream_time; bool send_frame; struct timeval start; // clock time when started the event @@ -136,8 +136,8 @@ class EventStream : public StreamBase { void runStream() override; Image *getImage(); private: - bool send_file( const char *file_path ); - bool send_buffer( uint8_t * buffer, int size ); + bool send_file(const char *filepath); + bool send_buffer(uint8_t * buffer, int size); Storage *storage; FFmpeg_Input *ffmpeg_input; AVCodecContext *input_codec_context; From a857f677a60b990a95eb280d1accdcd4ee0aa776 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 2 Nov 2020 12:45:48 -0500 Subject: [PATCH 0558/2339] cppcheck fixes, mostly %d->%u --- src/zm_monitorstream.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/zm_monitorstream.cpp b/src/zm_monitorstream.cpp index 71a7a66d2..58039b2bf 100644 --- a/src/zm_monitorstream.cpp +++ b/src/zm_monitorstream.cpp @@ -292,7 +292,7 @@ void MonitorStream::processCommand(const CmdMsg *msg) { if ( (nbytes = sendto(sd, &status_msg, sizeof(status_msg), MSG_DONTWAIT, (sockaddr *)&rem_addr, sizeof(rem_addr))) < 0 ) { //if ( errno != EAGAIN ) { - Error( "Can't sendto on sd %d: %s", sd, strerror(errno) ); + Error("Can't sendto on sd %d: %s", sd, strerror(errno)); //exit( -1 ); } } @@ -503,7 +503,7 @@ void MonitorStream::runStream() { const int max_swap_len_suffix = 15; int swap_path_length = staticConfig.PATH_SWAP.length() + 1; // +1 for NULL terminator - int subfolder1_length = snprintf(nullptr, 0, "/zmswap-m%d", monitor->Id()) + 1; + int subfolder1_length = snprintf(nullptr, 0, "/zmswap-m%u", monitor->Id()) + 1; int subfolder2_length = snprintf(nullptr, 0, "/zmswap-q%06d", connkey) + 1; int total_swap_path_length = swap_path_length + subfolder1_length + subfolder2_length; @@ -874,7 +874,7 @@ void MonitorStream::SingleImageRaw(int scale) { } fprintf(stdout, - "Content-Length: %d\r\n" + "Content-Length: %u\r\n" "Content-Type: image/x-rgb\r\n\r\n", snap_image->Size()); fwrite(snap_image->Buffer(), snap_image->Size(), 1, stdout); From 96a9a73320e778bdb07486a5c24cdf9f20e84874 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Mon, 2 Nov 2020 14:33:40 -0600 Subject: [PATCH 0559/2339] roll back events.php --- web/ajax/events.php | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/web/ajax/events.php b/web/ajax/events.php index 769bd29d9..1f8e71f1a 100644 --- a/web/ajax/events.php +++ b/web/ajax/events.php @@ -181,9 +181,6 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim if ( $where ) $where = ' WHERE '.$where; - # total has to be the # of available rows. Not sure what totalNotFiltered is actually used for yet. - $data['totalNotFiltered'] = $data['total'] = dbFetchOne('SELECT count(*) AS Total FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id'. $where, 'Total', $query['values']); - $sort = $sort == 'Monitor' ? 'M.Name' : 'E.'.$sort; $col_str = 'E.*, M.Name AS Monitor'; $query['sql'] = 'SELECT ' .$col_str. ' FROM `' .$table. '` AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id'.$where.' ORDER BY ' .$sort. ' ' .$order. ' LIMIT ?, ?'; @@ -198,10 +195,6 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim } $rows = array(); - $results = dbFetchAll($query['sql'], NULL, $query['values']); - if ( ! $results ) { - return $data; - } foreach ( dbFetchAll($query['sql'], NULL, $query['values']) as $row ) { $event = new ZM\Event($row); if ( !$filter->test_post_sql_conditions($event) ) { @@ -229,7 +222,6 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim } $data['rows'] = $rows; - if ( 0 ) { # totalNotFiltered must equal total, except when either search bar has been used $data['totalNotFiltered'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table. ' AS E'. ($filter->sql() ? ' WHERE '.$filter->sql():''), 'Total'); if ( $search != '' || count($advsearch) ) { @@ -237,7 +229,7 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim } else { $data['total'] = $data['totalNotFiltered']; } - } + return $data; } ?> From bd1d4f954bd39f18db67227430e5053943b46f7f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 2 Nov 2020 15:45:05 -0500 Subject: [PATCH 0560/2339] Test for EndTime value before using strftime on it. --- web/ajax/events.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/ajax/events.php b/web/ajax/events.php index 1f8e71f1a..fad91683d 100644 --- a/web/ajax/events.php +++ b/web/ajax/events.php @@ -213,7 +213,7 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim $row['Emailed'] = $row['Emailed'] ? translate('Yes') : translate('No'); $row['Cause'] = validHtmlStr($row['Cause']); $row['StartTime'] = strftime(STRF_FMT_DATETIME_SHORTER, strtotime($row['StartTime'])); - $row['EndTime'] = strftime(STRF_FMT_DATETIME_SHORTER, strtotime($row['EndTime'])); + $row['EndTime'] = $row['EndTime'] ? strftime(STRF_FMT_DATETIME_SHORTER, strtotime($row['EndTime'])) : null; $row['Length'] = gmdate('H:i:s', $row['Length'] ); $row['Storage'] = ( $row['StorageId'] and isset($StorageById[$row['StorageId']]) ) ? $StorageById[$row['StorageId']]->Name() : 'Default'; $row['Notes'] = nl2br(htmlspecialchars($row['Notes'])); From 0f74e24bfc0c74167f881b7a0fc208aaa530a2e4 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 2 Nov 2020 15:50:38 -0500 Subject: [PATCH 0561/2339] Join Monitors as M as well in total and totalNotFiltered queries --- web/ajax/events.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/ajax/events.php b/web/ajax/events.php index 1f8e71f1a..833c566d5 100644 --- a/web/ajax/events.php +++ b/web/ajax/events.php @@ -223,9 +223,9 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim $data['rows'] = $rows; # totalNotFiltered must equal total, except when either search bar has been used - $data['totalNotFiltered'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table. ' AS E'. ($filter->sql() ? ' WHERE '.$filter->sql():''), 'Total'); + $data['totalNotFiltered'] = dbFetchOne('SELECT count(*) AS Total FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id'. ($filter->sql() ? ' WHERE '.$filter->sql():''), 'Total'); if ( $search != '' || count($advsearch) ) { - $data['total'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table. ' AS E'.$where , 'Total', $wherevalues); + $data['total'] = dbFetchOne('SELECT count(*) AS Total FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id'.$where , 'Total', $wherevalues); } else { $data['total'] = $data['totalNotFiltered']; } From b8bd4b6961361aa6a8eb88206d2bc1f7f27e8463 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 2 Nov 2020 16:34:00 -0500 Subject: [PATCH 0562/2339] Add fallback for now to endtime. Set endtime in AddFramesInternal as well just in case there was never another frame. --- src/zm_event.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index f5d93f151..e762698fa 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -256,6 +256,11 @@ Event::~Event() { videowriter = nullptr; } + // endtime is set in AddFrame, so SHOULD be set to the value of the last frame timestamp. + if ( ! end_time.tv_sec ) { + Warning("Empty endtime for event. Should not happen. Setting to now."); + gettimeofday(&end_time, nullptr); + } struct DeltaTimeval delta_time; DELTA_TIMEVAL(delta_time, end_time, start_time, DT_PREC_2); Debug(2, "start_time:%d.%d end_time%d.%d", start_time.tv_sec, start_time.tv_usec, end_time.tv_sec, end_time.tv_usec); @@ -569,6 +574,7 @@ void Event::AddFramesInternal(int n_frames, int start_frame, Image **images, str } else { Debug(1, "No valid pre-capture frames to add"); } + end_time = *timestamps[n_frames-1]; } // void Event::AddFramesInternal(int n_frames, int start_frame, Image **images, struct timeval **timestamps) void Event::WriteDbFrames() { From 432ae9894bfe91226c0d667b9e0940fac200966f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 3 Nov 2020 08:34:41 -0500 Subject: [PATCH 0563/2339] Add EndTime IS NOT NULL to PurgeWhenFull Filter --- db/zm_create.sql.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index d3e7af6b6..fa8f9d1f3 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -804,7 +804,7 @@ INSERT INTO `Filters` VALUES ( 'PurgeWhenFull', - '{"sort_field":"Id","terms":[{"val":0,"attr":"Archived","op":"="},{"cnj":"and","val":95,"attr":"DiskPercent","op":">="}],"limit":100,"sort_asc":1}', + '{"sort_field":"Id","terms":[{"val":0,"attr":"Archived","op":"="},{"cnj":"and","val":95,"attr":"DiskPercent","op":">="},{"cnj":"and","obr":"0","attr":"EndDateTime","op":"IS NOT","val":"NULL","cbr":"0"}],"limit":100,"sort_asc":1}', 0/*AutoArchive*/, 0/*AutoVideo*/, 0/*AutoUpload*/, From 903c6a2d5a31c27d1ff7594fb735b1797c3db371 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 3 Nov 2020 08:41:57 -0500 Subject: [PATCH 0564/2339] Add EndTime IS NOT NULL to UpdateDiskSpace Filter --- db/zm_create.sql.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index fa8f9d1f3..41ed75eba 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -848,7 +848,7 @@ INSERT INTO `Filters` ) VALUES ( 'Update DiskSpace', - '{"terms":[{"attr":"DiskSpace","op":"IS","val":"NULL"}]}', + '{"terms":[{"attr":"DiskSpace","op":"IS","val":"NULL"},{"cnj":"and","obr":"0","attr":"EndDateTime","op":"IS NOT","val":"NULL","cbr":"0"}]}', 0/*AutoArchive*/, 0/*AutoVideo*/, 0/*AutoUpload*/, From f7c9a0e03d6a74749cc805b8890fe684b567bbf8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 3 Nov 2020 11:44:54 -0500 Subject: [PATCH 0565/2339] Must urlencode [Id]= --- web/includes/Filter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/includes/Filter.php b/web/includes/Filter.php index bd22f3b89..068ee628e 100644 --- a/web/includes/Filter.php +++ b/web/includes/Filter.php @@ -60,7 +60,7 @@ class Filter extends ZM_Object { $this->_querystring .= $term->querystring($objectname, $separator); } # end foreach term if ( $this->Id() ) { - $this->_querystring .= $separator.$objectname.'[Id]='.$this->Id(); + $this->_querystring .= $separator.$objectname.urlencode('[Id]=').$this->Id(); } } return $this->_querystring; From dda1decfb1a3e80a238798afcd463e10e0f50277 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 3 Nov 2020 11:45:22 -0500 Subject: [PATCH 0566/2339] When redirecting after execute, redirect to the full filter querystring, as it may not have an Id and may have additional changes --- web/includes/actions/filter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/includes/actions/filter.php b/web/includes/actions/filter.php index 63f4af94e..572cccf08 100644 --- a/web/includes/actions/filter.php +++ b/web/includes/actions/filter.php @@ -95,7 +95,7 @@ if ( isset($_REQUEST['object']) and ( $_REQUEST['object'] == 'filter' ) ) { } else if ( $filter->Background() ) { $filter->control('start'); } - $redirect = '?view=filter&Id='.$filter->Id(); + $redirect = '?view=filter'.$filter->querystring(); } else if ( $action == 'control' ) { if ( $_REQUEST['command'] == 'start' From b2385cceccf711659ac55eb991ef72b35373c669 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 3 Nov 2020 11:53:15 -0500 Subject: [PATCH 0567/2339] colour match a:link to navbar colour. This has the effect of brightening up all links. --- web/skins/classic/css/base/skin.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/css/base/skin.css b/web/skins/classic/css/base/skin.css index c6723b3a8..ee7a8a471 100644 --- a/web/skins/classic/css/base/skin.css +++ b/web/skins/classic/css/base/skin.css @@ -123,7 +123,7 @@ table th:last-child{ a:link { - color: #3498db; + color: #0fbcf9; text-decoration: none; } From 6112db627cfd469b7a4565db47ba390ba501b80f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 3 Nov 2020 11:59:28 -0500 Subject: [PATCH 0568/2339] Even if we found the filter in the db, if it is present in the query string, update the object with the new values --- web/skins/classic/views/filter.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/web/skins/classic/views/filter.php b/web/skins/classic/views/filter.php index d53fff02a..bcf46e360 100644 --- a/web/skins/classic/views/filter.php +++ b/web/skins/classic/views/filter.php @@ -53,17 +53,17 @@ foreach ( ZM\Filter::find(null,array('order'=>'lower(Name)')) as $Filter ) { $filter = $Filter; } } -if ( !$filter ) { +if ( !$filter ) { $filter = new ZM\Filter(); - - if ( isset($_REQUEST['filter']) ) { - # Update our filter object with whatever changes we have made before saving - $filter->set($_REQUEST['filter']); - } -} else { - ZM\Debug('filter: ' . print_r($filter,true)); } +if ( isset($_REQUEST['filter']) ) { + # Update our filter object with whatever changes we have made before saving + $filter->set($_REQUEST['filter']); + ZM\Debug("Setting filter from " . print_r($_REQUEST['filter'], true)); +} +ZM\Debug('filter: ' . print_r($filter,true)); + $conjunctionTypes = ZM\getFilterQueryConjunctionTypes(); $obracketTypes = array(); $cbracketTypes = array(); From c72ceffe3d66011f1a12d3f6c80e7e35e76a0d8f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 3 Nov 2020 12:30:27 -0500 Subject: [PATCH 0569/2339] Improved testing for existence of foreign keys, better descriptive output of steps. --- db/zm_update-1.35.11.sql | 45 ++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/db/zm_update-1.35.11.sql b/db/zm_update-1.35.11.sql index ad73b7bf4..5e4338d76 100644 --- a/db/zm_update-1.35.11.sql +++ b/db/zm_update-1.35.11.sql @@ -1,7 +1,7 @@ /* Change Id type to BIGINT. */ set @exist := (SELECT count(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = 'Events' AND COLUMN_NAME = 'Id' and DATA_TYPE='bigint'); -set @sqlstmt := if( @exist = 0, "ALTER TABLE Events MODIFY Id bigint unsigned NOT NULL auto_increment", "SELECT 'Ok'"); +set @sqlstmt := if( @exist = 0, "ALTER TABLE Events MODIFY Id bigint unsigned NOT NULL auto_increment", "SELECT 'Events.Id is already BIGINT'"); PREPARE stmt FROM @sqlstmt; EXECUTE stmt; @@ -14,69 +14,78 @@ set @sqlstmt := if( @exist = 0, "SELECT 'Adding foreign key for EventId to Frame PREPARE stmt FROM @sqlstmt; EXECUTE stmt; -set @sqlstmt := if( @exist != 0, "SELECT '.'", "SELECT 'Deleting unlinked Frames'"); +set @sqlstmt := if( @exist = 0, "SELECT 'Deleting unlinked Frames'", "SELECT '.'"); PREPARE stmt FROM @sqlstmt; EXECUTE stmt; -set @sqlstmt := if( @exist != 0, "SELECT '.'", "DELETE FROM Frames WHERE EventId NOT IN (SELECT Id FROM Events)"); +set @sqlstmt := if( @exist = 0, "DELETE FROM Frames WHERE EventId NOT IN (SELECT Id FROM Events)", "SELECT '.'"); PREPARE stmt FROM @sqlstmt; EXECUTE stmt; -set @sqlstmt := if( @exist != 0, "SELECT 'Ok'", "ALTER TABLE Frames ADD FOREIGN KEY (EventId) REFERENCES Events (Id) ON DELETE CASCADE"); +set @sqlstmt := if( @exist = 0, "ALTER TABLE Frames ADD FOREIGN KEY (EventId) REFERENCES Events (Id) ON DELETE CASCADE", "SELECT '.'"); PREPARE stmt FROM @sqlstmt; EXECUTE stmt; -SELECT 'Adding foreign key for EventId to Stats'; set @exist := (select count(*) FROM information_schema.key_column_usage where table_name='Stats' and column_name='EventId' and referenced_table_name='Events' and referenced_column_name='Id'); set @sqlstmt := if( @exist > 1, "SELECT 'You have more than 1 FOREIGN KEY. Please do manual cleanup'", "SELECT 'Ok'"); -set @sqlstmt := if( @exist = 1, "SELECT 'FOREIGN KEY already EventId in Stats already exists'", @sqlstmt); +set @sqlstmt := if( @exist = 1, "SELECT 'FOREIGN KEY EventId in Stats already exists'", @sqlstmt); set @sqlstmt := if( @exist = 0, "SELECT 'Adding FOREIGN KEY for EventId to Stats'", @sqlstmt); PREPARE stmt FROM @sqlstmt; EXECUTE stmt; -set @sqlstmt := if( @exist > 0, "SELECT 'FOREIGN KEY for EventId in Stats already exists'", "DELETE FROM Stats WHERE EventId NOT IN (SELECT Id FROM Events);"); +set @sqlstmt := if( @exist = 0, "SELECT 'Deleting unlinked Stats'", "SELECT '.'"); +PREPARE stmt FROM @sqlstmt; +EXECUTE stmt; +set @sqlstmt := if( @exist = 0, "DELETE FROM Stats WHERE EventId NOT IN (SELECT Id FROM Events);", "SELECT '.'"); PREPARE stmt FROM @sqlstmt; EXECUTE stmt; -set @sqlstmt := if( @exist > 0, "SELECT 'Ok'", "ALTER TABLE Stats ADD FOREIGN KEY (EventId) REFERENCES Events (Id) ON DELETE CASCADE"); +set @sqlstmt := if( @exist = 0, "ALTER TABLE Stats ADD FOREIGN KEY (EventId) REFERENCES Events (Id) ON DELETE CASCADE", "SELECT '.'"); PREPARE stmt FROM @sqlstmt; EXECUTE stmt; -SELECT 'Adding foreign key for MonitorId to Stats'; set @exist := (select count(*) FROM information_schema.key_column_usage where table_name='Stats' and column_name='MonitorId' and referenced_table_name='Monitors' and referenced_column_name='Id'); set @sqlstmt := if( @exist > 1, "SELECT 'You have more than 1 FOREIGN KEY. Please do manual cleanup'", "SELECT 'Ok'"); +set @sqlstmt := if( @exist = 1, "SELECT 'FOREIGN KEY for MonitorId in Stats already exists'", @sql_stmt); +set @sqlstmt := if( @exist = 0, "SELECT 'Adding FOREIGN KEY for MonitorId to Stats'", @sqlstmt); PREPARE stmt FROM @sqlstmt; EXECUTE stmt; -set @sqlstmt := if( @exist > 0, "SELECT 'FOREIGN KEY for MonitorId in Stats already exists'", "DELETE FROM Stats WHERE MonitorId NOT IN (SELECT Id FROM Monitors);"); +set @sqlstmt := if( @exist = 0, "SELECT 'Deleting unlinked Stats'", "SELECT '.'"); +PREPARE stmt FROM @sqlstmt; +EXECUTE stmt; +set @sqlstmt := if( @exist = 0, "DELETE FROM Stats WHERE MonitorId NOT IN (SELECT Id FROM Monitors);", "SELECT '.'"); PREPARE stmt FROM @sqlstmt; EXECUTE stmt; -set @sqlstmt := if( @exist > 0, "SELECT 'Ok'", "ALTER TABLE Stats ADD FOREIGN KEY (MonitorId) REFERENCES Monitors (Id) ON DELETE CASCADE"); +set @sqlstmt := if( @exist = 0, "ALTER TABLE Stats ADD FOREIGN KEY (MonitorId) REFERENCES Monitors (Id) ON DELETE CASCADE", "SELECT '.'"); PREPARE stmt FROM @sqlstmt; EXECUTE stmt; -SELECT 'Adding foreign key for ZoneId to Stats'; set @exist := (select count(*) FROM information_schema.key_column_usage where table_name='Stats' and column_name='ZoneId' and referenced_table_name='Zones' and referenced_column_name='Id'); set @sqlstmt := if( @exist > 1, "SELECT 'You have more than 1 FOREIGN KEY. Please do manual cleanup'", "SELECT 'Ok'"); +set @sqlstmt := if( @exist = 1, "SELECT 'FOREIGN KEY for ZoneId in Stats already exists'", @sqlstmt); +set @sqlstmt := if( @exist = 0, "SELECT 'Adding foreign key for ZoneId to Stats'", @sqlstmt); PREPARE stmt FROM @sqlstmt; EXECUTE stmt; -set @sqlstmt := if( @exist > 0, "SELECT 'FOREIGN KEY for ZoneId in Stats already exists'", "DELETE FROM Stats WHERE ZoneId NOT IN (SELECT Id FROM Zones);"); +set @sqlstmt := if( @exist = 0, "SELECT 'Deleting unlinked Stats'", "SELECT 'Ok'"); PREPARE stmt FROM @sqlstmt; EXECUTE stmt; - -set @sqlstmt := if( @exist > 0, "SELECT 'Ok'", "ALTER TABLE Stats ADD FOREIGN KEY (ZoneId) REFERENCES Zones (Id) ON DELETE CASCADE"); +set @sqlstmt := if( @exist = 0, "DELETE FROM Stats WHERE ZoneId NOT IN (SELECT Id FROM Zones);", "SELECT '.'"); +PREPARE stmt FROM @sqlstmt; +EXECUTE stmt; +set @sqlstmt := if( @exist = 0, "ALTER TABLE Stats ADD FOREIGN KEY (ZoneId) REFERENCES Zones (Id) ON DELETE CASCADE", "SELECT '.'"); PREPARE stmt FROM @sqlstmt; EXECUTE stmt; SELECT 'Adding foreign key for MonitorId to Zones'; set @exist := (select count(*) FROM information_schema.key_column_usage where table_name='Zones' and column_name='MonitorId' and referenced_table_name='Monitors' and referenced_column_name='Id'); set @sqlstmt := if( @exist > 1, "SELECT 'You have more than 1 FOREIGN KEY. Please do manual cleanup'", "SELECT 'Ok'"); -PREPARE stmt FROM @sqlstmt; -EXECUTE stmt; +set @sqlstmt := if( @exist = 1, "SELECT 'FOREIGN KEY for MonitorId in Zones already exists'", @sqlstmnt); +set @sqlstmt := if( @exist = 0, "SELECT 'Adding foreign key for MonitorId in Zones'", @sqlstmnt); -set @sqlstmt := if( @exist > 0, "SELECT 'FOREIGN KEY for MonitorId in Zones already exists'", "SELECT 'FOREIGN KEY for MonitorId in Zones does not already exist'"); +/*"SELECT 'FOREIGN KEY for MonitorId in Zones does not already exist'");*/ set @badzones := (select count(*) FROM Zones WHERE MonitorId NOT IN (SELECT Id FROM Monitors)); set @sqlstmt := if ( @badzones > 0, "SELECT 'You have Zones with no Monitor record in the Monitors table. Please delete them manually'", "ALTER TABLE Zones ADD FOREIGN KEY (MonitorId) REFERENCES Monitors (Id)"); PREPARE stmt FROM @sqlstmt; From af399bb1748a184ceec36c354a6973a5fcc94b6f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Nov 2020 09:18:41 -0500 Subject: [PATCH 0570/2339] Reqiure Id to have a value not just be set --- web/skins/classic/views/filter.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/web/skins/classic/views/filter.php b/web/skins/classic/views/filter.php index bcf46e360..1ce614795 100644 --- a/web/skins/classic/views/filter.php +++ b/web/skins/classic/views/filter.php @@ -35,13 +35,12 @@ $filterNames = array(''=>translate('ChooseFilter')); $filter = NULL; $fid = 0; -if ( isset($_REQUEST['Id']) ) { +if ( isset($_REQUEST['Id']) and $_REQUEST['Id'] ) { $fid = validInt($_REQUEST['Id']); } else if ( isset($_REQUEST['filter[Id]']) ) { $fid = validInt($_REQUEST['filter[Id]']); - ZM\Warning("got fid by object id $fid"); } - +$filter = null; foreach ( ZM\Filter::find(null,array('order'=>'lower(Name)')) as $Filter ) { $filterNames[$Filter->Id()] = $Filter->Id() . ' ' . $Filter->Name(); if ( $Filter->Background() ) From 09fe354a22e8a64c31b2b3aa4b4b57c38acdda96 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Nov 2020 11:59:08 -0500 Subject: [PATCH 0571/2339] If event db insert fails, try again until it succeeds. --- src/zm_event.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index e762698fa..e48cb701e 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -106,12 +106,10 @@ Event::Event( storage->SchemeString().c_str() ); db_mutex.lock(); - if ( mysql_query(&dbconn, sql) ) { + while ( mysql_query(&dbconn, sql) ) { db_mutex.unlock(); Error("Can't insert event: %s. sql was (%s)", mysql_error(&dbconn), sql); - return; - } else { - Debug(2, "Created new event with %s", sql); + db_mutex.lock(); } id = mysql_insert_id(&dbconn); From 387b2b1fc20545149dfe27591427fc04fcb34e6d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Nov 2020 12:39:42 -0500 Subject: [PATCH 0572/2339] add attr validation to addTerm. Add addTerms --- web/includes/Filter.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/web/includes/Filter.php b/web/includes/Filter.php index 068ee628e..20a04c229 100644 --- a/web/includes/Filter.php +++ b/web/includes/Filter.php @@ -1,6 +1,7 @@ terms(); if ( (!isset($position)) or ($position > count($terms)) ) @@ -650,5 +656,12 @@ class Filter extends ZM_Object { return $this; } # end function addTerm + function addTerms($terms, $options=null) { + foreach ( $terms as $term ) { + $this->addTerm($term); + } + return $this; + } + } # end class Filter ?> From e67532ef76ac4d37c29f14ef62faa12e1e5b94ac Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Nov 2020 12:40:43 -0500 Subject: [PATCH 0573/2339] implement is_valid_attr. Fix incorrect EventDiskspace vs FS DiskSpace. FS DiskSpace isn't implemented. DiskPercent is. --- web/includes/FilterTerm.php | 67 +++++++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 11 deletions(-) diff --git a/web/includes/FilterTerm.php b/web/includes/FilterTerm.php index 4b2b1b78e..ebae24bb5 100644 --- a/web/includes/FilterTerm.php +++ b/web/includes/FilterTerm.php @@ -13,6 +13,7 @@ function getFilterQueryConjunctionTypes() { return $validConjunctionTypes; } + class FilterTerm { public $filter; public $index; @@ -35,7 +36,7 @@ class FilterTerm { $this->val = $term['val']; if ( isset($term['cnj']) ) { if ( array_key_exists($term['cnj'], $validConjunctionTypes) ) { - $this->cnj = $term['cnj']; + $this->cnj = $term['cnj']; } else { Warning('Invalid cnj ' . $term['cnj'].' in '.print_r($term, true)); } @@ -65,7 +66,8 @@ class FilterTerm { return $values; } - foreach ( preg_split('/["\'\s]*?,["\'\s]*?/', preg_replace('/^["\']+?(.+)["\']+?$/', '$1', $this->val)) as $value ) { + $vals = is_array($this->val) ? $this->val : preg_split('/["\'\s]*?,["\'\s]*?/', preg_replace('/^["\']+?(.+)["\']+?$/', '$1', $this->val)); + foreach ( $vals as $value ) { switch ( $this->attr ) { @@ -75,7 +77,7 @@ class FilterTerm { case 'ExistsInFileSystem': $value = ''; break; - case 'DiskSpace': + case 'DiskPercent': $value = ''; break; case 'MonitorName': @@ -83,7 +85,7 @@ class FilterTerm { case 'Name': case 'Cause': case 'Notes': - if ( $this->op == 'LIKE' || $this->op == 'NOT LIKE' ) { + if ( strstr($this->op, 'LIKE') and ! strstr($this->val, '%' ) ) { $value = '%'.$value.'%'; } $value = dbEscape($value); @@ -145,7 +147,7 @@ class FilterTerm { case 'AlarmZoneId': return ' EXISTS '; case 'ExistsInFileSystem': - case 'DiskSpace': + case 'DiskPercent': return ''; } @@ -202,7 +204,7 @@ class FilterTerm { switch ( $this->attr ) { case 'ExistsInFileSystem': - case 'DiskSpace': + case 'DiskPercent': $sql .= 'TRUE /*'.$this->attr.'*/'; break; case 'MonitorName': @@ -260,9 +262,10 @@ class FilterTerm { case 'EndWeekday': $sql .= 'weekday(E.EndTime)'; break; + case 'Emailed': case 'Id': case 'Name': - case 'EventDiskSpace': + case 'DiskSpace': case 'MonitorId': case 'StorageId': case 'SecondaryStorageId': @@ -400,21 +403,63 @@ class FilterTerm { } public function is_pre_sql() { - if ( $this->attr == 'DiskPercent' ) { + if ( $this->attr == 'DiskPercent' ) + return true; + if ( $this->attr == 'DiskBlocks' ) return true; - } return false; } public function is_post_sql() { if ( $this->attr == 'ExistsInFileSystem' ) { return true; - } else if ( $this->attr == 'DiskPercent' ) { - return true; } return false; } + public static function is_valid_attr($attr) { + $attrs = array( + 'ExistsInFileSystem', + 'Emailed', + 'DiskSpace', + 'DiskPercent', + 'DiskBlocks', + 'MonitorName', + 'ServerId', + 'MonitorServerId', + 'StorageServerId', + 'FilterServerId', + 'DateTime', + 'Date', + 'Time', + 'Weekday', + 'StartDateTime', + 'FramesEventId', + 'StartDate', + 'StartTime', + 'StartWeekday', + 'EndDateTime', + 'EndDate', + 'EndTime', + 'EndWeekday', + 'Id', + 'Name', + 'MonitorId', + 'StorageId', + 'SecondaryStorageId', + 'Length', + 'Frames', + 'AlarmFrames', + 'TotScore', + 'AvgScore', + 'MaxScore', + 'Cause', + 'Notes', + 'StateId', + 'Archived' + ); + return in_array($attr, $attrs); + } } # end class FilterTerm ?> From 4731041a40d56905c532a51e92efc15f09fa86f2 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Nov 2020 12:42:04 -0500 Subject: [PATCH 0574/2339] FS Storage DiskSpace isn't implemented. --- web/skins/classic/views/filter.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/views/filter.php b/web/skins/classic/views/filter.php index 1ce614795..fe90681b3 100644 --- a/web/skins/classic/views/filter.php +++ b/web/skins/classic/views/filter.php @@ -88,8 +88,8 @@ $attrTypes = array( 'Cause' => translate('AttrCause'), 'DiskBlocks' => translate('AttrDiskBlocks'), 'DiskPercent' => translate('AttrDiskPercent'), - 'DiskSpace' => translate('AttrDiskSpace'), - 'EventDiskSpace' => translate('AttrEventDiskSpace'), + #'StorageDiskSpace' => translate('AttrStorageDiskSpace'), + 'DiskSpace' => translate('AttrEventDiskSpace'), 'EndDateTime' => translate('AttrEndDateTime'), 'EndDate' => translate('AttrEndDate'), 'EndTime' => translate('AttrEndTime'), From adbd3486bfa26a58c5190ed7dcd9e3601aa3b730 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Nov 2020 13:49:39 -0500 Subject: [PATCH 0575/2339] Rename StartTime, EndTime in Events to StartDateTime and EndDateTime --- db/triggers.sql | 12 +++---- db/zm_create.sql.in | 24 ++++++------- scripts/ZoneMinder/lib/ZoneMinder/Event.pm | 26 +++++++------- scripts/ZoneMinder/lib/ZoneMinder/Filter.pm | 36 ++++++++++--------- scripts/ZoneMinder/lib/ZoneMinder/General.pm | 16 ++++----- scripts/zmaudit.pl.in | 38 ++++++++++---------- scripts/zmfilter.pl.in | 2 +- scripts/zmrecover.pl.in | 14 ++++---- scripts/zmstats.pl.in | 8 ++--- scripts/zmvideo.pl.in | 2 +- 10 files changed, 90 insertions(+), 88 deletions(-) diff --git a/db/triggers.sql b/db/triggers.sql index 87c8465b4..ad697be54 100644 --- a/db/triggers.sql +++ b/db/triggers.sql @@ -152,13 +152,13 @@ BEGIN SET ArchivedEvents = GREATEST(COALESCE(ArchivedEvents,0)-1,0), ArchivedEventDiskSpace = GREATEST(COALESCE(ArchivedEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0),0) - WHERE Id=OLD.MonitorId; + WHERE Monitors.Id=OLD.MonitorId; ELSE IF ( OLD.DiskSpace != NEW.DiskSpace ) THEN UPDATE Events_Archived SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; UPDATE Monitors SET ArchivedEventDiskSpace = GREATEST(COALESCE(ArchivedEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0) + COALESCE(NEW.DiskSpace,0),0) - WHERE Id=OLD.MonitorId; + WHERE Monitors.Id=OLD.MonitorId; END IF; END IF; ELSEIF ( NEW.Archived AND diff ) THEN @@ -185,10 +185,10 @@ CREATE TRIGGER event_insert_trigger AFTER INSERT ON Events FOR EACH ROW BEGIN - INSERT INTO Events_Hour (EventId,MonitorId,StartTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartTime,0); - INSERT INTO Events_Day (EventId,MonitorId,StartTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartTime,0); - INSERT INTO Events_Week (EventId,MonitorId,StartTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartTime,0); - INSERT INTO Events_Month (EventId,MonitorId,StartTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartTime,0); + INSERT INTO Events_Hour (EventId,MonitorId,StartDateTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartDateTime,0); + INSERT INTO Events_Day (EventId,MonitorId,StartDateTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartDateTime,0); + INSERT INTO Events_Week (EventId,MonitorId,StartDateTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartDateTime,0); + INSERT INTO Events_Month (EventId,MonitorId,StartDateTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartDateTime,0); UPDATE Monitors SET HourEvents = COALESCE(HourEvents,0)+1, DayEvents = COALESCE(DayEvents,0)+1, diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index 41ed75eba..40063a74c 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -189,8 +189,8 @@ CREATE TABLE `Events` ( `SecondaryStorageId` smallint(5) unsigned default 0, `Name` varchar(64) NOT NULL default '', `Cause` varchar(32) NOT NULL default '', - `StartTime` datetime default NULL, - `EndTime` datetime default NULL, + `StartDateTime` datetime default NULL, + `EndDateTime` datetime default NULL, `Width` smallint(5) unsigned NOT NULL default '0', `Height` smallint(5) unsigned NOT NULL default '0', `Length` decimal(10,2) NOT NULL default '0.00', @@ -216,52 +216,52 @@ CREATE TABLE `Events` ( PRIMARY KEY (`Id`), KEY `Events_MonitorId_idx` (`MonitorId`), KEY `Events_StorageId_idx` (`StorageId`), - KEY `Events_StartTime_idx` (`StartTime`), - KEY `Events_EndTime_DiskSpace` (`EndTime`,`DiskSpace`) + KEY `Events_StartDateTime_idx` (`StartDateTime`), + KEY `Events_EndDateTime_DiskSpace` (`EndDateTime`,`DiskSpace`) ) ENGINE=@ZM_MYSQL_ENGINE@; DROP TABLE IF EXISTS `Events_Hour`; CREATE TABLE `Events_Hour` ( `EventId` BIGINT unsigned NOT NULL, `MonitorId` int(10) unsigned NOT NULL, - `StartTime` datetime default NULL, + `StartDateTime` datetime default NULL, `DiskSpace` bigint default NULL, PRIMARY KEY (`EventId`), KEY `Events_Hour_MonitorId_idx` (`MonitorId`), - KEY `Events_Hour_StartTime_idx` (`StartTime`) + KEY `Events_Hour_StartDateTime_idx` (`StartDateTime`) ) ENGINE=@ZM_MYSQL_ENGINE@; DROP TABLE IF EXISTS `Events_Day`; CREATE TABLE `Events_Day` ( `EventId` BIGINT unsigned NOT NULL, `MonitorId` int(10) unsigned NOT NULL, - `StartTime` datetime default NULL, + `StartDateTime` datetime default NULL, `DiskSpace` bigint default NULL, PRIMARY KEY (`EventId`), KEY `Events_Day_MonitorId_idx` (`MonitorId`), - KEY `Events_Day_StartTime_idx` (`StartTime`) + KEY `Events_Day_StartDateTime_idx` (`StartDateTime`) ) ENGINE=@ZM_MYSQL_ENGINE@; DROP TABLE IF EXISTS `Events_Week`; CREATE TABLE `Events_Week` ( `EventId` BIGINT unsigned NOT NULL, `MonitorId` int(10) unsigned NOT NULL, - `StartTime` datetime default NULL, + `StartDateTime` datetime default NULL, `DiskSpace` bigint default NULL, PRIMARY KEY (`EventId`), KEY `Events_Week_MonitorId_idx` (`MonitorId`), - KEY `Events_Week_StartTime_idx` (`StartTime`) + KEY `Events_Week_StartDateTime_idx` (`StartDateTime`) ) ENGINE=@ZM_MYSQL_ENGINE@; DROP TABLE IF EXISTS `Events_Month`; CREATE TABLE `Events_Month` ( `EventId` BIGINT unsigned NOT NULL, `MonitorId` int(10) unsigned NOT NULL, - `StartTime` datetime default NULL, + `StartDateTime` datetime default NULL, `DiskSpace` bigint default NULL, PRIMARY KEY (`EventId`), KEY `Events_Month_MonitorId_idx` (`MonitorId`), - KEY `Events_Month_StartTime_idx` (`StartTime`) + KEY `Events_Month_StartDateTime_idx` (`StartDateTime`) ) ENGINE=@ZM_MYSQL_ENGINE@; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm index 985ac71f3..2664830dd 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm @@ -68,8 +68,8 @@ $serial = $primary_key = 'Id'; SecondaryStorageId Name Cause - StartTime - EndTime + StartDateTime + EndDateTime Width Height Length @@ -111,8 +111,8 @@ sub Time { $_[0]{Time} = $_[1]; } if ( ! defined $_[0]{Time} ) { - if ( $_[0]{StartTime} ) { - $_[0]{Time} = Date::Parse::str2time( $_[0]{StartTime} ); + if ( $_[0]{StartDateTime} ) { + $_[0]{Time} = Date::Parse::str2time( $_[0]{StartDateTime} ); } } return $_[0]{Time}; @@ -364,11 +364,11 @@ sub delete { my $in_zmaudit = ( $0 =~ 'zmaudit.pl$'); if ( ! $in_zmaudit ) { - if ( ! ( $event->{Id} and $event->{MonitorId} and $event->{StartTime} ) ) { + if ( ! ( $event->{Id} and $event->{MonitorId} and $event->{StartDateTime} ) ) { # zmfilter shouldn't delete anything in an odd situation. zmaudit will though. my ( $caller, undef, $line ) = caller; - Warning("$0 Can't Delete event $event->{Id} from Monitor $event->{MonitorId} StartTime:". - (defined($event->{StartTime})?$event->{StartTime}:'undef')." from $caller:$line"); + Warning("$0 Can't Delete event $event->{Id} from Monitor $event->{MonitorId} StartDateTime:". + (defined($event->{StartDateTime})?$event->{StartDateTime}:'undef')." from $caller:$line"); return; } if ( !($event->Storage()->Path() and -e $event->Storage()->Path()) ) { @@ -379,7 +379,7 @@ sub delete { if ( $$event{Id} ) { # Need to have an event Id if we are to delete from the db. - Info("Deleting event $event->{Id} from Monitor $event->{MonitorId} StartTime:$event->{StartTime} from ".$event->Path()); + Info("Deleting event $event->{Id} from Monitor $event->{MonitorId} StartDateTime:$event->{StartDateTime} from ".$event->Path()); $ZoneMinder::Database::dbh->ping(); my $in_transaction = $ZoneMinder::Database::dbh->{AutoCommit} ? 0 : 1; @@ -820,9 +820,9 @@ sub recover_timestamps { my $duration = $last_timestamp - $first_timestamp; $Event->Length($duration); - $Event->StartTime( Date::Format::time2str('%Y-%m-%d %H:%M:%S', $first_timestamp) ); - $Event->EndTime( Date::Format::time2str('%Y-%m-%d %H:%M:%S', $last_timestamp) ); - Debug("From capture Jpegs have duration $duration = $last_timestamp - $first_timestamp : $$Event{StartTime} to $$Event{EndTime}"); + $Event->StartDateTime( Date::Format::time2str('%Y-%m-%d %H:%M:%S', $first_timestamp) ); + $Event->EndDateTime( Date::Format::time2str('%Y-%m-%d %H:%M:%S', $last_timestamp) ); + Debug("From capture Jpegs have duration $duration = $last_timestamp - $first_timestamp : $$Event{StartDateTime} to $$Event{EndDateTime}"); $ZoneMinder::Database::dbh->begin_work(); foreach my $jpg ( @capture_jpgs ) { my ( $id ) = $jpg =~ /^(\d+)\-capture\.jpg$/; @@ -858,8 +858,8 @@ sub recover_timestamps { } my $seconds = ($h*60*60)+($m*60)+$s; $Event->Length($seconds.'.'.$u); - $Event->StartTime( Date::Format::time2str('%Y-%m-%d %H:%M:%S', $first_timestamp) ); - $Event->EndTime( Date::Format::time2str('%Y-%m-%d %H:%M:%S', $first_timestamp+$seconds) ); + $Event->StartDateTime( Date::Format::time2str('%Y-%m-%d %H:%M:%S', $first_timestamp) ); + $Event->EndDateTime( Date::Format::time2str('%Y-%m-%d %H:%M:%S', $first_timestamp+$seconds) ); } if ( @mp4_files ) { $Event->DefaultVideo($mp4_files[0]); diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm index 85c09b141..eb1b36077 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm @@ -149,7 +149,7 @@ sub Sql { my $filter_expr = ZoneMinder::General::jsonDecode($self->{Query_json}); my $sql = 'SELECT E.*, - unix_timestamp(E.StartTime) as Time, + unix_timestamp(E.StartDateTime) as Time, M.Name as MonitorName, M.DefaultRate, M.DefaultScale @@ -184,27 +184,25 @@ sub Sql { $self->{Sql} .= $Config{ZM_SERVER_ID}; # StartTime options } elsif ( $term->{attr} eq 'DateTime' ) { - $self->{Sql} .= 'E.StartTime'; - } elsif ( $term->{attr} eq 'StartDateTime' ) { - $self->{Sql} .= 'E.StartTime'; + $self->{Sql} .= 'E.StartDateTime'; } elsif ( $term->{attr} eq 'Date' ) { - $self->{Sql} .= 'to_days( E.StartTime )'; + $self->{Sql} .= 'to_days( E.StartDateTime )'; } elsif ( $term->{attr} eq 'StartDate' ) { - $self->{Sql} .= 'to_days( E.StartTime )'; + $self->{Sql} .= 'to_days( E.StartDateTime )'; } elsif ( $term->{attr} eq 'Time' or $term->{attr} eq 'StartTime' ) { - $self->{Sql} .= 'extract( hour_second from E.StartTime )'; + $self->{Sql} .= 'extract( hour_second from E.StartDateTime )'; } elsif ( $term->{attr} eq 'Weekday' or $term->{attr} eq 'StartWeekday' ) { - $self->{Sql} .= 'weekday( E.StartTime )'; + $self->{Sql} .= 'weekday( E.StartDateTime )'; # EndTIme options } elsif ( $term->{attr} eq 'EndDateTime' ) { - $self->{Sql} .= 'E.EndTime'; + $self->{Sql} .= 'E.EndDateTime'; } elsif ( $term->{attr} eq 'EndDate' ) { - $self->{Sql} .= 'to_days( E.EndTime )'; - } elsif ( $term->{attr} eq 'EndTime' ) { - $self->{Sql} .= 'extract( hour_second from E.EndTime )'; + $self->{Sql} .= 'to_days( E.EndDateTime )'; + } elsif ( $term->{attr} eq 'EndDateTime' ) { + $self->{Sql} .= 'extract( hour_second from E.EndDateTime )'; } elsif ( $term->{attr} eq 'EndWeekday' ) { - $self->{Sql} .= "weekday( E.EndTime )"; + $self->{Sql} .= "weekday( E.EndDateTime )"; } elsif ( $term->{attr} eq 'ExistsInFileSystem' ) { push @{$self->{PostSQLConditions}}, $term; $self->{Sql} .= 'TRUE /* ExistsInFileSystem */'; @@ -368,7 +366,7 @@ sub Sql { $sql .= ' AND ( '.join(' or ', @auto_terms).' )'; } if ( !$filter_expr->{sort_field} ) { - $filter_expr->{sort_field} = 'StartTime'; + $filter_expr->{sort_field} = 'StartDateTime'; $filter_expr->{sort_asc} = 0; } my $sort_column = ''; @@ -378,10 +376,14 @@ sub Sql { $sort_column = 'M.Name'; } elsif ( $filter_expr->{sort_field} eq 'Name' ) { $sort_column = 'E.Name'; + } elsif ( $filter_expr->{sort_field} eq 'StartDateTime' ) { + $sort_column = 'E.StartDateTime'; } elsif ( $filter_expr->{sort_field} eq 'StartTime' ) { - $sort_column = 'E.StartTime'; + $sort_column = 'E.StartDateTime'; } elsif ( $filter_expr->{sort_field} eq 'EndTime' ) { - $sort_column = 'E.EndTime'; + $sort_column = 'E.EndDateTime'; + } elsif ( $filter_expr->{sort_field} eq 'EndDateTime' ) { + $sort_column = 'E.EndDateTime'; } elsif ( $filter_expr->{sort_field} eq 'Secs' ) { $sort_column = 'E.Length'; } elsif ( $filter_expr->{sort_field} eq 'Frames' ) { @@ -397,7 +399,7 @@ sub Sql { } elsif ( $filter_expr->{sort_field} eq 'DiskSpace' ) { $sort_column = 'E.DiskSpace'; } else { - $sort_column = 'E.StartTime'; + $sort_column = 'E.StartDateTime'; } my $sort_order = $filter_expr->{sort_asc} ? 'ASC' : 'DESC'; $sql .= ' ORDER BY '.$sort_column.' '.$sort_order; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/General.pm b/scripts/ZoneMinder/lib/ZoneMinder/General.pm index 0d3784185..d68967fa9 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/General.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/General.pm @@ -262,21 +262,21 @@ sub createEvent { } $frame->{Type} = $frame->{Score}>0?'Alarm':'Normal' unless( $frame->{Type} ); $frame->{Delta} = $lastTimestamp?($frame->{TimeStamp}-$lastTimestamp):0.0; - $event->{StartTime} = $frame->{TimeStamp} unless ( $event->{StartTime} ); + $event->{StartDateTime} = $frame->{TimeStamp} unless ( $event->{StartDateTime} ); $event->{TotScore} += $frame->{Score}; $event->{MaxScore} = $frame->{Score} if ( $frame->{Score} > $event->{MaxScore} ); $event->{AlarmFrames}++ if ( $frame->{Type} eq 'Alarm' ); - $event->{EndTime} = $frame->{TimeStamp}; + $event->{EndDateTime} = $frame->{TimeStamp}; $lastTimestamp = $frame->{TimeStamp}; } $event->{Width} = $event->{monitor}->{Width} unless( $event->{Width} ); $event->{Height} = $event->{monitor}->{Height} unless( $event->{Height} ); $event->{AvgScore} = $event->{TotScore}/int($event->{AlarmFrames}); - $event->{Length} = $event->{EndTime} - $event->{StartTime}; + $event->{Length} = $event->{EndDateTime} - $event->{StartDateTime}; my %formats = ( - StartTime => 'from_unixtime(?)', - EndTime => 'from_unixtime(?)', + StartDateTime => 'from_unixtime(?)', + EndDateTime => 'from_unixtime(?)', ); my ( @fields, @formats, @values ); @@ -297,7 +297,7 @@ sub createEvent { $event->{Id} = $dbh->{mysql_insertid}; Info( "Created event ".$event->{Id} ); - if ( $event->{EndTime} ) { + if ( $event->{EndDateTime} ) { $event->{Name} = $event->{monitor}->{EventPrefix}.$event->{Id} if ( $event->{Name} eq 'New Event' ); my $sql = "update Events set Name = ? where Id = ?"; @@ -383,8 +383,8 @@ sub updateEvent { if ( $event->{Name} eq 'New Event' ); my %formats = ( - StartTime => 'from_unixtime(?)', - EndTime => 'from_unixtime(?)', + StartDateTime => 'from_unixtime(?)', + EndDateTime => 'from_unixtime(?)', ); my ( @values, @sets ); diff --git a/scripts/zmaudit.pl.in b/scripts/zmaudit.pl.in index 80a227e2b..4601ea1aa 100644 --- a/scripts/zmaudit.pl.in +++ b/scripts/zmaudit.pl.in @@ -205,7 +205,7 @@ MAIN: while( $loop ) { 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 + my $eventSelectSql = 'SELECT `Id`, (unix_timestamp() - unix_timestamp(`StartDateTime`)) AS Age FROM `Events` WHERE `MonitorId` = ?'.(@Storage_Areas ? ' AND `StorageId` IN ('.join(',',map { '?'} @Storage_Areas).')' : '' ). ' ORDER BY `Id`'; my $eventSelectSth = $dbh->prepare_cached( $eventSelectSql ) or Fatal( "Can't prepare '$eventSelectSql': ".$dbh->errstr() ); @@ -397,13 +397,13 @@ MAIN: while( $loop ) { my ( undef, $year, $month, $day ) = split('/', $day_dir); $year += 2000; my ( $hour, $minute, $second ) = split('/', $event_dir); - my $StartTime =sprintf('%.4d-%.2d-%.2d %.2d:%.2d:%.2d', $year, $month, $day, $hour, $minute, $second); + my $StartDateTime =sprintf('%.4d-%.2d-%.2d %.2d:%.2d:%.2d', $year, $month, $day, $hour, $minute, $second); my $Event = ZoneMinder::Event->find_one( MonitorId=>$monitor_dir, - StartTime=>$StartTime, + StartDateTime=>$StartDateTime, ); if ( $Event ) { - Debug("Found event matching starttime on monitor $monitor_dir at $StartTime: " . $Event->to_string()); + Debug("Found event matching StartDateTime on monitor $monitor_dir at $StartDateTime: " . $Event->to_string()); next; } aud_print("Deleting event directories with no event id information at $day_dir/$event_dir"); @@ -440,7 +440,7 @@ MAIN: while( $loop ) { $Event->Path(); $Event->age(); Debug("Have event $$Event{Id} at $$Event{Path}"); - $Event->StartTime(POSIX::strftime('%Y-%m-%d %H:%M:%S', gmtime(time_of_youngest_file($Event->Path())))); + $Event->StartDateTime(POSIX::strftime('%Y-%m-%d %H:%M:%S', gmtime(time_of_youngest_file($Event->Path())))); } # end foreach event } @@ -592,7 +592,7 @@ EVENT: while ( my ( $db_event, $age ) = each( %$db_events ) ) { Warning("Event $$Event{Id} is Archived. Taking no further action on it."); next; } - if ( !$Event->StartTime() ) { + if ( !$Event->StartDateTime() ) { aud_print("Event $$Event{Id} has no start time."); if ( confirm() ) { $Event->delete(); @@ -600,7 +600,7 @@ EVENT: while ( my ( $db_event, $age ) = each( %$db_events ) ) { } next; } - if ( ! $Event->EndTime() ) { + if ( ! $Event->EndDateTime() ) { if ( $age > $Config{ZM_AUDIT_MIN_AGE} ) { aud_print("Event $$Event{Id} has no end time and is $age seconds old. Deleting it."); if ( confirm() ) { @@ -639,9 +639,9 @@ EVENT: while ( my ( $db_event, $age ) = each( %$db_events ) ) { Info("Updating storage area on event $$Event{Id} from $$Event{StorageId} to $$fs_events{$db_event}{StorageId}"); $Event->StorageId($$fs_events{$db_event}->StorageId()); } - if ( ! $Event->StartTime() ) { - Info("Updating StartTime on event $$Event{Id} from $$Event{StartTime} to $$fs_events{$db_event}{StartTime}"); - $Event->StartTime($$fs_events{$db_event}->StartTime()); + if ( ! $Event->StartDateTime() ) { + Info("Updating StartDateTime on event $$Event{Id} from $$Event{StartDateTime} to $$fs_events{$db_event}{StartDateTime}"); + $Event->StartDateTime($$fs_events{$db_event}->StartDateTime()); } $Event->save(); @@ -683,12 +683,12 @@ if ( $level > 1 ) { # Remove empty events (with no frames) $cleaned = 0; Debug("Checking for Events with no Frames"); - 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 $selectEmptyEventsSql = 'SELECT `E`.`Id` AS `Id`, `E`.`StartDateTime`, `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`.`StartDateTime`'; if ( my $selectEmptyEventsSth = $dbh->prepare_cached( $selectEmptyEventsSql ) ) { if ( $res = $selectEmptyEventsSth->execute() ) { while( my $event = $selectEmptyEventsSth->fetchrow_hashref() ) { - aud_print("Found empty event with no frame records '$event->{Id}' at $$event{StartTime}"); + aud_print("Found empty event with no frame records '$event->{Id}' at $$event{StartDateTime}"); if ( confirm() ) { if ( $res = $deleteEventSth->execute($event->{Id}) ) { $cleaned = 1; @@ -750,7 +750,7 @@ if ( $level > 1 ) { #"SELECT E.Id, ANY_VALUE(E.MonitorId), # #max(F.TimeStamp) as EndTime, -#unix_timestamp(max(F.TimeStamp)) - unix_timestamp(E.StartTime) as Length, +#unix_timestamp(max(F.TimeStamp)) - unix_timestamp(E.StartDateTime) as Length, #max(F.FrameId) as Frames, #count(if(F.Score>0,1,NULL)) as AlarmFrames, #sum(F.Score) as TotScore, @@ -760,11 +760,11 @@ if ( $level > 1 ) { #WHERE isnull(E.Frames) or isnull(E.EndTime) #GROUP BY E.Id HAVING EndTime < (now() - interval ".$Config{ZM_AUDIT_MIN_AGE}.' second)' #; - 'SELECT *, unix_timestamp(`StartTime`) AS `TimeStamp` FROM `Events` WHERE `EndTime` IS NULL AND `StartTime` < (now() - interval '.$Config{ZM_AUDIT_MIN_AGE}.' second)'.($monitor_id?' AND MonitorId=?':''); + 'SELECT *, unix_timestamp(`StartDateTime`) AS `TimeStamp` FROM `Events` WHERE `EndDateTime` IS NULL AND `StartDateTime` < (now() - interval '.$Config{ZM_AUDIT_MIN_AGE}.' second)'.($monitor_id?' AND MonitorId=?':''); my $selectFrameDataSql = ' SELECT - max(`TimeStamp`) AS `EndTime`, + max(`TimeStamp`) AS `EndDateTime`, unix_timestamp(max(`TimeStamp`)) AS `EndTimeStamp`, max(`FrameId`) AS `Frames`, count(if(`Score`>0,1,NULL)) AS `AlarmFrames`, @@ -779,7 +779,7 @@ FROM `Frames` WHERE `EventId`=?'; my $updateUnclosedEventsSql = "UPDATE low_priority `Events` SET `Name` = ?, - `EndTime` = ?, + `EndDateTime` = ?, `Length` = ?, `Frames` = ?, `AlarmFrames` = ?, @@ -794,7 +794,7 @@ FROM `Frames` WHERE `EventId`=?'; $res = $selectUnclosedEventsSth->execute($monitor_id?$monitor_id:()) or Fatal("Can't execute: ".$selectUnclosedEventsSth->errstr()); while( my $event = $selectUnclosedEventsSth->fetchrow_hashref() ) { - aud_print("Found open event '$event->{Id}' on Monitor $event->{MonitorId} at $$event{StartTime}"); + aud_print("Found open event '$event->{Id}' on Monitor $event->{MonitorId} at $$event{StartDateTime}"); if ( confirm('close', 'closing') ) { if ( ! ( $res = $selectFrameDataSth->execute($event->{Id}) ) ) { Error("Can't execute: $selectFrameDataSql:".$selectFrameDataSth->errstr()); @@ -808,7 +808,7 @@ FROM `Frames` WHERE `EventId`=?'; $event->{Id}, RECOVER_TAG ), - $frame->{EndTime}, + $frame->{EndDateTime}, $frame->{EndTimeStamp} - $event->{TimeStamp}, $frame->{Frames}, $frame->{AlarmFrames}, diff --git a/scripts/zmfilter.pl.in b/scripts/zmfilter.pl.in index 5540e6944..834da99f8 100644 --- a/scripts/zmfilter.pl.in +++ b/scripts/zmfilter.pl.in @@ -704,7 +704,7 @@ sub substituteTags { $text =~ s/%EN%/$Event->{Name}/g; $text =~ s/%EC%/$Event->{Cause}/g; $text =~ s/%ED%/$Event->{Notes}/g; - $text =~ s/%ET%/$Event->{StartTime}/g; + $text =~ s/%ET%/$Event->{StartDateTime}/g; $text =~ s/%EVF%/$$Event{DefaultVideo}/g; # Event video filename $text =~ s/%EL%/$Event->{Length}/g; $text =~ s/%EF%/$Event->{Frames}/g; diff --git a/scripts/zmrecover.pl.in b/scripts/zmrecover.pl.in index 58647b946..c52537b4e 100644 --- a/scripts/zmrecover.pl.in +++ b/scripts/zmrecover.pl.in @@ -231,7 +231,7 @@ Debug("@Monitors"); $Event->Height( $Monitor->Height() ); $Event->Orientation( $Monitor->Orientation() ); $Event->recover_timestamps(); - if ( $$Event{StartTime} ) { + if ( $$Event{StartDateTime} ) { $Event->save({}, 1); Info("Event resurrected as " . $Event->to_string() ); } else { @@ -294,7 +294,7 @@ Debug("@Monitors"); $Event->StorageId( $Storage->Id() ); $Event->DiskSpace( undef ); $Event->recover_timestamps(); - if ( $$Event{StartTime} ) { + if ( $$Event{StartDateTime} ) { $Event->save({}, 1); Info("Event resurrected as " . $Event->to_string() ); } else { @@ -309,13 +309,13 @@ Debug("@Monitors"); my ( undef, $year, $month, $day ) = split('/', $day_dir); $year += 2000; my ( $hour, $minute, $second ) = split('/', $event_dir); - my $StartTime =sprintf('%.4d-%.2d-%.2d %.2d:%.2d:%.2d', $year, $month, $day, $hour, $minute, $second); + my $StartDateTime =sprintf('%.4d-%.2d-%.2d %.2d:%.2d:%.2d', $year, $month, $day, $hour, $minute, $second); my $Event = ZoneMinder::Event->find_one( MonitorId=>$monitor_dir, - StartTime=>$StartTime, + StartDateTime=>$StartDateTime, ); if ( $Event ) { - Debug("Found event matching starttime on monitor $monitor_dir at $StartTime: " . $Event->to_string()); + Debug("Found event matching starttime on monitor $monitor_dir at $StartDateTime: " . $Event->to_string()); next; } @@ -358,7 +358,7 @@ Debug("@Monitors"); $Event->Orientation( $Monitor->Orientation() ); $Event->StorageId( $Storage->Id() ); $Event->recover_timestamps(); - if ( $$Event{StartTime} ) { + if ( $$Event{StartDateTime} ) { $Event->save({}, 1); Info("Event resurrected as " . $Event->to_string() ); } else { @@ -400,7 +400,7 @@ Debug("@Monitors"); $Event->Orientation( $Monitor->Orientation() ); $Event->StorageId( $Storage->Id() ); $Event->recover_timestamps(); - if ( $$Event{StartTime} ) { + if ( $$Event{StartDateTime} ) { $Event->save({}, 1); Info("Event resurrected as " . $Event->to_string() ); } else { diff --git a/scripts/zmstats.pl.in b/scripts/zmstats.pl.in index 555d9c602..8aef4ddc6 100644 --- a/scripts/zmstats.pl.in +++ b/scripts/zmstats.pl.in @@ -43,10 +43,10 @@ while( 1 ) { } } - $dbh->do('DELETE FROM Events_Hour WHERE StartTime < DATE_SUB(NOW(), INTERVAL 1 hour)') or Error($dbh->errstr()); - $dbh->do('DELETE FROM Events_Day WHERE StartTime < DATE_SUB(NOW(), INTERVAL 1 day)') or Error($dbh->errstr()); - $dbh->do('DELETE FROM Events_Week WHERE StartTime < DATE_SUB(NOW(), INTERVAL 1 week)') or Error($dbh->errstr()); - $dbh->do('DELETE FROM Events_Month WHERE StartTime < DATE_SUB(NOW(), INTERVAL 1 month)') or Error($dbh->errstr()); + $dbh->do('DELETE FROM Events_Hour WHERE StartDateTime < DATE_SUB(NOW(), INTERVAL 1 hour)') or Error($dbh->errstr()); + $dbh->do('DELETE FROM Events_Day WHERE StartDateTime < DATE_SUB(NOW(), INTERVAL 1 day)') or Error($dbh->errstr()); + $dbh->do('DELETE FROM Events_Week WHERE StartDateTime < DATE_SUB(NOW(), INTERVAL 1 week)') or Error($dbh->errstr()); + $dbh->do('DELETE FROM Events_Month WHERE StartDateTime < DATE_SUB(NOW(), INTERVAL 1 month)') or Error($dbh->errstr()); # Prune the Logs table if required if ( $Config{ZM_LOG_DATABASE_LIMIT} ) { diff --git a/scripts/zmvideo.pl.in b/scripts/zmvideo.pl.in index 04cfabb04..c676eb164 100644 --- a/scripts/zmvideo.pl.in +++ b/scripts/zmvideo.pl.in @@ -201,7 +201,7 @@ if ( $event_id ) { my $sql = " SELECT (SELECT max(Delta) FROM Frames WHERE EventId=Events.Id)-(SELECT min(Delta) FROM Frames WHERE EventId=Events.Id) as FullLength, Events.*, - unix_timestamp(Events.StartTime) as Time, + unix_timestamp(Events.StartDateTime) as Time, M.Name as MonitorName, M.Palette FROM Events From 33f58add118001bf6ad703845397f5c07448c15f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Nov 2020 13:49:47 -0500 Subject: [PATCH 0576/2339] Rename StartTime, EndTime in Events to StartDateTime and EndDateTime --- src/zm_event.cpp | 8 ++++---- src/zm_eventstream.cpp | 6 +++--- src/zm_monitor.cpp | 1 - 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index e48cb701e..cd7ba1918 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -71,7 +71,7 @@ Event::Event( start_time = now; } else if ( start_time.tv_sec > now.tv_sec ) { Error( - "StartTime in the future %u.%u > %u.%u", + "StartDateTime in the future %u.%u > %u.%u", start_time.tv_sec, start_time.tv_usec, now.tv_sec, now.tv_usec ); start_time = now; @@ -89,7 +89,7 @@ Event::Event( char sql[ZM_SQL_MED_BUFSIZ]; struct tm *stime = localtime(&start_time.tv_sec); snprintf(sql, sizeof(sql), "INSERT INTO Events " - "( MonitorId, StorageId, Name, StartTime, Width, Height, Cause, Notes, StateId, Orientation, Videoed, DefaultVideo, SaveJPEGs, Scheme )" + "( MonitorId, StorageId, Name, StartDateTime, Width, Height, Cause, Notes, StateId, Orientation, Videoed, DefaultVideo, SaveJPEGs, Scheme )" " VALUES ( %u, %u, 'New Event', from_unixtime( %ld ), %u, %u, '%s', '%s', %u, %d, %d, '%s', %d, '%s' )", monitor->Id(), storage->Id(), @@ -289,7 +289,7 @@ Event::~Event() { // Should not be static because we might be multi-threaded char sql[ZM_SQL_LGE_BUFSIZ]; snprintf(sql, sizeof(sql), - "UPDATE Events SET Name='%s%" PRIu64 "', EndTime = from_unixtime(%ld), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d WHERE Id = %" PRIu64 " AND Name='New Event'", + "UPDATE Events SET Name='%s%" PRIu64 "', EndDateTime = from_unixtime(%ld), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d WHERE Id = %" PRIu64 " AND Name='New Event'", monitor->EventPrefix(), id, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, frames, alarm_frames, @@ -305,7 +305,7 @@ Event::~Event() { if ( !mysql_affected_rows(&dbconn) ) { // Name might have been changed during recording, so just do the update without changing the name. snprintf(sql, sizeof(sql), - "UPDATE Events SET EndTime = from_unixtime(%ld), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d WHERE Id = %" PRIu64, + "UPDATE Events SET EndDateTime = from_unixtime(%ld), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d WHERE Id = %" PRIu64, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, frames, alarm_frames, diff --git a/src/zm_eventstream.cpp b/src/zm_eventstream.cpp index 6f2ba4197..2c8ec7c08 100644 --- a/src/zm_eventstream.cpp +++ b/src/zm_eventstream.cpp @@ -45,7 +45,7 @@ bool EventStream::loadInitialEventData(int monitor_id, time_t event_time) { static char sql[ZM_SQL_SML_BUFSIZ]; snprintf(sql, sizeof(sql), "SELECT `Id` FROM `Events` WHERE " - "`MonitorId` = %d AND unix_timestamp(`EndTime`) > %ld " + "`MonitorId` = %d AND unix_timestamp(`EndDateTime`) > %ld " "ORDER BY `Id` ASC LIMIT 1", monitor_id, event_time); if ( mysql_query(&dbconn, sql) ) { @@ -116,8 +116,8 @@ bool EventStream::loadEventData(uint64_t event_id) { static char sql[ZM_SQL_MED_BUFSIZ]; snprintf(sql, sizeof(sql), - "SELECT `MonitorId`, `StorageId`, `Frames`, unix_timestamp( `StartTime` ) AS StartTimestamp, " - "unix_timestamp( `EndTime` ) AS EndTimestamp, " + "SELECT `MonitorId`, `StorageId`, `Frames`, unix_timestamp( `StartDateTime` ) AS StartTimestamp, " + "unix_timestamp( `EndDateTime` ) AS EndTimestamp, " "(SELECT max(`Delta`)-min(`Delta`) FROM `Frames` WHERE `EventId`=`Events`.`Id`) AS Duration, " "`DefaultVideo`, `Scheme`, `SaveJPEGs`, `Orientation`+0 FROM `Events` WHERE `Id` = %" PRIu64, event_id); diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 231b02916..937a4bf3a 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1613,7 +1613,6 @@ bool Monitor::Analyse() { } // end if analysis_fps && pre_event_count shared_data->last_event = event->Id(); - //set up video store data snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "%s", event->getEventFile()); video_store_data->recording = event->StartTime(); From 0d404ac66f0db739dc8ee8e56877e5b122691783 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Nov 2020 13:50:45 -0500 Subject: [PATCH 0577/2339] Rename StartTime, EndTime in Events to StartDateTime and EndDateTime --- web/skins/classic/views/events.php | 4 ++-- web/skins/classic/views/js/events.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/web/skins/classic/views/events.php b/web/skins/classic/views/events.php index 555f13f51..86376d6b4 100644 --- a/web/skins/classic/views/events.php +++ b/web/skins/classic/views/events.php @@ -104,8 +104,8 @@ getBodyTopHTML(); - - + + diff --git a/web/skins/classic/views/js/events.js b/web/skins/classic/views/js/events.js index 20bf6b87f..7d4c67369 100644 --- a/web/skins/classic/views/js/events.js +++ b/web/skins/classic/views/js/events.js @@ -17,14 +17,14 @@ var params = "data": { "search":"some search text", - "sort":"StartTime", + "sort":"StartDateTime", "order":"asc", "offset":0, "limit":25 "filter": { "Name":"some advanced search text" - "StartTime":"some more advanced search text" + "StartDateTime":"some more advanced search text" } }, "cache":true, From 2d33dd5386dca643b719d57e3f360278e2eb98a6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Nov 2020 13:52:32 -0500 Subject: [PATCH 0578/2339] Rename StartTime, EndTime in Events to StartDateTime and EndDateTime --- web/includes/Event.php | 16 ++++++++-------- web/includes/Filter.php | 16 ++++++++-------- web/includes/FilterTerm.php | 24 ++++++++++++------------ 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/web/includes/Event.php b/web/includes/Event.php index 70eb27d8c..4e218edb2 100644 --- a/web/includes/Event.php +++ b/web/includes/Event.php @@ -14,8 +14,8 @@ class Event extends ZM_Object { 'StorageId' => null, 'SecondaryStorageId' => null, 'Cause' => '', - 'StartTime' => null, - 'EndTime' => null, + 'StartDateTime' => null, + 'EndDateTime' => null, 'Width' => null, 'Height' => null, 'Length' => null, @@ -93,7 +93,7 @@ class Event extends ZM_Object { public function Time() { if ( ! isset($this->{'Time'}) ) { - $this->{'Time'} = strtotime($this->{'StartTime'}); + $this->{'Time'} = strtotime($this->{'StartDateTime'}); } return $this->{'Time'}; } @@ -153,9 +153,9 @@ class Event extends ZM_Object { if ( $this->{'Scheme'} == 'Deep' ) { # Assumption: All events have a start time - $start_date = date_parse($this->{'StartTime'}); + $start_date = date_parse($this->{'StartDateTime'}); if ( ! $start_date ) { - throw new Exception('Unable to parse start time for event ' . $this->{'Id'} . ' not deleting files.'); + throw new Exception('Unable to parse start date time for event ' . $this->{'Id'} . ' not deleting files.'); } $start_date['year'] = $start_date['year'] % 100; @@ -279,7 +279,7 @@ class Event extends ZM_Object { } if ( (!property_exists($this, 'DiskSpace')) or (null === $this->{'DiskSpace'}) ) { $this->{'DiskSpace'} = folder_size($this->Path()); - if ( $this->{'EndTime'} ) { + if ( $this->{'EndDateTime'} ) { # Finished events shouldn't grow in size much so we can commit it to the db. dbQuery('UPDATE Events SET DiskSpace=? WHERE Id=?', array($this->{'DiskSpace'}, $this->{'Id'})); } @@ -606,7 +606,7 @@ class Event extends ZM_Object { if ( $this->Archived() ) { return false; } - if ( !$this->EndTime() ) { + if ( !$this->EndDateTime() ) { return false; } if ( !canEdit('Events') ) { @@ -619,7 +619,7 @@ class Event extends ZM_Object { public function cant_delete_reason() { if ( $this->Archived() ) { return 'You cannot delete an archived event. Unarchive it first.'; - } else if ( ! $this->EndTime() ) { + } else if ( ! $this->EndDateTime() ) { return 'You cannot delete an event while it is being recorded. Wait for it to finish.'; } else if ( ! canEdit('Events') ) { return 'You do not have rights to edit Events.'; diff --git a/web/includes/Filter.php b/web/includes/Filter.php index 20a04c229..84941dbeb 100644 --- a/web/includes/Filter.php +++ b/web/includes/Filter.php @@ -392,35 +392,35 @@ class Filter extends ZM_Object { break; case 'DateTime': case 'StartDateTime': - $sqlValue = 'E.StartTime'; + $sqlValue = 'E.StartDateTime'; $dtAttr = true; break; case 'Date': case 'StartDate': - $sqlValue = 'to_days(E.StartTime)'; + $sqlValue = 'to_days(E.StartDateTime)'; $dtAttr = true; break; case 'Time': case 'StartTime': - $sqlValue = 'extract(hour_second from E.StartTime)'; + $sqlValue = 'extract(hour_second from E.StartDateTime)'; break; case 'Weekday': case 'StartWeekday': - $sqlValue = 'weekday(E.StartTime)'; + $sqlValue = 'weekday(E.StartDateTime)'; break; case 'EndDateTime': - $sqlValue = 'E.EndTime'; + $sqlValue = 'E.EndDateTime'; $dtAttr = true; break; case 'EndDate': - $sqlValue = 'to_days(E.EndTime)'; + $sqlValue = 'to_days(E.EndDateTime)'; $dtAttr = true; break; case 'EndTime': - $sqlValue = 'extract(hour_second from E.EndTime)'; + $sqlValue = 'extract(hour_second from E.EndDateTime)'; break; case 'EndWeekday': - $sqlValue = 'weekday(E.EndTime)'; + $sqlValue = 'weekday(E.EndDateTime)'; break; case 'Id': case 'Name': diff --git a/web/includes/FilterTerm.php b/web/includes/FilterTerm.php index ebae24bb5..6b41a2e1d 100644 --- a/web/includes/FilterTerm.php +++ b/web/includes/FilterTerm.php @@ -222,45 +222,45 @@ class FilterTerm { break; # Unspecified start or end, so assume start, this is to support legacy filters case 'DateTime': - $sql .= 'E.StartTime'; + $sql .= 'E.StartDateTime'; break; case 'Date': - $sql .= 'to_days(E.StartTime)'; + $sql .= 'to_days(E.StartDateTime)'; break; case 'Time': - $sql .= 'extract(hour_second FROM E.StartTime)'; + $sql .= 'extract(hour_second FROM E.StartDateTime)'; break; case 'Weekday': - $sql .= 'weekday(E.StartTime)'; + $sql .= 'weekday(E.StartDateTime)'; break; # Starting Time case 'StartDateTime': - $sql .= 'E.StartTime'; + $sql .= 'E.StartDateTime'; break; case 'FramesEventId': $sql .= 'F.EventId'; break; case 'StartDate': - $sql .= 'to_days(E.StartTime)'; + $sql .= 'to_days(E.StartDateTime)'; break; case 'StartTime': - $sql .= 'extract(hour_second FROM E.StartTime)'; + $sql .= 'extract(hour_second FROM E.StartDateTime)'; break; case 'StartWeekday': - $sql .= 'weekday(E.StartTime)'; + $sql .= 'weekday(E.StartDateTime)'; break; # Ending Time case 'EndDateTime': - $sql .= 'E.EndTime'; + $sql .= 'E.EndDateTime'; break; case 'EndDate': - $sql .= 'to_days(E.EndTime)'; + $sql .= 'to_days(E.EndDateTime)'; break; case 'EndTime': - $sql .= 'extract(hour_second FROM E.EndTime)'; + $sql .= 'extract(hour_second FROM E.EndDateTime)'; break; case 'EndWeekday': - $sql .= 'weekday(E.EndTime)'; + $sql .= 'weekday(E.EndDateTime)'; break; case 'Emailed': case 'Id': From 8029f59eac0e2b92e6febfad3b465f7f900ba50b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Nov 2020 13:52:50 -0500 Subject: [PATCH 0579/2339] Rename StartTime, EndTime in Events to StartDateTime and EndDateTime --- web/includes/functions.php | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index 725c9baac..9ac46cd3c 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -996,26 +996,19 @@ function parseSort($saveToSession=false, $querySep='&') { $sortColumn = 'E.Cause'; break; case 'DateTime' : - $sortColumn = 'E.StartTime'; - $_REQUEST['sort_field'] = 'StartTime'; + $sortColumn = 'E.StartDateTime'; + $_REQUEST['sort_field'] = 'StartDateTime'; break; case 'DiskSpace' : $sortColumn = 'E.DiskSpace'; break; case 'StartTime' : - $sortColumn = 'E.StartTime'; - break; case 'StartDateTime' : - // Fix for systems with EVENT_SORT_ORDER set to erroneous StartDateTime. - $_REQUEST['sort_field'] = 'StartTime'; - $sortColumn = 'E.StartTime'; + $sortColumn = 'E.StartDateTime'; break; case 'EndTime' : - $sortColumn = 'E.EndTime'; - break; case 'EndDateTime' : - $_REQUEST['sort_field'] = 'EndTime'; - $sortColumn = 'E.EndTime'; + $sortColumn = 'E.EndDateTime'; break; case 'Length' : $sortColumn = 'E.Length'; @@ -1051,7 +1044,7 @@ function parseSort($saveToSession=false, $querySep='&') { $sortColumn = 'F.Score'; break; default: - $sortColumn = 'E.StartTime'; + $sortColumn = 'E.StartDateTime'; break; } if ( !isset($_REQUEST['sort_asc']) ) From 9e6a9cad80669864c103a96449fc3cf17a1402eb Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Nov 2020 13:53:17 -0500 Subject: [PATCH 0580/2339] Rename StartTime, EndTime in Events to StartDateTime and EndDateTime --- web/skins/classic/views/event.php | 2 +- web/skins/classic/views/export.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/web/skins/classic/views/event.php b/web/skins/classic/views/event.php index cb23429f9..24ce53a61 100644 --- a/web/skins/classic/views/event.php +++ b/web/skins/classic/views/event.php @@ -145,7 +145,7 @@ if ( !$Event->Id() ) { Id() ?> Id().' '.validHtmlStr($Monitor->Name()) ?> Cause()) ?> - StartTime())) ?> + StartDateTime())) ?> Length().'s' ?> Frames() ?>/AlarmFrames() ?> TotScore() ?>/AvgScore() ?>/MaxScore() ?> diff --git a/web/skins/classic/views/export.php b/web/skins/classic/views/export.php index 90e269a33..e234402f4 100644 --- a/web/skins/classic/views/export.php +++ b/web/skins/classic/views/export.php @@ -152,8 +152,8 @@ while ( $event_row = dbFetchNext($results) ) { Name()).($event->Archived()?'*':'') ?> MonitorId(), $event->MonitorName(), canEdit( 'Monitors' ) ) ?> Cause()), canEdit( 'Events' ), 'title="' .htmlspecialchars($event->Notes()). '" class="eDetailLink" data-eid=' .$event->Id(). '"') ?> - StartTime())) . -( $event->EndTime() ? ' until ' . strftime(STRF_FMT_DATETIME_SHORTER, strtotime($event->EndTime()) ) : '' ) ?> + StartDateTime())) . +( $event->EndDateTime() ? ' until ' . strftime(STRF_FMT_DATETIME_SHORTER, strtotime($event->EndDateTime()) ) : '' ) ?> Length() ) ?> Id(), $event->Frames() ) ?> From 9d22de98a34a101602f8ee8971bfd4d54b8898b0 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Nov 2020 13:53:45 -0500 Subject: [PATCH 0581/2339] Rename StartTime, EndTime in Events to StartDateTime and EndDateTime --- web/skins/classic/views/js/event.js | 8 ++++---- web/skins/classic/views/js/event.js.php | 4 ++-- web/skins/classic/views/js/montagereview.js.php | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/web/skins/classic/views/js/event.js b/web/skins/classic/views/js/event.js index 143f51ebc..9841ea425 100644 --- a/web/skins/classic/views/js/event.js +++ b/web/skins/classic/views/js/event.js @@ -16,7 +16,7 @@ function vjsReplay() { var overLaid = $j("#videoobj"); overLaid.append('

No more events

'); } else { - var endTime = (Date.parse(eventData.EndTime)).getTime(); + var endTime = (Date.parse(eventData.EndDateTime)).getTime(); var nextStartTime = nextEventStartTime.getTime(); //nextEventStartTime.getTime() is a mootools workaround, highjacks Date.parse if ( nextStartTime <= endTime ) { streamNext(true); @@ -584,7 +584,7 @@ function getEventResponse(respObj, respText) { $('dataCause').setProperty( 'title', causeString ); } $('dataCause').set( 'text', eventData.Cause ); - $('dataTime').set( 'text', eventData.StartTime ); + $('dataTime').set( 'text', eventData.StartDateTime ); $('dataDuration').set( 'text', eventData.Length ); $('dataFrames').set( 'text', eventData.Frames+"/"+eventData.AlarmFrames ); $('dataScore').set( 'text', eventData.TotScore+"/"+eventData.AvgScore+"/"+eventData.MaxScore ); @@ -606,7 +606,7 @@ function getEventResponse(respObj, respText) { vid.src({type: 'video/mp4', src: CurEventDefVideoPath}); //Currently mp4 is all we use console.log('getEventResponse'); initialAlarmCues(eventData.Id);//ajax and render, new event - addVideoTimingTrack(vid, LabelFormat, eventData.MonitorName, eventData.Length, eventData.StartTime); + addVideoTimingTrack(vid, LabelFormat, eventData.MonitorName, eventData.Length, eventData.StartDateTime); CurEventDefVideoPath = null; $j('#modeValue').html('Replay'); $j('#zoomValue').html('1'); @@ -1088,7 +1088,7 @@ function initPage() { //FIXME prevent blocking...not sure what is happening or best way to unblock if ( $j('#videoobj').length ) { vid = videojs('videoobj'); - addVideoTimingTrack(vid, LabelFormat, eventData.MonitorName, eventData.Length, eventData.StartTime); + addVideoTimingTrack(vid, LabelFormat, eventData.MonitorName, eventData.Length, eventData.StartDateTime); $j('.vjs-progress-control').append('
');//add a place for videojs only on first load vid.on('ended', vjsReplay); vid.on('play', vjsPlay); diff --git a/web/skins/classic/views/js/event.js.php b/web/skins/classic/views/js/event.js.php index beee0b668..105f47da1 100644 --- a/web/skins/classic/views/js/event.js.php +++ b/web/skins/classic/views/js/event.js.php @@ -44,8 +44,8 @@ var eventData = { Width: 'Width() ?>', Height: 'Height() ?>', Length: 'Length() ?>', - StartTime: 'StartTime() ?>', - EndTime: 'EndTime() ?>', + StartDateTime: 'StartDateTime() ?>', + EndDateTime: 'EndDateTime() ?>', Frames: 'Frames() ?>', MonitorName: 'Name()) ?>' }; diff --git a/web/skins/classic/views/js/montagereview.js.php b/web/skins/classic/views/js/montagereview.js.php index d2277b507..9a2206bc6 100644 --- a/web/skins/classic/views/js/montagereview.js.php +++ b/web/skins/classic/views/js/montagereview.js.php @@ -76,7 +76,7 @@ if ( !$liveMode ) { if ( !isset($event['FramesById']) ) { // Please note that this is the last frame as we sort DESC $event['FramesById'] = array(); - $frame['NextTimeStampSecs'] = $event['EndTime']; + $frame['NextTimeStampSecs'] = $event['EndTimeSecs']; } else { $frame['NextTimeStampSecs'] = $next_frames[$frame['EventId']]['TimeStampSecs']; $frame['NextFrameId'] = $next_frames[$frame['EventId']]['Id']; From d75e93249c1a0f0a5e624f57a63a3d78945cc660 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Nov 2020 13:54:12 -0500 Subject: [PATCH 0582/2339] Rename StartTime, EndTime in Events to StartDateTime and EndDateTime --- web/skins/classic/views/js/timeline.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/views/js/timeline.js b/web/skins/classic/views/js/timeline.js index 85c73baa6..3eacc2529 100644 --- a/web/skins/classic/views/js/timeline.js +++ b/web/skins/classic/views/js/timeline.js @@ -24,7 +24,7 @@ function createEventHtml(zm_event, frame) { new Element('p').inject(eventHtml).set('text', monitors[zm_event.MonitorId].Name); new Element('p').inject(eventHtml).set('text', zm_event.Name+(frame?('('+frame.FrameId+')'):'')); - new Element('p').inject(eventHtml).set('text', zm_event.StartTime+' - '+zm_event.Length+'s'); + new Element('p').inject(eventHtml).set('text', zm_event.StartDateTime+' - '+zm_event.Length+'s'); new Element('p').inject(eventHtml).set('text', zm_event.Cause); if ( zm_event.Notes ) { new Element('p').inject(eventHtml).set('text', zm_event.Notes); @@ -90,7 +90,7 @@ function showEventData(eventId, frameId) { showEventDetail( zm_event['frames'][frameId]['html'] ); var imagePath = 'index.php?view=image&eid='+eventId+'&fid='+frameId; var videoName = zm_event.DefaultVideo; - loadEventImage( imagePath, eventId, frameId, zm_event.Width, zm_event.Height, zm_event.Frames/zm_event.Length, videoName, zm_event.Length, zm_event.StartTime, monitors[zm_event.MonitorId]); + loadEventImage( imagePath, eventId, frameId, zm_event.Width, zm_event.Height, zm_event.Frames/zm_event.Length, videoName, zm_event.Length, zm_event.StartDateTime, monitors[zm_event.MonitorId]); return; } else { console.log('No frames for ' + frameId); From af9e279f9e73223a1971d410c73bd63deee077a0 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Nov 2020 13:55:27 -0500 Subject: [PATCH 0583/2339] Rename StartTime, EndTime in Events to StartDateTime and EndDateTime --- web/skins/classic/views/js/watch.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/watch.js b/web/skins/classic/views/js/watch.js index 23629514e..feea5e698 100644 --- a/web/skins/classic/views/js/watch.js +++ b/web/skins/classic/views/js/watch.js @@ -603,7 +603,7 @@ function getEventCmdResponse( respObj, respText ) { link.set('text', zm_event.Name); link.inject(row.getElement('td.colName')); - row.getElement('td.colTime').set('text', zm_event.StartTime); + row.getElement('td.colTime').set('text', zm_event.StartDateTime); row.getElement('td.colSecs').set('text', zm_event.Length); link = new Element('a', {'href': '#', 'events': {'click': openFrames.pass( [zm_event.Id] )}}); From 786e2fec92e6b4ae3f0c79dd44e00ff3b2faa2e1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Nov 2020 13:56:27 -0500 Subject: [PATCH 0584/2339] Rename StartTime, EndTime in Events to StartDateTime and EndDateTime --- web/skins/classic/views/montagereview.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/web/skins/classic/views/montagereview.php b/web/skins/classic/views/montagereview.php index 615a04c0c..d34ee44b4 100644 --- a/web/skins/classic/views/montagereview.php +++ b/web/skins/classic/views/montagereview.php @@ -114,19 +114,19 @@ if ( count($filter) ) { $eventsSql = 'SELECT E.Id,E.Name,E.StorageId, - E.StartTime AS StartTime,UNIX_TIMESTAMP(E.StartTime) AS StartTimeSecs, - CASE WHEN E.EndTime IS NULL THEN (SELECT NOW()) ELSE E.EndTime END AS EndTime, - UNIX_TIMESTAMP(EndTime) AS EndTimeSecs, + E.StartDateTime AS StartDateTime,UNIX_TIMESTAMP(E.StartDateTime) AS StartTimeSecs, + CASE WHEN E.EndDateTime IS NULL THEN (SELECT NOW()) ELSE E.EndDateTime END AS EndDateTime, + UNIX_TIMESTAMP(EndDateTime) AS EndTimeSecs, E.Length, E.Frames, E.MaxScore,E.Cause,E.Notes,E.Archived,E.MonitorId FROM Events AS E WHERE 1 > 0 '; -// select E.Id,E.Name,UNIX_TIMESTAMP(E.StartTime) as StartTimeSecs,UNIX_TIMESTAMP(max(DATE_ADD(E.StartTime, Interval Delta+0.5 Second))) as CalcEndTimeSecs, E.Length,max(F.FrameId) as Frames,E.MaxScore,E.Cause,E.Notes,E.Archived,E.MonitorId +// select E.Id,E.Name,UNIX_TIMESTAMP(E.StartDateTime) as StartTimeSecs,UNIX_TIMESTAMP(max(DATE_ADD(E.StartDateTime, Interval Delta+0.5 Second))) as CalcEndTimeSecs, E.Length,max(F.FrameId) as Frames,E.MaxScore,E.Cause,E.Notes,E.Archived,E.MonitorId // from Events as E // inner join Monitors as M on (E.MonitorId = M.Id) // inner join Frames F on F.EventId=E.Id -// where not isnull(E.Frames) and not isnull(StartTime) "; +// where not isnull(E.Frames) and not isnull(StartDateTime) "; // Note that the delta value seems more accurate than the time stamp for some reason. $framesSql = ' @@ -219,14 +219,14 @@ $initialDisplayInterval = 1000; if ( isset($_REQUEST['displayinterval']) ) $initialDisplayInterval = validHtmlStr($_REQUEST['displayinterval']); -#$eventsSql .= ' GROUP BY E.Id,E.Name,E.StartTime,E.Length,E.Frames,E.MaxScore,E.Cause,E.Notes,E.Archived,E.MonitorId'; +#$eventsSql .= ' GROUP BY E.Id,E.Name,E.StartDateTime,E.Length,E.Frames,E.MaxScore,E.Cause,E.Notes,E.Archived,E.MonitorId'; $minTimeSecs = $maxTimeSecs = 0; if ( isset($minTime) && isset($maxTime) ) { $minTimeSecs = strtotime($minTime); $maxTimeSecs = strtotime($maxTime); - $eventsSql .= " AND EndTime > '" . $minTime . "' AND StartTime < '" . $maxTime . "'"; - $framesSql .= " AND EndTime > '" . $minTime . "' AND StartTime < '" . $maxTime . "'"; + $eventsSql .= " AND EndDateTime > '" . $minTime . "' AND StartDateTime < '" . $maxTime . "'"; + $framesSql .= " AND EndDateTime > '" . $minTime . "' AND StartDateTime < '" . $maxTime . "'"; $framesSql .= ") AND TimeStamp > '" . $minTime . "' AND TimeStamp < '" . $maxTime . "'"; } else { $framesSql .= ')'; From 68ad1cf1f7383c5c32a42f40a36d1c8e108058a7 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Nov 2020 13:56:37 -0500 Subject: [PATCH 0585/2339] Rename StartTime, EndTime in Events to StartDateTime and EndDateTime --- web/skins/classic/views/report_event_audit.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/web/skins/classic/views/report_event_audit.php b/web/skins/classic/views/report_event_audit.php index 46c4dc90d..3dfc08a70 100644 --- a/web/skins/classic/views/report_event_audit.php +++ b/web/skins/classic/views/report_event_audit.php @@ -65,8 +65,8 @@ $filterQuery = $filter['query']; ZM\Debug($filterQuery); $eventsSql = 'SELECT *, - UNIX_TIMESTAMP(E.StartTime) AS StartTimeSecs, - UNIX_TIMESTAMP(EndTime) AS EndTimeSecs + UNIX_TIMESTAMP(E.StartDateTime) AS StartTimeSecs, + UNIX_TIMESTAMP(EndDateTime) AS EndTimeSecs FROM Events AS E WHERE 1 > 0 '; @@ -77,7 +77,7 @@ if ( count($selected_monitor_ids) ) { $eventsSql .= ' AND MonitorId IN ('.implode(',', $selected_monitor_ids).')'; } if ( isset($minTime) && isset($maxTime) ) { - $eventsSql .= " AND EndTime > '" . $minTime . "' AND StartTime < '" . $maxTime . "'"; + $eventsSql .= " AND EndDateTime > '" . $minTime . "' AND StartDateTime < '" . $maxTime . "'"; } $eventsSql .= ' ORDER BY Id ASC'; @@ -211,8 +211,8 @@ for ( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { Server()->Name())?> Id()])?count($EventsByMonitor[$Monitor->Id()]['Events']):0 ?> - link_to($FirstEvent->Id().' at '.$FirstEvent->StartTime()) : 'none'?> - link_to($LastEvent->Id().' at '.$LastEvent->StartTime()) : 'none'?> + link_to($FirstEvent->Id().' at '.$FirstEvent->StartDateTime()) : 'none'?> + link_to($LastEvent->Id().' at '.$LastEvent->StartDateTime()) : 'none'?> From ce99a9456b2ee49e4e15d2032922b0e499c782c6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Nov 2020 13:56:44 -0500 Subject: [PATCH 0586/2339] Rename StartTime, EndTime in Events to StartDateTime and EndDateTime --- web/skins/classic/views/timeline.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/web/skins/classic/views/timeline.php b/web/skins/classic/views/timeline.php index 264c8128e..c4f11d312 100644 --- a/web/skins/classic/views/timeline.php +++ b/web/skins/classic/views/timeline.php @@ -128,9 +128,9 @@ $chart = array( $monitors = array(); # The as E, and joining with Monitors is required for the filterSQL filters. -$rangeSql = 'SELECT min(E.StartTime) AS MinTime, max(E.EndTime) AS MaxTime FROM Events AS E INNER JOIN Monitors AS M ON (E.MonitorId = M.Id) WHERE NOT isnull(E.StartTime) AND NOT isnull(E.EndTime)'; -$eventsSql = 'SELECT E.* FROM Events AS E INNER JOIN Monitors AS M ON (E.MonitorId = M.Id) WHERE NOT isnull(StartTime)'; -$eventIdsSql = 'SELECT E.Id FROM Events AS E INNER JOIN Monitors AS M ON (E.MonitorId = M.Id) WHERE NOT isnull(StartTime)'; +$rangeSql = 'SELECT min(E.StartDateTime) AS MinTime, max(E.EndDateTime) AS MaxTime FROM Events AS E INNER JOIN Monitors AS M ON (E.MonitorId = M.Id) WHERE NOT isnull(E.StartDateTime) AND NOT isnull(E.EndDateTime)'; +$eventsSql = 'SELECT E.* FROM Events AS E INNER JOIN Monitors AS M ON (E.MonitorId = M.Id) WHERE NOT isnull(StartDateTime)'; +$eventIdsSql = 'SELECT E.Id FROM Events AS E INNER JOIN Monitors AS M ON (E.MonitorId = M.Id) WHERE NOT isnull(StartDateTime)'; $eventsValues = array(); if ( !empty($user['MonitorIds']) ) { @@ -277,8 +277,8 @@ $midTimeT = $minTimeT + $halfRange; $midTime = strftime(STRF_FMT_DATETIME_DB, $midTimeT); if ( isset($minTime) && isset($maxTime) ) { - $eventsSql .= " AND EndTime >= '$minTime' AND StartTime <= '$maxTime'"; - $eventIdsSql .= " AND EndTime >= '$minTime' AND StartTime <= '$maxTime'"; + $eventsSql .= " AND EndDateTime >= '$minTime' AND StartDateTime <= '$maxTime'"; + $eventIdsSql .= " AND EndDateTime >= '$minTime' AND StartDateTime <= '$maxTime'"; } if ( 0 ) { @@ -332,13 +332,13 @@ while( $event = $events_result->fetch(PDO::FETCH_ASSOC) ) { $currEventSlots = &$monEventSlots[$event['MonitorId']]; $currFrameSlots = &$monFrameSlots[$event['MonitorId']]; - $startTimeT = strtotime($event['StartTime']); + $startTimeT = strtotime($event['StartDateTime']); $startIndex = $rawStartIndex = (int)(($startTimeT - $chart['data']['x']['lo']) / $chart['data']['x']['density']); if ( $startIndex < 0 ) $startIndex = 0; - if ( isset($event['EndTime']) ) - $endTimeT = strtotime($event['EndTime']); + if ( isset($event['EndDateTime']) ) + $endTimeT = strtotime($event['EndDateTime']); else $endTimeT = time(); $endIndex = $rawEndIndex = (int)(($endTimeT - $chart['data']['x']['lo']) / $chart['data']['x']['density']); From b17fa8f9c1c944f76e71567a0781680484d1b606 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Nov 2020 13:58:03 -0500 Subject: [PATCH 0587/2339] Rename StartTime, EndTime in Events to StartDateTime and EndDateTime --- web/ajax/events.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/web/ajax/events.php b/web/ajax/events.php index bf4cbacdf..5d58a5a41 100644 --- a/web/ajax/events.php +++ b/web/ajax/events.php @@ -39,7 +39,7 @@ $search = isset($_REQUEST['search']) ? $_REQUEST['search'] : ''; $advsearch = isset($_REQUEST['advsearch']) ? json_decode($_REQUEST['advsearch'], JSON_OBJECT_AS_ARRAY) : array(); // Sort specifies the name of the column to sort on -$sort = 'StartTime'; +$sort = 'StartDateTime'; if ( isset($_REQUEST['sort']) ) { $sort = $_REQUEST['sort']; } @@ -133,7 +133,7 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim $table = 'Events'; // The names of the dB columns in the events table we are interested in - $columns = array('Id', 'MonitorId', 'StorageId', 'Name', 'Cause', 'StartTime', 'EndTime', 'Length', 'Frames', 'AlarmFrames', 'TotScore', 'AvgScore', 'MaxScore', 'Archived', 'Emailed', 'Notes', 'DiskSpace'); + $columns = array('Id', 'MonitorId', 'StorageId', 'Name', 'Cause', 'StartDateTime', 'EndDateTime', 'Length', 'Frames', 'AlarmFrames', 'TotScore', 'AvgScore', 'MaxScore', 'Archived', 'Emailed', 'Notes', 'DiskSpace'); // The names of columns shown in the event view that are NOT dB columns in the database $col_alt = array('Monitor', 'Storage'); @@ -212,8 +212,8 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim $row['Archived'] = $row['Archived'] ? translate('Yes') : translate('No'); $row['Emailed'] = $row['Emailed'] ? translate('Yes') : translate('No'); $row['Cause'] = validHtmlStr($row['Cause']); - $row['StartTime'] = strftime(STRF_FMT_DATETIME_SHORTER, strtotime($row['StartTime'])); - $row['EndTime'] = $row['EndTime'] ? strftime(STRF_FMT_DATETIME_SHORTER, strtotime($row['EndTime'])) : null; + $row['StartDateTime'] = strftime(STRF_FMT_DATETIME_SHORTER, strtotime($row['StartDateTime'])); + $row['EndDateTime'] = $row['EndDateTime'] ? strftime(STRF_FMT_DATETIME_SHORTER, strtotime($row['EndDateTime'])) : null; $row['Length'] = gmdate('H:i:s', $row['Length'] ); $row['Storage'] = ( $row['StorageId'] and isset($StorageById[$row['StorageId']]) ) ? $StorageById[$row['StorageId']]->Name() : 'Default'; $row['Notes'] = nl2br(htmlspecialchars($row['Notes'])); From c3d43838da2a3407b67b128465a7721d4ca5e7ee Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Nov 2020 14:41:32 -0500 Subject: [PATCH 0588/2339] Update StartTime to StartDateTime and EndTime to EndDateTime --- db/zm_update-1.35.13.sql | 101 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 db/zm_update-1.35.13.sql diff --git a/db/zm_update-1.35.13.sql b/db/zm_update-1.35.13.sql new file mode 100644 index 000000000..4f0bf8d24 --- /dev/null +++ b/db/zm_update-1.35.13.sql @@ -0,0 +1,101 @@ +/* DateTime is invalid and it being set here will cause warnings because it isn't in the dropdown set of values in Filter edit. */ +UPDATE Config SET Value='StartDateTime' WHERE Name='ZM_WEB_EVENT_SORT_FIELD' AND Value='DateTime'; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Events' + AND column_name = 'StartDateTime' + ) > 0, +"SELECT 'Column StartDateTime already exists in Events'", +"ALTER TABLE Events RENAME COLUMN StartTime TO StartDateTime" +)); + +PREPARE stmt FROM @s; +EXECUTE stmt; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Events' + AND column_name = 'EndDateTime' + ) > 0, + "SELECT 'Column EndDateTime already exists in Events'", + "ALTER TABLE Events RENAME COLUMN EndTime TO EndDateTime" +)); + +PREPARE stmt FROM @s; +EXECUTE stmt; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Events_Hour' + AND column_name = 'StartDateTime' + ) > 0, + "SELECT 'Column StartDateTime already exists in Events_Hour'", + "ALTER TABLE Events_Hour RENAME COLUMN StartTime TO StartDateTime" +)); + +PREPARE stmt FROM @s; +EXECUTE stmt; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Events_Day' + AND column_name = 'StartDateTime' + ) > 0, + "SELECT 'Column StartDateTime already exists in Events_Day'", + "ALTER TABLE Events_Day RENAME COLUMN StartTime TO StartDateTime" +)); + +PREPARE stmt FROM @s; +EXECUTE stmt; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Events_Week' + AND column_name = 'StartDateTime' + ) > 0, + "SELECT 'Column StartDateTime already exists in Events_Week'", + "ALTER TABLE Events_Week RENAME COLUMN StartTime TO StartDateTime" +)); + +PREPARE stmt FROM @s; +EXECUTE stmt; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Events_Month' + AND column_name = 'StartDateTime' + ) > 0, + "SELECT 'Column StartDateTime already exists in Events_Month'", + "ALTER TABLE Events_Month RENAME COLUMN StartTime TO StartDateTime" +)); + +PREPARE stmt FROM @s; +EXECUTE stmt; + +delimiter // + +DROP TRIGGER IF EXISTS event_insert_trigger// + +/* The assumption is that when an Event is inserted, it has no size yet, so don't bother updating the DiskSpace, just the count. + * The DiskSpace will get update in the Event Update Trigger + */ +CREATE TRIGGER event_insert_trigger AFTER INSERT ON Events +FOR EACH ROW + BEGIN + + INSERT INTO Events_Hour (EventId,MonitorId,StartDateTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartDateTime,0); + INSERT INTO Events_Day (EventId,MonitorId,StartDateTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartDateTime,0); + INSERT INTO Events_Week (EventId,MonitorId,StartDateTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartDateTime,0); + INSERT INTO Events_Month (EventId,MonitorId,StartDateTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartDateTime,0); + UPDATE Monitors SET + HourEvents = COALESCE(HourEvents,0)+1, + DayEvents = COALESCE(DayEvents,0)+1, + WeekEvents = COALESCE(WeekEvents,0)+1, + MonthEvents = COALESCE(MonthEvents,0)+1, + TotalEvents = COALESCE(TotalEvents,0)+1 + WHERE Id=NEW.MonitorId; +END; +// + +delimiter ; From 3e5f87cb41e6d4903809296d1e65dcbccf596b36 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Nov 2020 14:42:01 -0500 Subject: [PATCH 0589/2339] Bump version to 1.35.13 --- distros/redhat/zoneminder.spec | 2 +- version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index eefba559d..220f38652 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -28,7 +28,7 @@ %global _hardened_build 1 Name: zoneminder -Version: 1.35.12 +Version: 1.35.13 Release: 1%{?dist} Summary: A camera monitoring and analysis tool Group: System Environment/Daemons diff --git a/version b/version index 7d872edd4..8cf7685bd 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.35.12 +1.35.13 From 018abe39c250c4f8ea63446a29426b1482d16afa Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Nov 2020 18:11:24 -0500 Subject: [PATCH 0590/2339] Use rename commands that work on mysql 5.7 --- db/zm_update-1.35.13.sql | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/db/zm_update-1.35.13.sql b/db/zm_update-1.35.13.sql index 4f0bf8d24..2911aaf65 100644 --- a/db/zm_update-1.35.13.sql +++ b/db/zm_update-1.35.13.sql @@ -7,7 +7,7 @@ SET @s = (SELECT IF( AND column_name = 'StartDateTime' ) > 0, "SELECT 'Column StartDateTime already exists in Events'", -"ALTER TABLE Events RENAME COLUMN StartTime TO StartDateTime" +"ALTER TABLE Events CHANGE StartTime StartDateTime datetime default NULL" )); PREPARE stmt FROM @s; @@ -19,7 +19,7 @@ SET @s = (SELECT IF( AND column_name = 'EndDateTime' ) > 0, "SELECT 'Column EndDateTime already exists in Events'", - "ALTER TABLE Events RENAME COLUMN EndTime TO EndDateTime" + "ALTER TABLE Events CHANGE EndTime EndDateTime datetime default NULL" )); PREPARE stmt FROM @s; @@ -31,7 +31,7 @@ SET @s = (SELECT IF( AND column_name = 'StartDateTime' ) > 0, "SELECT 'Column StartDateTime already exists in Events_Hour'", - "ALTER TABLE Events_Hour RENAME COLUMN StartTime TO StartDateTime" + "ALTER TABLE Events_Hour CHANGE StartTime StartDateTime datetime default NULL" )); PREPARE stmt FROM @s; @@ -43,7 +43,7 @@ SET @s = (SELECT IF( AND column_name = 'StartDateTime' ) > 0, "SELECT 'Column StartDateTime already exists in Events_Day'", - "ALTER TABLE Events_Day RENAME COLUMN StartTime TO StartDateTime" + "ALTER TABLE Events_Day CHANGE StartTime StartDateTime datetime default NULL" )); PREPARE stmt FROM @s; @@ -55,7 +55,7 @@ SET @s = (SELECT IF( AND column_name = 'StartDateTime' ) > 0, "SELECT 'Column StartDateTime already exists in Events_Week'", - "ALTER TABLE Events_Week RENAME COLUMN StartTime TO StartDateTime" + "ALTER TABLE Events_Week CHANGE StartTime StartDateTime datetime default NULL" )); PREPARE stmt FROM @s; @@ -67,7 +67,7 @@ SET @s = (SELECT IF( AND column_name = 'StartDateTime' ) > 0, "SELECT 'Column StartDateTime already exists in Events_Month'", - "ALTER TABLE Events_Month RENAME COLUMN StartTime TO StartDateTime" + "ALTER TABLE Events_Month CHANGE StartTime StartDateTime datetime default NULL" )); PREPARE stmt FROM @s; From d37bce4e0ea99aaaaeaaaf44ab703d9ef1903511 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Nov 2020 18:20:59 -0500 Subject: [PATCH 0591/2339] Fix missed StartTime to StartDateTime --- web/api/app/Controller/Component/ImageComponent.php | 4 ++-- web/api/app/Controller/EventsController.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/web/api/app/Controller/Component/ImageComponent.php b/web/api/app/Controller/Component/ImageComponent.php index 2033e0d8c..567333a71 100644 --- a/web/api/app/Controller/Component/ImageComponent.php +++ b/web/api/app/Controller/Component/ImageComponent.php @@ -89,11 +89,11 @@ class ImageComponent extends Component { } - // Take the StartTime of an Event and return + // Take the StartDateTime of an Event and return // the path to its location on the filesystem public function getEventPath( $event ) { if ( $config['ZM_USE_DEEP_STORAGE'] == 1 ) - return $event['Event']['MonitorId'].'/'.strftime( "%y/%m/%d/%H/%M/%S", strtotime($event['Event']['StartTime']) ); + return $event['Event']['MonitorId'].'/'.strftime( '%y/%m/%d/%H/%M/%S', strtotime($event['Event']['StartDateTime']) ); else return $event['Event']['MonitorId'].'/'.$event['Event']['Id']; } diff --git a/web/api/app/Controller/EventsController.php b/web/api/app/Controller/EventsController.php index 3b132e932..021c40b5e 100644 --- a/web/api/app/Controller/EventsController.php +++ b/web/api/app/Controller/EventsController.php @@ -65,7 +65,7 @@ class EventsController extends AppController { // API 'limit' => '100', - 'order' => array('StartTime'), + 'order' => array('StartDateTime'), 'paramType' => 'querystring', ); if ( isset($conditions['GroupId']) ) { @@ -309,7 +309,7 @@ class EventsController extends AppController { } else { $conditions = array(); } - array_push($conditions, array("StartTime >= DATE_SUB(NOW(), INTERVAL $expr $unit)")); + array_push($conditions, array("StartDateTime >= DATE_SUB(NOW(), INTERVAL $expr $unit)")); $query = $this->Event->find('all', array( 'fields' => array( 'MonitorId', From 130588eb8fd763fb0c3cadfa31ad22a910072df2 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Nov 2020 18:22:50 -0500 Subject: [PATCH 0592/2339] fix typos --- web/ajax/stream.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/ajax/stream.php b/web/ajax/stream.php index 2c583ba14..cdb67c0f9 100644 --- a/web/ajax/stream.php +++ b/web/ajax/stream.php @@ -128,7 +128,7 @@ if ( sem_acquire($semaphore,1) !== false ) { $data['auth'] = $auth_hash; ZM\Debug("including nw auth hash " . $data['auth']); } else { - ZM\Debug('Not including nw auth hash becase it hashn\'t changed '.$auth_hash); + ZM\Debug('Not including new auth hash becase it hasn\'t changed '.$auth_hash); } } ajaxResponse(array('status'=>$data)); From e085e08caa6a7641567db30f34b3b3adfa3dcdaf Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Nov 2020 18:27:51 -0500 Subject: [PATCH 0593/2339] Fix missed StartTime to StartDateTime --- web/ajax/status.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/web/ajax/status.php b/web/ajax/status.php index 190d239ad..9d97d34b8 100644 --- a/web/ajax/status.php +++ b/web/ajax/status.php @@ -109,8 +109,8 @@ $statusData = array( 'Name' => true, 'Cause' => true, 'Notes' => true, - 'StartTime' => true, - 'StartTimeShort' => array( 'sql' => 'date_format( StartTime, \''.MYSQL_FMT_DATETIME_SHORT.'\' )' ), + 'StartDateTime' => true, + 'StartTimeShort' => array( 'sql' => 'date_format( StartDateTime, \''.MYSQL_FMT_DATETIME_SHORT.'\' )' ), 'EndTime' => true, 'Width' => true, 'Height' => true, @@ -133,8 +133,8 @@ $statusData = array( 'MonitorName' => array('sql' => '(SELECT Monitors.Name FROM Monitors WHERE Monitors.Id = Events.MonitorId)'), 'Name' => true, 'Cause' => true, - 'StartTime' => true, - 'StartTimeShort' => array( 'sql' => 'date_format( StartTime, \''.MYSQL_FMT_DATETIME_SHORT.'\' )' ), + 'StartDateTime' => true, + 'StartTimeShort' => array( 'sql' => 'date_format( StartDateTime, \''.MYSQL_FMT_DATETIME_SHORT.'\' )' ), 'EndTime' => true, 'Width' => true, 'Height' => true, @@ -180,7 +180,7 @@ $statusData = array( 'EventId' => true, 'Type' => true, 'TimeStamp' => true, - 'TimeStampShort' => array( 'sql' => 'date_format( StartTime, \''.MYSQL_FMT_DATETIME_SHORT.'\' )' ), + 'TimeStampShort' => array( 'sql' => 'date_format( StartDateTime, \''.MYSQL_FMT_DATETIME_SHORT.'\' )' ), 'Delta' => true, 'Score' => true, //'Image' => array( 'postFunc' => 'getFrameImage' ), @@ -424,11 +424,11 @@ function getNearEvents() { } # When listing, it may make sense to list them in descending order. But when viewing Prev should timewise earlier and Next should be after. - if ( $sortColumn == 'E.Id' or $sortColumn == 'E.StartTime' ) { + if ( $sortColumn == 'E.Id' or $sortColumn == 'E.StartDateTime' ) { $sortOrder = 'ASC'; } - $sql = 'SELECT E.Id AS Id, E.StartTime AS StartTime FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id WHERE '.$sortColumn.' '.($sortOrder=='ASC'?'<=':'>=').' \''.$event[$_REQUEST['sort_field']].'\' AND ('.$filter->sql().') AND E.Id<'.$event['Id'] . ' ORDER BY '.$sortColumn.' '.($sortOrder=='ASC'?'DESC':'ASC'); + $sql = 'SELECT E.Id AS Id, E.StartDateTime AS StartDateTime FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id WHERE '.$sortColumn.' '.($sortOrder=='ASC'?'<=':'>=').' \''.$event[$_REQUEST['sort_field']].'\' AND ('.$filter->sql().') AND E.Id<'.$event['Id'] . ' ORDER BY '.$sortColumn.' '.($sortOrder=='ASC'?'DESC':'ASC'); if ( $sortColumn != 'E.Id' ) { # When sorting by starttime, if we have two events with the same starttime (diffreent monitors) then we should sort secondly by Id $sql .= ', E.Id DESC'; @@ -442,7 +442,7 @@ function getNearEvents() { $prevEvent = dbFetchNext($result); - $sql = 'SELECT E.Id AS Id, E.StartTime AS StartTime FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id WHERE '.$sortColumn .' '.($sortOrder=='ASC'?'>=':'<=').' \''.$event[$_REQUEST['sort_field']]."' AND (".$filter->sql().') AND E.Id>'.$event['Id'] . ' ORDER BY '.$sortColumn.' '.($sortOrder=='ASC'?'ASC':'DESC'); + $sql = 'SELECT E.Id AS Id, E.StartDateTime AS StartDateTime FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id WHERE '.$sortColumn .' '.($sortOrder=='ASC'?'>=':'<=').' \''.$event[$_REQUEST['sort_field']]."' AND (".$filter->sql().') AND E.Id>'.$event['Id'] . ' ORDER BY '.$sortColumn.' '.($sortOrder=='ASC'?'ASC':'DESC'); if ( $sortColumn != 'E.Id' ) { # When sorting by starttime, if we have two events with the same starttime (diffreent monitors) then we should sort secondly by Id $sql .= ', E.Id ASC'; @@ -457,14 +457,14 @@ function getNearEvents() { if ( $prevEvent ) { $NearEvents['PrevEventId'] = $prevEvent['Id']; - $NearEvents['PrevEventStartTime'] = $prevEvent['StartTime']; + $NearEvents['PrevEventStartTime'] = $prevEvent['StartDateTime']; $NearEvents['PrevEventDefVideoPath'] = getEventDefaultVideoPath($prevEvent['Id']); } else { $NearEvents['PrevEventId'] = $NearEvents['PrevEventStartTime'] = $NearEvents['PrevEventDefVideoPath'] = 0; } if ( $nextEvent ) { $NearEvents['NextEventId'] = $nextEvent['Id']; - $NearEvents['NextEventStartTime'] = $nextEvent['StartTime']; + $NearEvents['NextEventStartTime'] = $nextEvent['StartDateTime']; $NearEvents['NextEventDefVideoPath'] = getEventDefaultVideoPath($nextEvent['Id']); } else { $NearEvents['NextEventId'] = $NearEvents['NextEventStartTime'] = $NearEvents['NextEventDefVideoPath'] = 0; From ee89eb45e66658abe00e24d47dcfa94f0c1d4905 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 4 Nov 2020 18:39:02 -0500 Subject: [PATCH 0594/2339] Fix EndTime to EndDateTime --- web/ajax/status.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/ajax/status.php b/web/ajax/status.php index 9d97d34b8..795a4b581 100644 --- a/web/ajax/status.php +++ b/web/ajax/status.php @@ -111,7 +111,7 @@ $statusData = array( 'Notes' => true, 'StartDateTime' => true, 'StartTimeShort' => array( 'sql' => 'date_format( StartDateTime, \''.MYSQL_FMT_DATETIME_SHORT.'\' )' ), - 'EndTime' => true, + 'EndDateTime' => true, 'Width' => true, 'Height' => true, 'Length' => true, @@ -135,7 +135,7 @@ $statusData = array( 'Cause' => true, 'StartDateTime' => true, 'StartTimeShort' => array( 'sql' => 'date_format( StartDateTime, \''.MYSQL_FMT_DATETIME_SHORT.'\' )' ), - 'EndTime' => true, + 'EndDateTime' => true, 'Width' => true, 'Height' => true, 'Length' => true, From 7b8ee6af9f5342752809064a5fd12026d12dd9d8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 5 Nov 2020 12:20:49 -0500 Subject: [PATCH 0595/2339] Rework code to use Filter methods to generate advanced search functionality. Reduces sql queries to 1 or 2, using count() to populate [total] and [totalNotFiltered]. Does pagination using array_splice instead of SQL queries. Will use more ram, but reduces db load. --- web/ajax/events.php | 115 +++++++++++++++++++++++++------------------- 1 file changed, 65 insertions(+), 50 deletions(-) diff --git a/web/ajax/events.php b/web/ajax/events.php index 5d58a5a41..3a2e6ad53 100644 --- a/web/ajax/events.php +++ b/web/ajax/events.php @@ -1,5 +1,4 @@ addTerm(array('cnj'=>'and', 'attr'=>'MonitorId', 'op'=>'IN', 'val'=>$user['MonitorIds'])); @@ -115,11 +115,12 @@ function deleteRequest($eid) { } function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $limit) { + $data = array( 'total' => 0, 'totalNotFiltered' => 0, 'rows' => array(), - 'updated' => preg_match('/%/', DATE_FMT_CONSOLE_LONG) ? strftime(DATE_FMT_CONSOLE_LONG) : date(DATE_FMT_CONSOLE_LONG) + 'updated' => preg_match('/%/', DATE_FMT_CONSOLE_LONG) ? strftime(DATE_FMT_CONSOLE_LONG) : date(DATE_FMT_CONSOLE_LONG) ); $failed = !$filter->test_pre_sql_conditions(); @@ -143,50 +144,15 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim $sort = 'Id'; } - $data = array(); - $query = array(); - $query['values'] = array(); + $values = array(); $likes = array(); - $where = ($filter->sql()?'('.$filter->sql().')' : ''); - // There are two search bars in the log view, normal and advanced - // Making an exuctive decision to ignore the normal search, when advanced search is in use - // Alternatively we could try to do both - if ( count($advsearch) ) { - - foreach ( $advsearch as $col=>$text ) { - if ( in_array($col, $columns) ) { - array_push($likes, 'E.'.$col.' LIKE ?'); - array_push($query['values'], $text); - } else if ( in_array($col, $col_alt) ) { - array_push($likes, 'M.'.$col.' LIKE ?'); - array_push($query['values'], $text); - } else { - ZM\Error("'$col' is not a sortable column name"); - continue; - } - } # end foreach col in advsearch - $wherevalues = $query['values']; - $where .= ($where != '') ? ' AND (' .implode(' OR ', $likes). ')' : implode(' OR ', $likes); - - } else if ( $search != '' ) { - - $search = '%' .$search. '%'; - foreach ( $columns as $col ) { - array_push($likes, 'E.'.$col.' LIKE ?'); - array_push($query['values'], $search); - } - $wherevalues = $query['values']; - $where .= ( $where != '') ? ' AND (' .implode(' OR ', $likes). ')' : implode(' OR ', $likes); - } - if ( $where ) - $where = ' WHERE '.$where; + $where = $filter->sql()?' WHERE ('.$filter->sql().')' : ''; $sort = $sort == 'Monitor' ? 'M.Name' : 'E.'.$sort; $col_str = 'E.*, M.Name AS Monitor'; - $query['sql'] = 'SELECT ' .$col_str. ' FROM `' .$table. '` AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id'.$where.' ORDER BY ' .$sort. ' ' .$order. ' LIMIT ?, ?'; - array_push($query['values'], $offset, $limit); + $sql = 'SELECT ' .$col_str. ' FROM `Events` AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id'.$where.' ORDER BY '.$sort.' '.$order; - //ZM\Debug('Calling the following sql query: ' .$query['sql']); + //ZM\Debug('Calling the following sql query: ' .$sql); $storage_areas = ZM\Storage::find(); $StorageById = array(); @@ -194,13 +160,61 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim $StorageById[$S->Id()] = $S; } - $rows = array(); - foreach ( dbFetchAll($query['sql'], NULL, $query['values']) as $row ) { + $unfiltered_rows = array(); + $event_ids = array(); + + foreach ( dbFetchAll($sql, NULL, $values) as $row ) { $event = new ZM\Event($row); if ( !$filter->test_post_sql_conditions($event) ) { $event->remove_from_cache(); continue; } + $event_ids[] = $event->Id(); + $unfiltered_rows[] = $row; + } + + ZM\Debug('Have ' . count($event_ids) . ' events matching base filter.'); + + $filtered_rows = null; + + if ( count($advsearch) or $search != '' ) { + $search_filter = new ZM\Filter(); + $search_filter = $search_filter->addTerm(array('cnj'=>'and', 'attr'=>'Id', 'op'=>'IN', 'val'=>$event_ids)); + + // There are two search bars in the log view, normal and advanced + // Making an exuctive decision to ignore the normal search, when advanced search is in use + // Alternatively we could try to do both + if ( count($advsearch) ) { + $terms = array(); + foreach ( $advsearch as $col=>$text ) { + $terms[] = array('cnj'=>'and', 'attr'=>$col, 'op'=>'LIKE', 'val'=>$text); + } # end foreach col in advsearch + $terms[0]['obr'] = 1; + $terms[count($terms)-1]['cbr'] = 1; + $search_filter->addTerms($terms); + } else if ( $search != '' ) { + $search = '%' .$search. '%'; + $terms = array(); + foreach ( $columns as $col ) { + $terms[] = array('cnj'=>'or', 'attr'=>$col, 'op'=>'LIKE', 'val'=>$search); + } + $terms[0]['obr'] = 1; + $terms[0]['cnj'] = 'and'; + $terms[count($terms)-1]['cbr'] = 1; + $search_filter = $search_filter->addTerms($terms, array('obr'=>1, 'cbr'=>1, 'op'=>'OR')); + } # end if search + + $sql = 'SELECT ' .$col_str. ' FROM `Events` AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id WHERE '.$search_filter->sql().' ORDER BY ' .$sort. ' ' .$order; + $filtered_rows = dbFetchAll($sql); + ZM\Debug('Have ' . count($filtered_rows) . ' events matching search filter.'); + } else { + $filtered_rows = $unfiltered_rows; + } # end if search_filter->terms() > 1 + + $returned_rows = array(); + foreach ( array_slice($filtered_rows, $offset, $limit) as $row ) { + $event = new ZM\Event($row); + $scale = intval(5*100*ZM_WEB_LIST_THUMB_WIDTH / $event->Width()); $imgSrc = $event->getThumbnailSrc(array(),'&'); $streamSrc = $event->getStreamSrc(array( @@ -218,16 +232,17 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim $row['Storage'] = ( $row['StorageId'] and isset($StorageById[$row['StorageId']]) ) ? $StorageById[$row['StorageId']]->Name() : 'Default'; $row['Notes'] = nl2br(htmlspecialchars($row['Notes'])); $row['DiskSpace'] = human_filesize($event->DiskSpace()); - $rows[] = $row; - } - $data['rows'] = $rows; + $returned_rows[] = $row; + } # end foreach row matching search + + $data['rows'] = $returned_rows; # totalNotFiltered must equal total, except when either search bar has been used - $data['totalNotFiltered'] = dbFetchOne('SELECT count(*) AS Total FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id'. ($filter->sql() ? ' WHERE '.$filter->sql():''), 'Total'); + $data['totalNotFiltered'] = count($event_ids); if ( $search != '' || count($advsearch) ) { - $data['total'] = dbFetchOne('SELECT count(*) AS Total FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id'.$where , 'Total', $wherevalues); + $data['total'] = count($filtered_rows); } else { - $data['total'] = $data['totalNotFiltered']; + $data['total'] = count($unfiltered_rows); } return $data; From c4eb59442e4767d53b8b052add1a1d5d511ae46e Mon Sep 17 00:00:00 2001 From: Esteban Flores Date: Mon, 2 Nov 2020 01:05:57 -0600 Subject: [PATCH 0596/2339] Changed "Purge By Age" filter Changed "Purge By Age" filter, the "date" option is not available in v1.34.22. Using "End Date" as the filter parameter works just fine. --- docs/faq.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/faq.rst b/docs/faq.rst index 56b67d082..1db30e05f 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -27,7 +27,7 @@ After you've done that, you changes will automatically be loaded into zmfilter w Check the ``zmfilter.log`` file to make sure it is running as sometimes missing perl modules mean that it never runs but people don't always realize. **Purge By Age** -To delete events that are older than 7 days, create a new filter with "Date" set to "less than" and a value of "-7 days", sort by "date/time" in "asc"ending order, then enable the checkbox "delete all matches". You can also use a value of week or week and days: "-2 week" or "-2 week 4 day" +To delete events that are older than 7 days, create a new filter with "End Date" set to "less than" and a value of "-7 days", sort by "date/time" in "asc"ending order, then enable the checkbox "delete all matches". You can also use a value of week or week and days: "-2 week" or "-2 week 4 day" Save with 'Run Filter In Background' enabled to have it run automatically. Optional skip archived events: click on the plus sign next to -7 days to add another condition. "and" "archive status" equal to "unarchived only". @@ -534,4 +534,4 @@ The GPL license allows you produce systems based on GPL software provided your s I am having issues with zmNinja and/or Event Notification Server ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -zmNinja and the Event Notification Server are 3rd party solutions. The developer maintains exhaustive `documentation and FAQs `__. Please direct your questions there. \ No newline at end of file +zmNinja and the Event Notification Server are 3rd party solutions. The developer maintains exhaustive `documentation and FAQs `__. Please direct your questions there. From 746882ba85fe8a5b0c763a20a06d86659f6dd697 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 5 Nov 2020 13:45:02 -0500 Subject: [PATCH 0597/2339] Get rid of zmEventScaleAuto cookie. Just use the per monitor zmEventScale cookie. Fixes #3070 --- web/skins/classic/views/event.php | 3 --- web/skins/classic/views/js/event.js | 7 +------ 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/web/skins/classic/views/event.php b/web/skins/classic/views/event.php index b9c2d8f38..231a60430 100644 --- a/web/skins/classic/views/event.php +++ b/web/skins/classic/views/event.php @@ -46,9 +46,6 @@ if ( isset($_REQUEST['rate']) ) { if ( isset($_REQUEST['scale']) ) { $scale = validInt($_REQUEST['scale']); -} else if ( isset($_COOKIE['zmEventScaleAuto']) ) { - // If we're using scale to fit use it on all monitors - $scale = '0'; } else if ( isset($_COOKIE['zmEventScale'.$Event->MonitorId()]) ) { $scale = $_COOKIE['zmEventScale'.$Event->MonitorId()]; } else { diff --git a/web/skins/classic/views/js/event.js b/web/skins/classic/views/js/event.js index efc9360da..ef79125f0 100644 --- a/web/skins/classic/views/js/event.js +++ b/web/skins/classic/views/js/event.js @@ -175,12 +175,7 @@ function changeScale() { } else { alarmCue.html(renderAlarmCues(eventViewer));//just re-render alarmCues. skip ajax call } - if ( scale = '0' || scale == 'auto' ) { - Cookie.write('zmEventScaleAuto', 'auto', {duration: 10*365}); - } else { - Cookie.write('zmEventScale'+eventData.MonitorId, scale, {duration: 10*365}); - Cookie.dispose('zmEventScaleAuto'); - } + Cookie.write('zmEventScale'+eventData.MonitorId, scale, {duration: 10*365}); } function changeReplayMode() { From 402b559b2cbc08c42395e4eaf6463798f2c79c5d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 6 Nov 2020 11:15:12 -0500 Subject: [PATCH 0598/2339] Add StartTime and EndTime virtual fields for backwards compatability --- web/api/app/Model/Event.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/web/api/app/Model/Event.php b/web/api/app/Model/Event.php index 22a97f62f..e54fd125f 100644 --- a/web/api/app/Model/Event.php +++ b/web/api/app/Model/Event.php @@ -31,6 +31,10 @@ class Event extends AppModel { */ public $displayField = 'Name'; + public $virtualFields = array( + 'StartTime' => 'StartDateTime', + 'EndTime' => 'EndDateTime' + ); //The Associations below have been created with all possible keys, those that are not needed can be removed From 6ed006bc600bde23ba21a4e37923f5515d3d6477 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 6 Nov 2020 12:25:04 -0500 Subject: [PATCH 0599/2339] rename StartTime and EndTime to StartDateTime and EndDateTime in the named query params --- web/api/app/Controller/EventsController.php | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/web/api/app/Controller/EventsController.php b/web/api/app/Controller/EventsController.php index 021c40b5e..d18409387 100644 --- a/web/api/app/Controller/EventsController.php +++ b/web/api/app/Controller/EventsController.php @@ -48,9 +48,24 @@ class EventsController extends AppController { $mon_options = ''; } - if ( $this->request->params['named'] ) { + $named_params = $this->request->params['named']; + if ( $named_params ) { + # In 1.35.13 we renamed StartTime and EndTime to StartDateTime and EndDateTime. + # This hack renames the query string params + foreach ( $named_params as $k=>$v ) { + if ( false !== strpos($k, 'StartTime') ) { + $new_k = preg_replace('/StartTime/', 'StartDateTime', $k); + $named_params[$new_k] = $named_params[$k]; + unset($named_params[$k]); + } + if ( false !== strpos($k, 'EndTime') ) { + $new_k = preg_replace('/EndTime/', 'EndDateTime', $k); + $named_params[$new_k] = $named_params[$k]; + unset($named_params[$k]); + } + } $this->FilterComponent = $this->Components->load('Filter'); - $conditions = $this->FilterComponent->buildFilter($this->request->params['named']); + $conditions = $this->FilterComponent->buildFilter($named_params); } else { $conditions = array(); } From 63c78b43f8a6d8496e538a46be1bf52e3b1b3ff3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 6 Nov 2020 13:27:00 -0500 Subject: [PATCH 0600/2339] Change event stats to Monitor_Status --- db/triggers.sql | 78 ++++++++++++++++++++++----------------------- db/zm_create.sql.in | 24 +++++++------- 2 files changed, 51 insertions(+), 51 deletions(-) diff --git a/db/triggers.sql b/db/triggers.sql index ad697be54..574d34440 100644 --- a/db/triggers.sql +++ b/db/triggers.sql @@ -3,10 +3,10 @@ delimiter // DROP TRIGGER IF EXISTS Events_Hour_delete_trigger// CREATE TRIGGER Events_Hour_delete_trigger BEFORE DELETE ON Events_Hour FOR EACH ROW BEGIN - UPDATE Monitors SET + UPDATE Monitor_Status SET HourEvents = GREATEST(COALESCE(HourEvents,1)-1,0), HourEventDiskSpace=GREATEST(COALESCE(HourEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0),0) - WHERE Id=OLD.MonitorId; + WHERE Monitor_Status.MonitorId=OLD.MonitorId; END; // @@ -20,10 +20,10 @@ FOR EACH ROW set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); IF ( diff ) THEN IF ( NEW.MonitorID != OLD.MonitorID ) THEN - UPDATE Monitors SET HourEventDiskSpace=GREATEST(COALESCE(HourEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0),0) WHERE Monitors.Id=OLD.MonitorId; - UPDATE Monitors SET HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)+COALESCE(NEW.DiskSpace,0) WHERE Monitors.Id=NEW.MonitorId; + UPDATE Monitor_Status SET HourEventDiskSpace=GREATEST(COALESCE(HourEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0),0) WHERE Monitor_Status.MonitorId=OLD.MonitorId; + UPDATE Monitor_Status SET HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)+COALESCE(NEW.DiskSpace,0) WHERE Monitor_Status.MonitorId=NEW.MonitorId; ELSE - UPDATE Monitors SET HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)+diff WHERE Monitors.Id=NEW.MonitorId; + UPDATE Monitor_Status SET HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)+diff WHERE Monitor_Status.MonitorId=NEW.MonitorId; END IF; END IF; END; @@ -32,10 +32,10 @@ FOR EACH ROW DROP TRIGGER IF EXISTS Events_Day_delete_trigger// CREATE TRIGGER Events_Day_delete_trigger BEFORE DELETE ON Events_Day FOR EACH ROW BEGIN - UPDATE Monitors SET + UPDATE Monitor_Status SET DayEvents = GREATEST(COALESCE(DayEvents,1)-1,0), DayEventDiskSpace=GREATEST(COALESCE(DayEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0),0) - WHERE Id=OLD.MonitorId; + WHERE Monitor_Status.MonitorId=OLD.MonitorId; END; // @@ -48,10 +48,10 @@ FOR EACH ROW set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); IF ( diff ) THEN IF ( NEW.MonitorID != OLD.MonitorID ) THEN - UPDATE Monitors SET DayEventDiskSpace=GREATEST(COALESCE(DayEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0),0) WHERE Monitors.Id=OLD.MonitorId; - UPDATE Monitors SET DayEventDiskSpace=COALESCE(DayEventDiskSpace,0)+COALESCE(NEW.DiskSpace,0) WHERE Monitors.Id=NEW.MonitorId; + UPDATE Monitor_Status SET DayEventDiskSpace=GREATEST(COALESCE(DayEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0),0) WHERE Monitor_Status.MonitorId=OLD.MonitorId; + UPDATE Monitor_Status SET DayEventDiskSpace=COALESCE(DayEventDiskSpace,0)+COALESCE(NEW.DiskSpace,0) WHERE Monitor_Status.MonitorId=NEW.MonitorId; ELSE - UPDATE Monitors SET DayEventDiskSpace=GREATEST(COALESCE(DayEventDiskSpace,0)+diff,0) WHERE Monitors.Id=NEW.MonitorId; + UPDATE Monitor_Status SET DayEventDiskSpace=GREATEST(COALESCE(DayEventDiskSpace,0)+diff,0) WHERE Monitor_Status.MonitorId=NEW.MonitorId; END IF; END IF; END; @@ -61,10 +61,10 @@ FOR EACH ROW DROP TRIGGER IF EXISTS Events_Week_delete_trigger// CREATE TRIGGER Events_Week_delete_trigger BEFORE DELETE ON Events_Week FOR EACH ROW BEGIN - UPDATE Monitors SET + UPDATE Monitor_Status SET WeekEvents = GREATEST(COALESCE(WeekEvents,1)-1,0), WeekEventDiskSpace=GREATEST(COALESCE(WeekEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0),0) - WHERE Id=OLD.MonitorId; + WHERE Monitor_Status.MonitorId=OLD.MonitorId; END; // @@ -77,10 +77,10 @@ FOR EACH ROW set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); IF ( diff ) THEN IF ( NEW.MonitorID != OLD.MonitorID ) THEN - UPDATE Monitors SET WeekEventDiskSpace=GREATEST(COALESCE(WeekEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0),0) WHERE Monitors.Id=OLD.MonitorId; - UPDATE Monitors SET WeekEventDiskSpace=COALESCE(WeekEventDiskSpace,0)+COALESCE(NEW.DiskSpace,0) WHERE Monitors.Id=NEW.MonitorId; + UPDATE Monitor_Status SET WeekEventDiskSpace=GREATEST(COALESCE(WeekEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0),0) WHERE Monitor_Status.MonitorId=OLD.MonitorId; + UPDATE Monitor_Status SET WeekEventDiskSpace=COALESCE(WeekEventDiskSpace,0)+COALESCE(NEW.DiskSpace,0) WHERE Monitor_Status.MonitorId=NEW.MonitorId; ELSE - UPDATE Monitors SET WeekEventDiskSpace=GREATEST(COALESCE(WeekEventDiskSpace,0)+diff,0) WHERE Monitors.Id=NEW.MonitorId; + UPDATE Monitor_Status SET WeekEventDiskSpace=GREATEST(COALESCE(WeekEventDiskSpace,0)+diff,0) WHERE Monitor_Status.MonitorId=NEW.MonitorId; END IF; END IF; END; @@ -89,10 +89,10 @@ FOR EACH ROW DROP TRIGGER IF EXISTS Events_Month_delete_trigger// CREATE TRIGGER Events_Month_delete_trigger BEFORE DELETE ON Events_Month FOR EACH ROW BEGIN - UPDATE Monitors SET + UPDATE Monitor_Status SET MonthEvents = GREATEST(COALESCE(MonthEvents,1)-1,0), MonthEventDiskSpace=GREATEST(COALESCE(MonthEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0),0) - WHERE Id=OLD.MonitorId; + WHERE Monitor_Status.MonitorId=OLD.MonitorId; END; // @@ -105,10 +105,10 @@ FOR EACH ROW set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); IF ( diff ) THEN IF ( NEW.MonitorID != OLD.MonitorID ) THEN - UPDATE Monitors SET MonthEventDiskSpace=GREATEST(COALESCE(MonthEventDiskSpace,0)-COALESCE(OLD.DiskSpace),0) WHERE Monitors.Id=OLD.MonitorId; - UPDATE Monitors SET MonthEventDiskSpace=COALESCE(MonthEventDiskSpace,0)+COALESCE(NEW.DiskSpace) WHERE Monitors.Id=NEW.MonitorId; + UPDATE Monitor_Status SET MonthEventDiskSpace=GREATEST(COALESCE(MonthEventDiskSpace,0)-COALESCE(OLD.DiskSpace),0) WHERE Monitor_Status.MonitorId=OLD.MonitorId; + UPDATE Monitor_Status SET MonthEventDiskSpace=COALESCE(MonthEventDiskSpace,0)+COALESCE(NEW.DiskSpace) WHERE Monitor_Status.MonitorId=NEW.MonitorId; ELSE - UPDATE Monitors SET MonthEventDiskSpace=GREATEST(COALESCE(MonthEventDiskSpace,0)+diff,0) WHERE Monitors.Id=NEW.MonitorId; + UPDATE Monitor_Status SET MonthEventDiskSpace=GREATEST(COALESCE(MonthEventDiskSpace,0)+diff,0) WHERE Monitor_Status.MonitorId=NEW.MonitorId; END IF; END IF; END; @@ -126,14 +126,14 @@ BEGIN set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); IF ( NEW.StorageId = OLD.StorageID ) THEN IF ( diff ) THEN - UPDATE Storage SET DiskSpace = GREATEST(COALESCE(DiskSpace,0) + diff,0) WHERE Id = OLD.StorageId; + UPDATE Storage SET DiskSpace = GREATEST(COALESCE(DiskSpace,0) + diff,0) WHERE Storage.Id = OLD.StorageId; END IF; ELSE IF ( NEW.DiskSpace ) THEN - UPDATE Storage SET DiskSpace = COALESCE(DiskSpace,0) + NEW.DiskSpace WHERE Id = NEW.StorageId; + UPDATE Storage SET DiskSpace = COALESCE(DiskSpace,0) + NEW.DiskSpace WHERE Storage.Id = NEW.StorageId; END IF; IF ( OLD.DiskSpace ) THEN - UPDATE Storage SET DiskSpace = GREATEST(COALESCE(DiskSpace,0) - OLD.DiskSpace,0) WHERE Id = OLD.StorageId; + UPDATE Storage SET DiskSpace = GREATEST(COALESCE(DiskSpace,0) - OLD.DiskSpace,0) WHERE Storage.Id = OLD.StorageId; END IF; END IF; @@ -145,20 +145,20 @@ BEGIN IF ( NEW.Archived != OLD.Archived ) THEN IF ( NEW.Archived ) THEN INSERT INTO Events_Archived (EventId,MonitorId,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.DiskSpace); - UPDATE Monitors SET ArchivedEvents = COALESCE(ArchivedEvents,0)+1, ArchivedEventDiskSpace = COALESCE(ArchivedEventDiskSpace,0) + COALESCE(NEW.DiskSpace,0) WHERE Id=NEW.MonitorId; + UPDATE Monitor_Status SET ArchivedEvents = COALESCE(ArchivedEvents,0)+1, ArchivedEventDiskSpace = COALESCE(ArchivedEventDiskSpace,0) + COALESCE(NEW.DiskSpace,0) WHERE Monitor_Status.MonitorId=NEW.MonitorId; ELSEIF ( OLD.Archived ) THEN DELETE FROM Events_Archived WHERE EventId=OLD.Id; - UPDATE Monitors + UPDATE Monitor_Status SET ArchivedEvents = GREATEST(COALESCE(ArchivedEvents,0)-1,0), ArchivedEventDiskSpace = GREATEST(COALESCE(ArchivedEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0),0) - WHERE Monitors.Id=OLD.MonitorId; + WHERE Monitor_Status.MonitorId=OLD.MonitorId; ELSE IF ( OLD.DiskSpace != NEW.DiskSpace ) THEN UPDATE Events_Archived SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; - UPDATE Monitors SET + UPDATE Monitor_Status SET ArchivedEventDiskSpace = GREATEST(COALESCE(ArchivedEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0) + COALESCE(NEW.DiskSpace,0),0) - WHERE Monitors.Id=OLD.MonitorId; + WHERE Monitor_Status.MonitorId=OLD.MonitorId; END IF; END IF; ELSEIF ( NEW.Archived AND diff ) THEN @@ -166,10 +166,10 @@ BEGIN END IF; IF ( diff ) THEN - UPDATE Monitors + UPDATE Monitor_Status SET TotalEventDiskSpace = GREATEST(COALESCE(TotalEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0) + COALESCE(NEW.DiskSpace,0),0) - WHERE Id=OLD.MonitorId; + WHERE Monitor_Status.MonitorId=OLD.MonitorId; END IF; END; @@ -189,13 +189,13 @@ FOR EACH ROW INSERT INTO Events_Day (EventId,MonitorId,StartDateTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartDateTime,0); INSERT INTO Events_Week (EventId,MonitorId,StartDateTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartDateTime,0); INSERT INTO Events_Month (EventId,MonitorId,StartDateTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartDateTime,0); - UPDATE Monitors SET + UPDATE Monitor_Status SET HourEvents = COALESCE(HourEvents,0)+1, DayEvents = COALESCE(DayEvents,0)+1, WeekEvents = COALESCE(WeekEvents,0)+1, MonthEvents = COALESCE(MonthEvents,0)+1, TotalEvents = COALESCE(TotalEvents,0)+1 - WHERE Id=NEW.MonitorId; + WHERE Monitor_Status.MonitorId=NEW.MonitorId; END; // @@ -205,7 +205,7 @@ CREATE TRIGGER event_delete_trigger BEFORE DELETE ON Events FOR EACH ROW BEGIN IF ( OLD.DiskSpace ) THEN - UPDATE Storage SET DiskSpace = GREATEST(COALESCE(DiskSpace,0) - COALESCE(OLD.DiskSpace,0),0) WHERE Id = OLD.StorageId; + UPDATE Storage SET DiskSpace = GREATEST(COALESCE(DiskSpace,0) - COALESCE(OLD.DiskSpace,0),0) WHERE Storage.Id = OLD.StorageId; END IF; DELETE FROM Events_Hour WHERE EventId=OLD.Id; DELETE FROM Events_Day WHERE EventId=OLD.Id; @@ -213,17 +213,17 @@ BEGIN DELETE FROM Events_Month WHERE EventId=OLD.Id; IF ( OLD.Archived ) THEN DELETE FROM Events_Archived WHERE EventId=OLD.Id; - UPDATE Monitors SET + UPDATE Monitor_Status SET ArchivedEvents = GREATEST(COALESCE(ArchivedEvents,1) - 1,0), ArchivedEventDiskSpace = GREATEST(COALESCE(ArchivedEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0),0), TotalEvents = GREATEST(COALESCE(TotalEvents,1) - 1,0), TotalEventDiskSpace = GREATEST(COALESCE(TotalEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0),0) - WHERE Id=OLD.MonitorId; + WHERE Monitor_Status.MonitorId=OLD.MonitorId; ELSE - UPDATE Monitors SET + UPDATE Monitor_Status SET TotalEvents = GREATEST(COALESCE(TotalEvents,1)-1,0), TotalEventDiskSpace=GREATEST(COALESCE(TotalEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0),0) - WHERE Id=OLD.MonitorId; + WHERE Monitor_Status.MonitorId=OLD.MonitorId; END IF; END; @@ -233,14 +233,14 @@ DROP TRIGGER IF EXISTS Zone_Insert_Trigger// CREATE TRIGGER Zone_Insert_Trigger AFTER INSERT ON Zones FOR EACH ROW BEGIN - UPDATE Monitors SET ZoneCount=(SELECT COUNT(*) FROM Zones WHERE MonitorId=NEW.MonitorId) WHERE Id=NEW.MonitorID; + UPDATE Monitors SET ZoneCount=(SELECT COUNT(*) FROM Zones WHERE MonitorId=NEW.MonitorId) WHERE Monitors.Id=NEW.MonitorID; END // DROP TRIGGER IF EXISTS Zone_Delete_Trigger// CREATE TRIGGER Zone_Delete_Trigger AFTER DELETE ON Zones FOR EACH ROW BEGIN - UPDATE Monitors SET ZoneCount=(SELECT COUNT(*) FROM Zones WHERE MonitorId=OLD.MonitorId) WHERE Id=OLD.MonitorID; + UPDATE Monitors SET ZoneCount=(SELECT COUNT(*) FROM Zones WHERE MonitorId=OLD.MonitorId) WHERE Monitors.Id=OLD.MonitorID; END // diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index 40063a74c..8cbd7866d 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -525,18 +525,6 @@ CREATE TABLE `Monitors` ( `WebColour` varchar(32) NOT NULL default 'red', `Exif` tinyint(1) unsigned NOT NULL default '0', `Sequence` smallint(5) unsigned default NULL, - `TotalEvents` int(10) default NULL, - `TotalEventDiskSpace` bigint default NULL, - `HourEvents` int(10) default NULL, - `HourEventDiskSpace` bigint default NULL, - `DayEvents` int(10) default NULL, - `DayEventDiskSpace` bigint default NULL, - `WeekEvents` int(10) default NULL, - `WeekEventDiskSpace` bigint default NULL, - `MonthEvents` int(10) default NULL, - `MonthEventDiskSpace` bigint default NULL, - `ArchivedEvents` int(10) default NULL, - `ArchivedEventDiskSpace` bigint default NULL, `ZoneCount` TINYINT NOT NULL DEFAULT 0, `Refresh` int(10) unsigned default NULL, `Latitude` DECIMAL(10,8), @@ -553,6 +541,18 @@ CREATE TABLE `Monitor_Status` ( `CaptureFPS` DECIMAL(10,2) NOT NULL default 0, `AnalysisFPS` DECIMAL(5,2) NOT NULL default 0, `CaptureBandwidth` INT NOT NULL default 0, + `TotalEvents` int(10) default NULL, + `TotalEventDiskSpace` bigint default NULL, + `HourEvents` int(10) default NULL, + `HourEventDiskSpace` bigint default NULL, + `DayEvents` int(10) default NULL, + `DayEventDiskSpace` bigint default NULL, + `WeekEvents` int(10) default NULL, + `WeekEventDiskSpace` bigint default NULL, + `MonthEvents` int(10) default NULL, + `MonthEventDiskSpace` bigint default NULL, + `ArchivedEvents` int(10) default NULL, + `ArchivedEventDiskSpace` bigint default NULL, PRIMARY KEY (`MonitorId`) ) ENGINE=@ZM_MYSQL_ENGINE@; -- From 159b3832760f4212c8c016c4a4aeb8b86d0f3833 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 6 Nov 2020 13:27:47 -0500 Subject: [PATCH 0601/2339] Move event stat totals to Monitor_Status. Implement a class for them called Monitor_Status --- scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm | 24 ----- .../lib/ZoneMinder/Monitor_Status.pm | 99 +++++++++++++++++++ 2 files changed, 99 insertions(+), 24 deletions(-) create mode 100644 scripts/ZoneMinder/lib/ZoneMinder/Monitor_Status.pm diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm b/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm index 55e46e114..80b4fb75a 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm @@ -121,18 +121,6 @@ $serial = $primary_key = 'Id'; WebColour Exif Sequence - TotalEvents - TotalEventDiskSpace - HourEvents - HourEventDiskSpace - DayEvents - DayEventDiskSpace - WeekEvents - WeekEventDiskSpace - MonthEvents - MonthEventDiskSpace - ArchivedEvents - ArchivedEventDiskSpace ZoneCount Refresh DefaultCodec @@ -219,18 +207,6 @@ $serial = $primary_key = 'Id'; WebColour => '#ff0000', Exif => 0, Sequence => undef, - TotalEvents => undef, - TotalEventDiskSpace => undef, - HourEvents => undef, - HourEventDiskSpace => undef, - DayEvents => undef, - DayEventDiskSpace => undef, - WeekEvents => undef, - WeekEventDiskSpace => undef, - MonthEvents => undef, - MonthEventDiskSpace => undef, - ArchivedEvents => undef, - ArchivedEventDiskSpace => undef, ZoneCount => 0, Refresh => undef, DefaultCodec => 'auto', diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Monitor_Status.pm b/scripts/ZoneMinder/lib/ZoneMinder/Monitor_Status.pm new file mode 100644 index 000000000..059c38121 --- /dev/null +++ b/scripts/ZoneMinder/lib/ZoneMinder/Monitor_Status.pm @@ -0,0 +1,99 @@ +# ========================================================================== +# +# ZoneMinder Monitor_STatus Module +# Copyright (C) 2020 ZoneMinder +# +# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# ========================================================================== +# +# This module contains the common definitions and functions used by the rest +# of the ZoneMinder scripts +# +package ZoneMinder::Monitor_Status; + +use 5.006; +use strict; +use warnings; + +require ZoneMinder::Base; +require ZoneMinder::Object; + +#our @ISA = qw(Exporter ZoneMinder::Base); +use parent qw(ZoneMinder::Object); + +use vars qw/ $table $primary_key %fields $serial %defaults $debug/; +$table = 'Monitor_Status'; +$serial = $primary_key = 'MonitorId'; +%fields = map { $_ => $_ } qw( + MonitorId + TotalEvents + TotalEventDiskSpace + HourEvents + HourEventDiskSpace + DayEvents + DayEventDiskSpace + WeekEvents + WeekEventDiskSpace + MonthEvents + MonthEventDiskSpace + ArchivedEvents + ArchivedEventDiskSpace + ); + +%defaults = ( + TotalEvents => undef, + TotalEventDiskSpace => undef, + HourEvents => undef, + HourEventDiskSpace => undef, + DayEvents => undef, + DayEventDiskSpace => undef, + WeekEvents => undef, + WeekEventDiskSpace => undef, + MonthEvents => undef, + MonthEventDiskSpace => undef, + ArchivedEvents => undef, + ArchivedEventDiskSpace => undef, + ); + +sub Monitor { + return new ZoneMinder::Monitor( $_[0]{MonitorId} ); +} # end sub Monitor + +1; +__END__ + +=head1 NAME + +ZoneMinder::Monitor_Status - Perl Class for Monitor Status + +=head1 SYNOPSIS + +use ZoneMinder::Monitor_Status; + +=head1 AUTHOR + +Isaac Connor, Eisaac@zoneminder.comE + +=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 From 59403dc11b450b6df43e39071d745a54501e3181 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 6 Nov 2020 14:00:18 -0500 Subject: [PATCH 0602/2339] Move event stat totals to Monitor_Status. --- web/includes/Monitor.php | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/web/includes/Monitor.php b/web/includes/Monitor.php index e858135e6..00735aeda 100644 --- a/web/includes/Monitor.php +++ b/web/includes/Monitor.php @@ -113,18 +113,6 @@ class Monitor extends ZM_Object { 'WebColour' => '#ff0000', 'Exif' => array('type'=>'boolean','default'=>0), 'Sequence' => null, - 'TotalEvents' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), - 'TotalEventDiskSpace' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), - 'HourEvents' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), - 'HourEventDiskSpace' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), - 'DayEvents' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), - 'DayEventDiskSpace' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), - 'WeekEvents' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), - 'WeekEventDiskSpace' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), - 'MonthEvents' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), - 'MonthEventDiskSpace' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), - 'ArchivedEvents' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), - 'ArchivedEventDiskSpace' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), 'ZoneCount' => 0, 'Refresh' => null, 'DefaultCodec' => 'auto', @@ -137,6 +125,18 @@ class Monitor extends ZM_Object { 'AnalysisFPS' => null, 'CaptureFPS' => null, 'CaptureBandwidth' => null, + 'TotalEvents' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), + 'TotalEventDiskSpace' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), + 'HourEvents' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), + 'HourEventDiskSpace' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), + 'DayEvents' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), + 'DayEventDiskSpace' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), + 'WeekEvents' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), + 'WeekEventDiskSpace' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), + 'MonthEvents' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), + 'MonthEventDiskSpace' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), + 'ArchivedEvents' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), + 'ArchivedEventDiskSpace' => array('type'=>'integer', 'default'=>null, 'do_not_update'=>1), ); public function Control() { From 98e296a2c8a92153ff8d98942b66b24477b8bcb4 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 6 Nov 2020 14:15:05 -0500 Subject: [PATCH 0603/2339] Move event stat totals to Monitor_Status. --- db/zm_update-1.35.14.sql | 556 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 556 insertions(+) create mode 100644 db/zm_update-1.35.14.sql diff --git a/db/zm_update-1.35.14.sql b/db/zm_update-1.35.14.sql new file mode 100644 index 000000000..c2d02bf49 --- /dev/null +++ b/db/zm_update-1.35.14.sql @@ -0,0 +1,556 @@ + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Monitor_Status' + AND column_name = 'TotalEvents' + ) > 0, +"SELECT 'Column TotalEvents already exists in Monitor_Status'", +"ALTER TABLE `Monitor_Status` ADD `TotalEvents` INT(10) AFTER `CaptureBandwidth`" +)); +PREPARE stmt FROM @s; +EXECUTE stmt; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Monitors' + AND column_name = 'TotalEvents' + ) > 0, +"SELECT 'Column TotalEvents is already removed from Monitors'", +"ALTER TABLE `Monitors` DROP `TotalEvents`" +)); +PREPARE stmt FROM @s; +EXECUTE stmt; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Monitor_Status' + AND column_name = 'TotalEventDiskSpace' + ) > 0, +"SELECT 'Column TotalEventDiskSpace already exists in Monitor_Status'", +"ALTER TABLE `Monitor_Status` ADD `TotalEventDiskSpace` BIGINT AFTER `TotalEvents`" +)); +PREPARE stmt FROM @s; +EXECUTE stmt; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Monitors' + AND column_name = 'TotalEventDiskSpace' + ) > 0, +"SELECT 'Column TotalEventDiskSpace is already removed from Monitors'", +"ALTER TABLE `Monitors` DROP `TotalEventDiskSpace`" +)); +PREPARE stmt FROM @s; +EXECUTE stmt; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Monitor_Status' + AND column_name = 'HourEvents' + ) > 0, +"SELECT 'Column HourEvents already exists in Monitors'", +"ALTER TABLE `Monitor_Status` ADD `HourEvents` INT(10) AFTER `TotalEventDiskSpace`" +)); +PREPARE stmt FROM @s; +EXECUTE stmt; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Monitors' + AND column_name = 'HourEvents' + ) > 0, +"ALTER TABLE `Monitors` DROP `HourEvents`" +"SELECT 'Column HourEvents is already removed from Monitors'", +)); +PREPARE stmt FROM @s; +EXECUTE stmt; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Monitor_Status' + AND column_name = 'HourEventDiskSpace' + ) > 0, +"SELECT 'Column HourEventDiskSpace already exists in Monitor_Status'", +"ALTER TABLE `Monitor_Status` ADD `HourEventDiskSpace` BIGINT AFTER `HourEvents`" +)); +PREPARE stmt FROM @s; +EXECUTE stmt; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Monitors' + AND column_name = 'HourEventDiskSpace' + ) > 0, +"ALTER TABLE `Monitors` DROP `HourEventDiskSpace`" +"SELECT 'Column HourEventDiskSpace is already removed from Monitors'", +)); +PREPARE stmt FROM @s; +EXECUTE stmt; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Monitor_Status' + AND column_name = 'DayEvents' + ) > 0, +"SELECT 'Column DayEvents already exists in Monitor_Status'", +"ALTER TABLE `Monitor_Status` ADD `DayEvents` INT(10) AFTER `HourEventDiskSpace`" +)); +PREPARE stmt FROM @s; +EXECUTE stmt; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Monitors' + AND column_name = 'DayEvents' + ) > 0, +"ALTER TABLE `Monitors` DROP `DayEvents`" +"SELECT 'Column DayEvents is already removed from Monitors'", +)); +PREPARE stmt FROM @s; +EXECUTE stmt; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Monitor_Status' + AND column_name = 'DayEventDiskSpace' + ) > 0, +"SELECT 'Column DayEventDiskSpace already exists in Monitor_Status'", +"ALTER TABLE `Monitor_Status` ADD `DayEventDiskSpace` BIGINT AFTER `DayEvents`" +)); +PREPARE stmt FROM @s; +EXECUTE stmt; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Monitors' + AND column_name = 'DayEventDiskSpace' + ) > 0, +"ALTER TABLE `Monitors` DROP `DayEventDiskSpace`" +"SELECT 'Column DayEventDiskSpace is already removed from Monitors'", +)); +PREPARE stmt FROM @s; +EXECUTE stmt; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Monitor_Status' + AND column_name = 'WeekEvents' + ) > 0, +"SELECT 'Column WeekEvents already exists in Monitor_Status'", +"ALTER TABLE `Monitor_Status` ADD `WeekEvents` INT(10) AFTER `DayEventDiskSpace`" +)); +PREPARE stmt FROM @s; +EXECUTE stmt; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Monitors' + AND column_name = 'WeekEvents' + ) > 0, +"ALTER TABLE `Monitors` DROP `WeekEvents`" +"SELECT 'Column WeekEvents is already removed from Monitors'", +)); +PREPARE stmt FROM @s; +EXECUTE stmt; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Monitor_Status' + AND column_name = 'WeekEventDiskSpace' + ) > 0, +"SELECT 'Column WeekEventDiskSpace already exists in Monitor_Status'", +"ALTER TABLE `Monitor_Status` ADD `WeekEventDiskSpace` BIGINT AFTER `WeekEvents`" +)); +PREPARE stmt FROM @s; +EXECUTE stmt; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Monitors' + AND column_name = 'WeekEventDiskSpace' + ) > 0, +"ALTER TABLE `Monitors` DROP `WeekEventDiskSpace`" +"SELECT 'Column WeekEventDiskSpace is already removed from Monitors'", +)); +PREPARE stmt FROM @s; +EXECUTE stmt; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Monitor_Status' + AND column_name = 'MonthEvents' + ) > 0, +"SELECT 'Column MonthEvents already exists in Monitor_Status'", +"ALTER TABLE `Monitor_Status` ADD `MonthEvents` INT(10) AFTER `WeekEventDiskSpace`" +)); +PREPARE stmt FROM @s; +EXECUTE stmt; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Monitors' + AND column_name = 'MonthEvents' + ) > 0, +"ALTER TABLE `Monitors` DROP `MonthEvents`" +"SELECT 'Column MonthEvents is already removed from Monitors'", +)); +PREPARE stmt FROM @s; +EXECUTE stmt; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Monitor_Status' + AND column_name = 'MonthEventDiskSpace' + ) > 0, +"SELECT 'Column MonthEventDiskSpace already exists in Monitor_Status'", +"ALTER TABLE `Monitor_Status` ADD `MonthEventDiskSpace` BIGINT AFTER `MonthEvents`" +)); +PREPARE stmt FROM @s; +EXECUTE stmt; + + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Monitors' + AND column_name = 'MonthEventDiskSpace' + ) > 0, +"ALTER TABLE `Monitors` DROP `MonthEventDiskSpace`" +"SELECT 'Column MonthEventDiskSpace is already removed from Monitors'", +)); +PREPARE stmt FROM @s; +EXECUTE stmt; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Monitor_Status' + AND column_name = 'ArchivedEvents' + ) > 0, +"SELECT 'Column ArchivedEvents already exists in Monitor_Status'", +"ALTER TABLE `Monitor_Status` ADD `ArchivedEvents` INT(10) AFTER `MonthEventDiskSpace`" +)); +PREPARE stmt FROM @s; +EXECUTE stmt; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Monitors' + AND column_name = 'ArchivedEvents' + ) > 0, +"ALTER TABLE `Monitors` DROP `ArchivedEvents`" +"SELECT 'Column ArchivedEvents is already removed from Monitors'", +)); +PREPARE stmt FROM @s; +EXECUTE stmt; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Monitor_Status' + AND column_name = 'ArchivedEventDiskSpace' + ) > 0, +"SELECT 'Column ArchivedEventDiskSpace already exists in Monitor_Status'", +"ALTER TABLE `Monitor_Status` ADD `ArchivedEventDiskSpace` BIGINT AFTER `ArchivedEvents`" +)); +PREPARE stmt FROM @s; +EXECUTE stmt; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Monitors' + AND column_name = 'ArchivedEventDiskSpace' + ) > 0, +"ALTER TABLE `Monitors` DROP `ArchivedEventDiskSpace`" +"SELECT 'Column ArchivedEventDiskSpace is already removed from Monitors'", +)); +PREPARE stmt FROM @s; +EXECUTE stmt; + +UPDATE Monitor_Status INNER JOIN ( + SELECT MonitorId, + COUNT(Id) AS TotalEvents, + SUM(DiskSpace) AS TotalEventDiskSpace, + SUM(IF(Archived,1,0)) AS ArchivedEvents, + SUM(IF(Archived,DiskSpace,0)) AS ArchivedEventDiskSpace, + SUM(IF(StartDateTime > DATE_SUB(NOW(), INTERVAL 1 hour),1,0)) AS HourEvents, + SUM(IF(StartDateTime > DATE_SUB(NOW(), INTERVAL 1 hour),DiskSpace,0)) AS HourEventDiskSpace, + SUM(IF(StartDateTime > DATE_SUB(NOW(), INTERVAL 1 day),1,0)) AS DayEvents, + SUM(IF(StartDateTime > DATE_SUB(NOW(), INTERVAL 1 day),DiskSpace,0)) AS DayEventDiskSpace, + SUM(IF(StartDateTime > DATE_SUB(NOW(), INTERVAL 1 week),1,0)) AS WeekEvents, + SUM(IF(StartDateTime > DATE_SUB(NOW(), INTERVAL 1 week),DiskSpace,0)) AS WeekEventDiskSpace, + SUM(IF(StartDateTime > DATE_SUB(NOW(), INTERVAL 1 month),1,0)) AS MonthEvents, + SUM(IF(StartDateTime > DATE_SUB(NOW(), INTERVAL 1 month),DiskSpace,0)) AS MonthEventDiskSpace + FROM Events GROUP BY MonitorId + ) AS E ON E.MonitorId=Monitor_Status.MonitorId SET + Monitor_Status.TotalEvents = E.TotalEvents, + Monitor_Status.TotalEventDiskSpace = E.TotalEventDiskSpace, + Monitor_Status.ArchivedEvents = E.ArchivedEvents, + Monitor_Status.ArchivedEventDiskSpace = E.ArchivedEventDiskSpace, + Monitor_Status.HourEvents = E.HourEvents, + Monitor_Status.HourEventDiskSpace = E.HourEventDiskSpace, + Monitor_Status.DayEvents = E.DayEvents, + Monitor_Status.DayEventDiskSpace = E.DayEventDiskSpace, + Monitor_Status.WeekEvents = E.WeekEvents, + Monitor_Status.WeekEventDiskSpace = E.WeekEventDiskSpace, + Monitor_Status.MonthEvents = E.MonthEvents, + Monitor_Status.MonthEventDiskSpace = E.MonthEventDiskSpace; + + +delimiter // +DROP TRIGGER IF EXISTS Events_Hour_delete_trigger// +CREATE TRIGGER Events_Hour_delete_trigger BEFORE DELETE ON Events_Hour +FOR EACH ROW BEGIN + UPDATE Monitor_Status SET + HourEvents = GREATEST(COALESCE(HourEvents,1)-1,0), + HourEventDiskSpace=GREATEST(COALESCE(HourEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0),0) + WHERE Monitor_Status.MonitorId=OLD.MonitorId; +END; +// + +DROP TRIGGER IF EXISTS Events_Hour_update_trigger// + +CREATE TRIGGER Events_Hour_update_trigger AFTER UPDATE ON Events_Hour +FOR EACH ROW + BEGIN + declare diff BIGINT default 0; + + set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); + IF ( diff ) THEN + IF ( NEW.MonitorID != OLD.MonitorID ) THEN + UPDATE Monitor_Status SET HourEventDiskSpace=GREATEST(COALESCE(HourEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0),0) WHERE Monitor_Status.Id=OLD.MonitorId; + UPDATE Monitor_Status SET HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)+COALESCE(NEW.DiskSpace,0) WHERE Monitor_Status.Id=NEW.MonitorId; + ELSE + UPDATE Monitor_Status SET HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)+diff WHERE Monitor_Status.Id=NEW.MonitorId; + END IF; + END IF; + END; +// + +DROP TRIGGER IF EXISTS Events_Day_delete_trigger// +CREATE TRIGGER Events_Day_delete_trigger BEFORE DELETE ON Events_Day +FOR EACH ROW BEGIN + UPDATE Monitor_Status SET + DayEvents = GREATEST(COALESCE(DayEvents,1)-1,0), + DayEventDiskSpace=GREATEST(COALESCE(DayEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0),0) + WHERE Monitor_Status.MonitorId=OLD.MonitorId; +END; +// + +DROP TRIGGER IF EXISTS Events_Day_update_trigger; +CREATE TRIGGER Events_Day_update_trigger AFTER UPDATE ON Events_Day +FOR EACH ROW + BEGIN + declare diff BIGINT default 0; + + set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); + IF ( diff ) THEN + IF ( NEW.MonitorID != OLD.MonitorID ) THEN + UPDATE Monitor_Status SET DayEventDiskSpace=GREATEST(COALESCE(DayEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0),0) WHERE Monitor_Status.Id=OLD.MonitorId; + UPDATE Monitor_Status SET DayEventDiskSpace=COALESCE(DayEventDiskSpace,0)+COALESCE(NEW.DiskSpace,0) WHERE Monitor_Status.Id=NEW.MonitorId; + ELSE + UPDATE Monitor_Status SET DayEventDiskSpace=GREATEST(COALESCE(DayEventDiskSpace,0)+diff,0) WHERE Monitor_Status.Id=NEW.MonitorId; + END IF; + END IF; + END; + // + + +DROP TRIGGER IF EXISTS Events_Week_delete_trigger// +CREATE TRIGGER Events_Week_delete_trigger BEFORE DELETE ON Events_Week +FOR EACH ROW BEGIN + UPDATE Monitor_Status SET + WeekEvents = GREATEST(COALESCE(WeekEvents,1)-1,0), + WeekEventDiskSpace=GREATEST(COALESCE(WeekEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0),0) + WHERE Monitor_Status.MonitorId=OLD.MonitorId; +END; +// + +DROP TRIGGER IF EXISTS Events_Week_update_trigger; +CREATE TRIGGER Events_Week_update_trigger AFTER UPDATE ON Events_Week +FOR EACH ROW + BEGIN + declare diff BIGINT default 0; + + set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); + IF ( diff ) THEN + IF ( NEW.MonitorID != OLD.MonitorID ) THEN + UPDATE Monitor_Status SET WeekEventDiskSpace=GREATEST(COALESCE(WeekEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0),0) WHERE Monitor_Status.Id=OLD.MonitorId; + UPDATE Monitor_Status SET WeekEventDiskSpace=COALESCE(WeekEventDiskSpace,0)+COALESCE(NEW.DiskSpace,0) WHERE Monitor_Status.Id=NEW.MonitorId; + ELSE + UPDATE Monitor_Status SET WeekEventDiskSpace=GREATEST(COALESCE(WeekEventDiskSpace,0)+diff,0) WHERE Monitor_Status.Id=NEW.MonitorId; + END IF; + END IF; + END; + // + +DROP TRIGGER IF EXISTS Events_Month_delete_trigger// +CREATE TRIGGER Events_Month_delete_trigger BEFORE DELETE ON Events_Month +FOR EACH ROW BEGIN + UPDATE Monitor_Status SET + MonthEvents = GREATEST(COALESCE(MonthEvents,1)-1,0), + MonthEventDiskSpace=GREATEST(COALESCE(MonthEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0),0) + WHERE Monitor_Status.MonitorId=OLD.MonitorId; +END; +// + +DROP TRIGGER IF EXISTS Events_Month_update_trigger; +CREATE TRIGGER Events_Month_update_trigger AFTER UPDATE ON Events_Month +FOR EACH ROW + BEGIN + declare diff BIGINT default 0; + + set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); + IF ( diff ) THEN + IF ( NEW.MonitorID != OLD.MonitorID ) THEN + UPDATE Monitor_Status SET MonthEventDiskSpace=GREATEST(COALESCE(MonthEventDiskSpace,0)-COALESCE(OLD.DiskSpace),0) WHERE Monitor_Status.Id=OLD.MonitorId; + UPDATE Monitor_Status SET MonthEventDiskSpace=COALESCE(MonthEventDiskSpace,0)+COALESCE(NEW.DiskSpace) WHERE Monitor_Status.Id=NEW.MonitorId; + ELSE + UPDATE Monitor_Status SET MonthEventDiskSpace=GREATEST(COALESCE(MonthEventDiskSpace,0)+diff,0) WHERE Monitor_Status.Id=NEW.MonitorId; + END IF; + END IF; + END; + // + +drop procedure if exists update_storage_stats// + +drop trigger if exists event_update_trigger// + +CREATE TRIGGER event_update_trigger AFTER UPDATE ON Events +FOR EACH ROW +BEGIN + declare diff BIGINT default 0; + + set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); + IF ( NEW.StorageId = OLD.StorageID ) THEN + IF ( diff ) THEN + UPDATE Storage SET DiskSpace = GREATEST(COALESCE(DiskSpace,0) + diff,0) WHERE Monitor_Status.MonitorId = OLD.StorageId; + END IF; + ELSE + IF ( NEW.DiskSpace ) THEN + UPDATE Storage SET DiskSpace = COALESCE(DiskSpace,0) + NEW.DiskSpace WHERE Monitor_Status.MonitorId = NEW.StorageId; + END IF; + IF ( OLD.DiskSpace ) THEN + UPDATE Storage SET DiskSpace = GREATEST(COALESCE(DiskSpace,0) - OLD.DiskSpace,0) WHERE Monitor_Status.MonitorId = OLD.StorageId; + END IF; + END IF; + + UPDATE Events_Hour SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; + UPDATE Events_Day SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; + UPDATE Events_Week SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; + UPDATE Events_Month SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; + + IF ( NEW.Archived != OLD.Archived ) THEN + IF ( NEW.Archived ) THEN + INSERT INTO Events_Archived (EventId,MonitorId,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.DiskSpace); + UPDATE Monitor_Status SET ArchivedEvents = COALESCE(ArchivedEvents,0)+1, ArchivedEventDiskSpace = COALESCE(ArchivedEventDiskSpace,0) + COALESCE(NEW.DiskSpace,0) WHERE Monitor_Status.MonitorId=NEW.MonitorId; + ELSEIF ( OLD.Archived ) THEN + DELETE FROM Events_Archived WHERE EventId=OLD.Id; + UPDATE Monitor_Status + SET + ArchivedEvents = GREATEST(COALESCE(ArchivedEvents,0)-1,0), + ArchivedEventDiskSpace = GREATEST(COALESCE(ArchivedEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0),0) + WHERE Monitor_Status.Id=OLD.MonitorId; + ELSE + IF ( OLD.DiskSpace != NEW.DiskSpace ) THEN + UPDATE Events_Archived SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; + UPDATE Monitor_Status SET + ArchivedEventDiskSpace = GREATEST(COALESCE(ArchivedEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0) + COALESCE(NEW.DiskSpace,0),0) + WHERE Monitor_Status.Id=OLD.MonitorId; + END IF; + END IF; + ELSEIF ( NEW.Archived AND diff ) THEN + UPDATE Events_Archived SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; + END IF; + + IF ( diff ) THEN + UPDATE Monitor_Status + SET + TotalEventDiskSpace = GREATEST(COALESCE(TotalEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0) + COALESCE(NEW.DiskSpace,0),0) + WHERE Monitor_Status.MonitorId=OLD.MonitorId; + END IF; + +END; + +// + +DROP TRIGGER IF EXISTS event_insert_trigger// + +/* The assumption is that when an Event is inserted, it has no size yet, so don't bother updating the DiskSpace, just the count. + * The DiskSpace will get update in the Event Update Trigger + */ +CREATE TRIGGER event_insert_trigger AFTER INSERT ON Events +FOR EACH ROW + BEGIN + + INSERT INTO Events_Hour (EventId,MonitorId,StartDateTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartDateTime,0); + INSERT INTO Events_Day (EventId,MonitorId,StartDateTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartDateTime,0); + INSERT INTO Events_Week (EventId,MonitorId,StartDateTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartDateTime,0); + INSERT INTO Events_Month (EventId,MonitorId,StartDateTime,DiskSpace) VALUES (NEW.Id,NEW.MonitorId,NEW.StartDateTime,0); + UPDATE Monitor_Status SET + HourEvents = COALESCE(HourEvents,0)+1, + DayEvents = COALESCE(DayEvents,0)+1, + WeekEvents = COALESCE(WeekEvents,0)+1, + MonthEvents = COALESCE(MonthEvents,0)+1, + TotalEvents = COALESCE(TotalEvents,0)+1 + WHERE Monitor_Status.MonitorId=NEW.MonitorId; +END; +// + +DROP TRIGGER IF EXISTS event_delete_trigger// + +CREATE TRIGGER event_delete_trigger BEFORE DELETE ON Events +FOR EACH ROW +BEGIN + IF ( OLD.DiskSpace ) THEN + UPDATE Storage SET DiskSpace = GREATEST(COALESCE(DiskSpace,0) - COALESCE(OLD.DiskSpace,0),0) WHERE Monitor_Status.MonitorId = OLD.StorageId; + END IF; + DELETE FROM Events_Hour WHERE EventId=OLD.Id; + DELETE FROM Events_Day WHERE EventId=OLD.Id; + DELETE FROM Events_Week WHERE EventId=OLD.Id; + DELETE FROM Events_Month WHERE EventId=OLD.Id; + IF ( OLD.Archived ) THEN + DELETE FROM Events_Archived WHERE EventId=OLD.Id; + UPDATE Monitor_Status SET + ArchivedEvents = GREATEST(COALESCE(ArchivedEvents,1) - 1,0), + ArchivedEventDiskSpace = GREATEST(COALESCE(ArchivedEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0),0), + TotalEvents = GREATEST(COALESCE(TotalEvents,1) - 1,0), + TotalEventDiskSpace = GREATEST(COALESCE(TotalEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0),0) + WHERE Monitor_Status.MonitorId=OLD.MonitorId; + ELSE + UPDATE Monitor_Status SET + TotalEvents = GREATEST(COALESCE(TotalEvents,1)-1,0), + TotalEventDiskSpace=GREATEST(COALESCE(TotalEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0),0) + WHERE Monitor_Status.MonitorId=OLD.MonitorId; + END IF; +END; + +// + +DELIMITER ; + +UPDATE Monitor_Status INNER JOIN ( + SELECT MonitorId, + COUNT(Id) AS TotalEvents, + SUM(DiskSpace) AS TotalEventDiskSpace, + SUM(IF(Archived,1,0)) AS ArchivedEvents, + SUM(IF(Archived,DiskSpace,0)) AS ArchivedEventDiskSpace, + SUM(IF(StartDateTime > DATE_SUB(NOW(), INTERVAL 1 hour),1,0)) AS HourEvents, + SUM(IF(StartDateTime > DATE_SUB(NOW(), INTERVAL 1 hour),DiskSpace,0)) AS HourEventDiskSpace, + SUM(IF(StartDateTime > DATE_SUB(NOW(), INTERVAL 1 day),1,0)) AS DayEvents, + SUM(IF(StartDateTime > DATE_SUB(NOW(), INTERVAL 1 day),DiskSpace,0)) AS DayEventDiskSpace, + SUM(IF(StartDateTime > DATE_SUB(NOW(), INTERVAL 1 week),1,0)) AS WeekEvents, + SUM(IF(StartDateTime > DATE_SUB(NOW(), INTERVAL 1 week),DiskSpace,0)) AS WeekEventDiskSpace, + SUM(IF(StartDateTime > DATE_SUB(NOW(), INTERVAL 1 month),1,0)) AS MonthEvents, + SUM(IF(StartDateTime > DATE_SUB(NOW(), INTERVAL 1 month),DiskSpace,0)) AS MonthEventDiskSpace + FROM Events GROUP BY MonitorId + ) AS E ON E.MonitorId=Monitor_Status.MonitorId SET + Monitor_Status.TotalEvents = E.TotalEvents, + Monitor_Status.TotalEventDiskSpace = E.TotalEventDiskSpace, + Monitor_Status.ArchivedEvents = E.ArchivedEvents, + Monitor_Status.ArchivedEventDiskSpace = E.ArchivedEventDiskSpace, + Monitor_Status.HourEvents = E.HourEvents, + Monitor_Status.HourEventDiskSpace = E.HourEventDiskSpace, + Monitor_Status.DayEvents = E.DayEvents, + Monitor_Status.DayEventDiskSpace = E.DayEventDiskSpace, + Monitor_Status.WeekEvents = E.WeekEvents, + Monitor_Status.WeekEventDiskSpace = E.WeekEventDiskSpace, + Monitor_Status.MonthEvents = E.MonthEvents, + Monitor_Status.MonthEventDiskSpace = E.MonthEventDiskSpace; From a3a6d94b6ffe36d67b040448c401949beae996e6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 6 Nov 2020 14:16:34 -0500 Subject: [PATCH 0604/2339] bump version to 1.15.14 --- distros/redhat/zoneminder.spec | 2 +- version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index 220f38652..af62cefba 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -28,7 +28,7 @@ %global _hardened_build 1 Name: zoneminder -Version: 1.35.13 +Version: 1.35.14 Release: 1%{?dist} Summary: A camera monitoring and analysis tool Group: System Environment/Daemons diff --git a/version b/version index 8cf7685bd..31d4ef08d 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.35.13 +1.35.14 From 691ff5881d5d796d9f05674366921d5f1db525d6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 6 Nov 2020 14:28:11 -0500 Subject: [PATCH 0605/2339] Fix some commas --- db/zm_update-1.35.14.sql | 41 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/db/zm_update-1.35.14.sql b/db/zm_update-1.35.14.sql index c2d02bf49..c473cdc39 100644 --- a/db/zm_update-1.35.14.sql +++ b/db/zm_update-1.35.14.sql @@ -59,8 +59,8 @@ SET @s = (SELECT IF( AND table_name = 'Monitors' AND column_name = 'HourEvents' ) > 0, -"ALTER TABLE `Monitors` DROP `HourEvents`" -"SELECT 'Column HourEvents is already removed from Monitors'", +"ALTER TABLE `Monitors` DROP `HourEvents`", +"SELECT 'Column HourEvents is already removed from Monitors'" )); PREPARE stmt FROM @s; EXECUTE stmt; @@ -81,8 +81,8 @@ SET @s = (SELECT IF( AND table_name = 'Monitors' AND column_name = 'HourEventDiskSpace' ) > 0, -"ALTER TABLE `Monitors` DROP `HourEventDiskSpace`" -"SELECT 'Column HourEventDiskSpace is already removed from Monitors'", +"ALTER TABLE `Monitors` DROP `HourEventDiskSpace`", +"SELECT 'Column HourEventDiskSpace is already removed from Monitors'" )); PREPARE stmt FROM @s; EXECUTE stmt; @@ -103,8 +103,8 @@ SET @s = (SELECT IF( AND table_name = 'Monitors' AND column_name = 'DayEvents' ) > 0, -"ALTER TABLE `Monitors` DROP `DayEvents`" -"SELECT 'Column DayEvents is already removed from Monitors'", +"ALTER TABLE `Monitors` DROP `DayEvents`", +"SELECT 'Column DayEvents is already removed from Monitors'" )); PREPARE stmt FROM @s; EXECUTE stmt; @@ -125,8 +125,8 @@ SET @s = (SELECT IF( AND table_name = 'Monitors' AND column_name = 'DayEventDiskSpace' ) > 0, -"ALTER TABLE `Monitors` DROP `DayEventDiskSpace`" -"SELECT 'Column DayEventDiskSpace is already removed from Monitors'", +"ALTER TABLE `Monitors` DROP `DayEventDiskSpace`", +"SELECT 'Column DayEventDiskSpace is already removed from Monitors'" )); PREPARE stmt FROM @s; EXECUTE stmt; @@ -147,8 +147,8 @@ SET @s = (SELECT IF( AND table_name = 'Monitors' AND column_name = 'WeekEvents' ) > 0, -"ALTER TABLE `Monitors` DROP `WeekEvents`" -"SELECT 'Column WeekEvents is already removed from Monitors'", +"ALTER TABLE `Monitors` DROP `WeekEvents`", +"SELECT 'Column WeekEvents is already removed from Monitors'" )); PREPARE stmt FROM @s; EXECUTE stmt; @@ -169,8 +169,8 @@ SET @s = (SELECT IF( AND table_name = 'Monitors' AND column_name = 'WeekEventDiskSpace' ) > 0, -"ALTER TABLE `Monitors` DROP `WeekEventDiskSpace`" -"SELECT 'Column WeekEventDiskSpace is already removed from Monitors'", +"ALTER TABLE `Monitors` DROP `WeekEventDiskSpace`", +"SELECT 'Column WeekEventDiskSpace is already removed from Monitors'" )); PREPARE stmt FROM @s; EXECUTE stmt; @@ -191,8 +191,8 @@ SET @s = (SELECT IF( AND table_name = 'Monitors' AND column_name = 'MonthEvents' ) > 0, -"ALTER TABLE `Monitors` DROP `MonthEvents`" -"SELECT 'Column MonthEvents is already removed from Monitors'", +"ALTER TABLE `Monitors` DROP `MonthEvents`", +"SELECT 'Column MonthEvents is already removed from Monitors'" )); PREPARE stmt FROM @s; EXECUTE stmt; @@ -208,14 +208,13 @@ SET @s = (SELECT IF( PREPARE stmt FROM @s; EXECUTE stmt; - SET @s = (SELECT IF( (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() AND table_name = 'Monitors' AND column_name = 'MonthEventDiskSpace' ) > 0, -"ALTER TABLE `Monitors` DROP `MonthEventDiskSpace`" -"SELECT 'Column MonthEventDiskSpace is already removed from Monitors'", +"ALTER TABLE `Monitors` DROP `MonthEventDiskSpace`", +"SELECT 'Column MonthEventDiskSpace is already removed from Monitors'" )); PREPARE stmt FROM @s; EXECUTE stmt; @@ -236,8 +235,8 @@ SET @s = (SELECT IF( AND table_name = 'Monitors' AND column_name = 'ArchivedEvents' ) > 0, -"ALTER TABLE `Monitors` DROP `ArchivedEvents`" -"SELECT 'Column ArchivedEvents is already removed from Monitors'", +"ALTER TABLE `Monitors` DROP `ArchivedEvents`", +"SELECT 'Column ArchivedEvents is already removed from Monitors'" )); PREPARE stmt FROM @s; EXECUTE stmt; @@ -258,8 +257,8 @@ SET @s = (SELECT IF( AND table_name = 'Monitors' AND column_name = 'ArchivedEventDiskSpace' ) > 0, -"ALTER TABLE `Monitors` DROP `ArchivedEventDiskSpace`" -"SELECT 'Column ArchivedEventDiskSpace is already removed from Monitors'", +"ALTER TABLE `Monitors` DROP `ArchivedEventDiskSpace`", +"SELECT 'Column ArchivedEventDiskSpace is already removed from Monitors'" )); PREPARE stmt FROM @s; EXECUTE stmt; From 2e7aa178828b5bd2d2f579cd782cdf1568fb0272 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 6 Nov 2020 14:32:21 -0500 Subject: [PATCH 0606/2339] Fix triggers that update Storage --- db/zm_update-1.35.14.sql | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/db/zm_update-1.35.14.sql b/db/zm_update-1.35.14.sql index c473cdc39..c961fe0c2 100644 --- a/db/zm_update-1.35.14.sql +++ b/db/zm_update-1.35.14.sql @@ -420,14 +420,14 @@ BEGIN set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); IF ( NEW.StorageId = OLD.StorageID ) THEN IF ( diff ) THEN - UPDATE Storage SET DiskSpace = GREATEST(COALESCE(DiskSpace,0) + diff,0) WHERE Monitor_Status.MonitorId = OLD.StorageId; + UPDATE Storage SET DiskSpace = GREATEST(COALESCE(DiskSpace,0) + diff,0) WHERE Storage.Id = OLD.StorageId; END IF; ELSE IF ( NEW.DiskSpace ) THEN - UPDATE Storage SET DiskSpace = COALESCE(DiskSpace,0) + NEW.DiskSpace WHERE Monitor_Status.MonitorId = NEW.StorageId; + UPDATE Storage SET DiskSpace = COALESCE(DiskSpace,0) + NEW.DiskSpace WHERE Storage.Id = NEW.StorageId; END IF; IF ( OLD.DiskSpace ) THEN - UPDATE Storage SET DiskSpace = GREATEST(COALESCE(DiskSpace,0) - OLD.DiskSpace,0) WHERE Monitor_Status.MonitorId = OLD.StorageId; + UPDATE Storage SET DiskSpace = GREATEST(COALESCE(DiskSpace,0) - OLD.DiskSpace,0) WHERE Storage.Id = OLD.StorageId; END IF; END IF; @@ -499,7 +499,7 @@ CREATE TRIGGER event_delete_trigger BEFORE DELETE ON Events FOR EACH ROW BEGIN IF ( OLD.DiskSpace ) THEN - UPDATE Storage SET DiskSpace = GREATEST(COALESCE(DiskSpace,0) - COALESCE(OLD.DiskSpace,0),0) WHERE Monitor_Status.MonitorId = OLD.StorageId; + UPDATE Storage SET DiskSpace = GREATEST(COALESCE(DiskSpace,0) - COALESCE(OLD.DiskSpace,0),0) WHERE Storage.Id = OLD.StorageId; END IF; DELETE FROM Events_Hour WHERE EventId=OLD.Id; DELETE FROM Events_Day WHERE EventId=OLD.Id; From 4b4863c44ac75beb6f510b7e84b17f13fd4a53bc Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 6 Nov 2020 16:07:40 -0500 Subject: [PATCH 0607/2339] Fix remaining references to MonitorStatus.Id --- db/zm_update-1.35.14.sql | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/db/zm_update-1.35.14.sql b/db/zm_update-1.35.14.sql index c961fe0c2..46a6d2445 100644 --- a/db/zm_update-1.35.14.sql +++ b/db/zm_update-1.35.14.sql @@ -314,10 +314,10 @@ FOR EACH ROW set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); IF ( diff ) THEN IF ( NEW.MonitorID != OLD.MonitorID ) THEN - UPDATE Monitor_Status SET HourEventDiskSpace=GREATEST(COALESCE(HourEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0),0) WHERE Monitor_Status.Id=OLD.MonitorId; - UPDATE Monitor_Status SET HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)+COALESCE(NEW.DiskSpace,0) WHERE Monitor_Status.Id=NEW.MonitorId; + UPDATE Monitor_Status SET HourEventDiskSpace=GREATEST(COALESCE(HourEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0),0) WHERE Monitor_Status.MonitorId=OLD.MonitorId; + UPDATE Monitor_Status SET HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)+COALESCE(NEW.DiskSpace,0) WHERE Monitor_Status.MonitorId=NEW.MonitorId; ELSE - UPDATE Monitor_Status SET HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)+diff WHERE Monitor_Status.Id=NEW.MonitorId; + UPDATE Monitor_Status SET HourEventDiskSpace=COALESCE(HourEventDiskSpace,0)+diff WHERE Monitor_Status.MonitorId=NEW.MonitorId; END IF; END IF; END; @@ -342,10 +342,10 @@ FOR EACH ROW set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); IF ( diff ) THEN IF ( NEW.MonitorID != OLD.MonitorID ) THEN - UPDATE Monitor_Status SET DayEventDiskSpace=GREATEST(COALESCE(DayEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0),0) WHERE Monitor_Status.Id=OLD.MonitorId; - UPDATE Monitor_Status SET DayEventDiskSpace=COALESCE(DayEventDiskSpace,0)+COALESCE(NEW.DiskSpace,0) WHERE Monitor_Status.Id=NEW.MonitorId; + UPDATE Monitor_Status SET DayEventDiskSpace=GREATEST(COALESCE(DayEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0),0) WHERE Monitor_Status.MonitorId=OLD.MonitorId; + UPDATE Monitor_Status SET DayEventDiskSpace=COALESCE(DayEventDiskSpace,0)+COALESCE(NEW.DiskSpace,0) WHERE Monitor_Status.MonitorId=NEW.MonitorId; ELSE - UPDATE Monitor_Status SET DayEventDiskSpace=GREATEST(COALESCE(DayEventDiskSpace,0)+diff,0) WHERE Monitor_Status.Id=NEW.MonitorId; + UPDATE Monitor_Status SET DayEventDiskSpace=GREATEST(COALESCE(DayEventDiskSpace,0)+diff,0) WHERE Monitor_Status.MonitorId=NEW.MonitorId; END IF; END IF; END; @@ -371,10 +371,10 @@ FOR EACH ROW set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); IF ( diff ) THEN IF ( NEW.MonitorID != OLD.MonitorID ) THEN - UPDATE Monitor_Status SET WeekEventDiskSpace=GREATEST(COALESCE(WeekEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0),0) WHERE Monitor_Status.Id=OLD.MonitorId; - UPDATE Monitor_Status SET WeekEventDiskSpace=COALESCE(WeekEventDiskSpace,0)+COALESCE(NEW.DiskSpace,0) WHERE Monitor_Status.Id=NEW.MonitorId; + UPDATE Monitor_Status SET WeekEventDiskSpace=GREATEST(COALESCE(WeekEventDiskSpace,0)-COALESCE(OLD.DiskSpace,0),0) WHERE Monitor_Status.MonitorId=OLD.MonitorId; + UPDATE Monitor_Status SET WeekEventDiskSpace=COALESCE(WeekEventDiskSpace,0)+COALESCE(NEW.DiskSpace,0) WHERE Monitor_Status.MonitorId=NEW.MonitorId; ELSE - UPDATE Monitor_Status SET WeekEventDiskSpace=GREATEST(COALESCE(WeekEventDiskSpace,0)+diff,0) WHERE Monitor_Status.Id=NEW.MonitorId; + UPDATE Monitor_Status SET WeekEventDiskSpace=GREATEST(COALESCE(WeekEventDiskSpace,0)+diff,0) WHERE Monitor_Status.MonitorId=NEW.MonitorId; END IF; END IF; END; @@ -399,10 +399,10 @@ FOR EACH ROW set diff = COALESCE(NEW.DiskSpace,0) - COALESCE(OLD.DiskSpace,0); IF ( diff ) THEN IF ( NEW.MonitorID != OLD.MonitorID ) THEN - UPDATE Monitor_Status SET MonthEventDiskSpace=GREATEST(COALESCE(MonthEventDiskSpace,0)-COALESCE(OLD.DiskSpace),0) WHERE Monitor_Status.Id=OLD.MonitorId; - UPDATE Monitor_Status SET MonthEventDiskSpace=COALESCE(MonthEventDiskSpace,0)+COALESCE(NEW.DiskSpace) WHERE Monitor_Status.Id=NEW.MonitorId; + UPDATE Monitor_Status SET MonthEventDiskSpace=GREATEST(COALESCE(MonthEventDiskSpace,0)-COALESCE(OLD.DiskSpace),0) WHERE Monitor_Status.MonitorId=OLD.MonitorId; + UPDATE Monitor_Status SET MonthEventDiskSpace=COALESCE(MonthEventDiskSpace,0)+COALESCE(NEW.DiskSpace) WHERE Monitor_Status.MonitorId=NEW.MonitorId; ELSE - UPDATE Monitor_Status SET MonthEventDiskSpace=GREATEST(COALESCE(MonthEventDiskSpace,0)+diff,0) WHERE Monitor_Status.Id=NEW.MonitorId; + UPDATE Monitor_Status SET MonthEventDiskSpace=GREATEST(COALESCE(MonthEventDiskSpace,0)+diff,0) WHERE Monitor_Status.MonitorId=NEW.MonitorId; END IF; END IF; END; @@ -446,13 +446,13 @@ BEGIN SET ArchivedEvents = GREATEST(COALESCE(ArchivedEvents,0)-1,0), ArchivedEventDiskSpace = GREATEST(COALESCE(ArchivedEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0),0) - WHERE Monitor_Status.Id=OLD.MonitorId; + WHERE Monitor_Status.MonitorId=OLD.MonitorId; ELSE IF ( OLD.DiskSpace != NEW.DiskSpace ) THEN UPDATE Events_Archived SET DiskSpace=NEW.DiskSpace WHERE EventId=NEW.Id; UPDATE Monitor_Status SET ArchivedEventDiskSpace = GREATEST(COALESCE(ArchivedEventDiskSpace,0) - COALESCE(OLD.DiskSpace,0) + COALESCE(NEW.DiskSpace,0),0) - WHERE Monitor_Status.Id=OLD.MonitorId; + WHERE Monitor_Status.MonitorId=OLD.MonitorId; END IF; END IF; ELSEIF ( NEW.Archived AND diff ) THEN From b3e3fea79f711d4942c4f37fdda3d8d2b84729a5 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 9 Nov 2020 12:26:14 -0500 Subject: [PATCH 0608/2339] Update summary event count tables --- db/zm_update-1.35.14.sql | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/db/zm_update-1.35.14.sql b/db/zm_update-1.35.14.sql index 46a6d2445..7c9b39d99 100644 --- a/db/zm_update-1.35.14.sql +++ b/db/zm_update-1.35.14.sql @@ -525,6 +525,12 @@ END; DELIMITER ; +REPLACE INTO Events_Hour SELECT Id,MonitorId,StartDateTime,DiskSpace FROM Events WHERE StartDateTime > DATE_SUB(NOW(), INTERVAL 1 hour); +REPLACE INTO Events_Day SELECT Id,MonitorId,StartDateTime,DiskSpace FROM Events WHERE StartDateTime > DATE_SUB(NOW(), INTERVAL 1 day); +REPLACE INTO Events_Week SELECT Id,MonitorId,StartDateTime,DiskSpace FROM Events WHERE StartDateTime > DATE_SUB(NOW(), INTERVAL 1 week); +REPLACE INTO Events_Month SELECT Id,MonitorId,StartDateTime,DiskSpace FROM Events WHERE StartDateTime > DATE_SUB(NOW(), INTERVAL 1 month); +REPLACE INTO Events_Archived SELECT Id,MonitorId,DiskSpace FROM Events WHERE Archived=1; + UPDATE Monitor_Status INNER JOIN ( SELECT MonitorId, COUNT(Id) AS TotalEvents, From cda3824a257969a0f1c33862f863fe006bd4d420 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 10 Nov 2020 12:33:10 -0500 Subject: [PATCH 0609/2339] Use INSERT.. ON DUPLICATE... instead of REPLACE INTO. REPLACE INTO deletes the existing row. Since we now have event counts in there, we lose them. --- src/zmc.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/zmc.cpp b/src/zmc.cpp index 8376c91ba..e11745e43 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -243,8 +243,8 @@ int main(int argc, char *argv[]) { time_t now = (time_t)time(nullptr); monitors[i]->setStartupTime(now); - snprintf(sql, sizeof(sql), - "REPLACE INTO Monitor_Status (MonitorId, Status) VALUES ('%d','Running')", + snprintf(sql, sizeof(sql), + "INSERT INTO Monitor_Status (MonitorId,Status) VALUES (%d, 'Running') ON DUPLICATE KEY UPDATE Status='Running'", monitors[i]->Id()); if ( mysql_query(&dbconn, sql) ) { Error("Can't run query: %s", mysql_error(&dbconn)); @@ -273,7 +273,7 @@ int main(int argc, char *argv[]) { capture_delays[i] = monitors[i]->GetCaptureDelay(); alarm_capture_delays[i] = monitors[i]->GetAlarmCaptureDelay(); snprintf(sql, sizeof(sql), - "REPLACE INTO Monitor_Status (MonitorId, Status) VALUES ('%d','Connected')", + "INSERT INTO Monitor_Status (MonitorId,Status) VALUES (%d, 'Connected') ON DUPLICATE KEY UPDATE Status='Connected'", monitors[i]->Id()); if ( mysql_query(&dbconn, sql) ) { Error("Can't run query: %s", mysql_error(&dbconn)); @@ -364,7 +364,7 @@ int main(int argc, char *argv[]) { for ( int i = 0; i < n_monitors; i++ ) { static char sql[ZM_SQL_SML_BUFSIZ]; snprintf(sql, sizeof(sql), - "REPLACE INTO Monitor_Status (MonitorId, Status) VALUES ('%d','NotRunning')", + "INSERT INTO Monitor_Status (MonitorId,Status) VALUES (%d, 'Connected') ON DUPLICATE KEY UPDATE Status='NotRunning'", monitors[i]->Id()); if ( mysql_query(&dbconn, sql) ) { Error("Can't run query: %s", mysql_error(&dbconn)); From 8f456e7c3daa3655a2711d0169f868f328633590 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 10 Nov 2020 12:38:10 -0500 Subject: [PATCH 0610/2339] Add a useful warning message regarding the update needing SUPER prvilege --- db/zm_update-1.35.14.sql | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/db/zm_update-1.35.14.sql b/db/zm_update-1.35.14.sql index 7c9b39d99..daa8239ff 100644 --- a/db/zm_update-1.35.14.sql +++ b/db/zm_update-1.35.14.sql @@ -1,3 +1,16 @@ +SELECT 'This update may make changes that require SUPER privileges. If you see an error message saying: + +ERROR 1419 (HY000) at line 298: You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable) + +You will have to either run this update as root manually using something like (on ubuntu/debian) + +sudo mysql --defaults-file=/etc/mysql/debian.cnf zm < /usr/share/zoneminder/db/zm_update-1.35.14.sql + +OR + +sudo mysql --defaults-file=/etc/mysql/debian.cnf "set global log_bin_trust_function_creators=1;" +sudo zmupdate.pl +'; SET @s = (SELECT IF( (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() From 5b10fff2a0e8f04873c2d35b453aa219236b91c3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 10 Nov 2020 13:14:36 -0500 Subject: [PATCH 0611/2339] Use cached objects when using new instead of only find_one --- web/includes/Object.php | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/web/includes/Object.php b/web/includes/Object.php index e8fff930b..aa571bb59 100644 --- a/web/includes/Object.php +++ b/web/includes/Object.php @@ -11,7 +11,16 @@ class ZM_Object { $row = NULL; if ( $IdOrRow ) { + global $object_cache; + if ( ! isset($object_cache[$class]) ) { + $object_cache[$class] = array(); + } + $cache = &$object_cache[$class]; + if ( is_integer($IdOrRow) or ctype_digit($IdOrRow) ) { + if ( isset($cache[$IdOrRow]) ) { + return $cache[$IdOrRow]; + } $table = $class::$table; $row = dbFetchOne("SELECT * FROM `$table` WHERE `Id`=?", NULL, array($IdOrRow)); if ( !$row ) { @@ -22,12 +31,6 @@ class ZM_Object { } if ( $row ) { - global $object_cache; - if ( ! isset($object_cache[$class]) ) { - $object_cache[$class] = array(); - } - $cache = &$object_cache[$class]; - foreach ($row as $k => $v) { $this->{$k} = $v; } From b4aacde5bfdcc393c2815393b54dc54db4c28bb5 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 10 Nov 2020 13:15:46 -0500 Subject: [PATCH 0612/2339] Remove debug. Auth is pretty solid these days --- web/includes/auth.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/web/includes/auth.php b/web/includes/auth.php index 0268b0018..a4e1e4268 100644 --- a/web/includes/auth.php +++ b/web/includes/auth.php @@ -254,8 +254,6 @@ function userFromSession() { $sql = 'SELECT * FROM Users WHERE Enabled=1 AND Username=?'; $user = dbFetchOne($sql, NULL, array($_SESSION['username'])); } - } else { - ZM\Debug('No username in session'); } return $user; } From 330023f65b529b9d2026a85847fdddb059d205ed Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 11 Nov 2020 09:30:39 -0500 Subject: [PATCH 0613/2339] Move Events totals to Monitor_Status instead of Monitors --- scripts/zmaudit.pl.in | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/scripts/zmaudit.pl.in b/scripts/zmaudit.pl.in index 4601ea1aa..eb17faef5 100644 --- a/scripts/zmaudit.pl.in +++ b/scripts/zmaudit.pl.in @@ -885,7 +885,7 @@ FROM `Frames` WHERE `EventId`=?'; $loop = $continuous; my $eventcounts_sql = ' - UPDATE `Monitors` SET + UPDATE `Monitor_Status` SET `TotalEvents`=(SELECT COUNT(`Id`) FROM `Events` WHERE `MonitorId`=`Monitors`.`Id`), `TotalEventDiskSpace`=(SELECT SUM(`DiskSpace`) FROM `Events` WHERE `MonitorId`=`Monitors`.`Id` AND `DiskSpace` IS NOT NULL), `ArchivedEvents`=(SELECT COUNT(`Id`) FROM `Events` WHERE `MonitorId`=`Monitors`.`Id` AND `Archived`=1), @@ -897,40 +897,40 @@ FROM `Frames` WHERE `EventId`=?'; $eventcounts_sth->finish(); my $eventcounts_hour_sql = ' - UPDATE `Monitors` INNER JOIN ( + UPDATE `Monitor_Status` INNER JOIN ( SELECT `MonitorId`, COUNT(*) AS `HourEvents`, SUM(COALESCE(`DiskSpace`,0)) AS `HourEventDiskSpace` FROM `Events_Hour` GROUP BY `MonitorId` - ) AS `E` ON `E`.`MonitorId`=`Monitors`.`Id` SET - `Monitors`.`HourEvents` = `E`.`HourEvents`, - `Monitors`.`HourEventDiskSpace` = `E`.`HourEventDiskSpace` + ) AS `E` ON `E`.`MonitorId`=`Monitor_Status`.`MonitorId` SET + `Monitor_Status`.`HourEvents` = `E`.`HourEvents`, + `Monitor_Status`.`HourEventDiskSpace` = `E`.`HourEventDiskSpace` '; my $eventcounts_day_sql = ' - UPDATE `Monitors` INNER JOIN ( + UPDATE `Monitor_Status` INNER JOIN ( SELECT `MonitorId`, COUNT(*) AS `DayEvents`, SUM(COALESCE(`DiskSpace`,0)) AS `DayEventDiskSpace` FROM `Events_Day` GROUP BY `MonitorId` - ) AS `E` ON `E`.`MonitorId`=`Monitors`.`Id` SET - `Monitors`.`DayEvents` = `E`.`DayEvents`, - `Monitors`.`DayEventDiskSpace` = `E`.`DayEventDiskSpace` + ) AS `E` ON `E`.`MonitorId`=`Monitor_Status`.`MonitorId` SET + `Monitor_Status`.`DayEvents` = `E`.`DayEvents`, + `Monitor_Status`.`DayEventDiskSpace` = `E`.`DayEventDiskSpace` '; my $eventcounts_week_sql = ' - UPDATE `Monitors` INNER JOIN ( + UPDATE `Monitor_Status` INNER JOIN ( SELECT `MonitorId`, COUNT(*) AS `WeekEvents`, SUM(COALESCE(`DiskSpace`,0)) AS `WeekEventDiskSpace` FROM `Events_Week` GROUP BY `MonitorId` - ) AS `E` ON `E`.`MonitorId`=`Monitors`.`Id` SET - `Monitors`.`WeekEvents` = `E`.`WeekEvents`, - `Monitors`.`WeekEventDiskSpace` = `E`.`WeekEventDiskSpace` + ) AS `E` ON `E`.`MonitorId`=`Monitor_Status`.`MonitorId` SET + `Monitor_Status`.`WeekEvents` = `E`.`WeekEvents`, + `Monitor_Status`.`WeekEventDiskSpace` = `E`.`WeekEventDiskSpace` '; my $eventcounts_month_sql = ' - UPDATE `Monitors` INNER JOIN ( + UPDATE `Monitor_Status` INNER JOIN ( SELECT `MonitorId`, COUNT(*) AS `MonthEvents`, SUM(COALESCE(`DiskSpace`,0)) AS `MonthEventDiskSpace` FROM `Events_Month` GROUP BY `MonitorId` - ) AS `E` ON `E`.`MonitorId`=`Monitors`.`Id` SET - `Monitors`.`MonthEvents` = `E`.`MonthEvents`, - `Monitors`.`MonthEventDiskSpace` = `E`.`MonthEventDiskSpace` + ) AS `E` ON `E`.`MonitorId`=`Monitor_Status`.`MonitorId` SET + `Monitor_Status`.`MonthEvents` = `E`.`MonthEvents`, + `Monitor_Status`.`MonthEventDiskSpace` = `E`.`MonthEventDiskSpace` '; my $eventcounts_hour_sth = $dbh->prepare_cached($eventcounts_hour_sql); my $eventcounts_day_sth = $dbh->prepare_cached($eventcounts_day_sql); From 0aef0adf48716eaf9f0dbd321099bf6aa8ce93b6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 11 Nov 2020 11:32:54 -0500 Subject: [PATCH 0614/2339] Fix more Monitors.Id => Monitor_Status.MonitorId --- scripts/zmaudit.pl.in | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/zmaudit.pl.in b/scripts/zmaudit.pl.in index eb17faef5..29ff7cab9 100644 --- a/scripts/zmaudit.pl.in +++ b/scripts/zmaudit.pl.in @@ -886,10 +886,10 @@ FROM `Frames` WHERE `EventId`=?'; my $eventcounts_sql = ' UPDATE `Monitor_Status` SET - `TotalEvents`=(SELECT COUNT(`Id`) FROM `Events` WHERE `MonitorId`=`Monitors`.`Id`), - `TotalEventDiskSpace`=(SELECT SUM(`DiskSpace`) FROM `Events` WHERE `MonitorId`=`Monitors`.`Id` AND `DiskSpace` IS NOT NULL), - `ArchivedEvents`=(SELECT COUNT(`Id`) FROM `Events` WHERE `MonitorId`=`Monitors`.`Id` AND `Archived`=1), - `ArchivedEventDiskSpace`=(SELECT SUM(`DiskSpace`) FROM `Events` WHERE `MonitorId`=`Monitors`.`Id` AND `Archived`=1 AND `DiskSpace` IS NOT NULL) + `TotalEvents`=(SELECT COUNT(`Id`) FROM `Events` WHERE `MonitorId`=`Monitor_Status`.`MonitorId`), + `TotalEventDiskSpace`=(SELECT SUM(`DiskSpace`) FROM `Events` WHERE `MonitorId`=`Monitor_Status`.`MonitorId` AND `DiskSpace` IS NOT NULL), + `ArchivedEvents`=(SELECT COUNT(`Id`) FROM `Events` WHERE `MonitorId`=`Monitor_Status`.`MonitorId` AND `Archived`=1), + `ArchivedEventDiskSpace`=(SELECT SUM(`DiskSpace`) FROM `Events` WHERE `MonitorId`=`Monitor_Status`.`MonitorId` AND `Archived`=1 AND `DiskSpace` IS NOT NULL) '; my $eventcounts_sth = $dbh->prepare_cached( $eventcounts_sql ); From 52c7cc5869484ef967654b29dbd25567d90b989f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 11 Nov 2020 11:49:44 -0500 Subject: [PATCH 0615/2339] reorganize code. Remove Server caching as it is done in Object.php. --- web/ajax/log.php | 100 ++++++++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 54 deletions(-) diff --git a/web/ajax/log.php b/web/ajax/log.php index 22897fd04..60f0c1dc4 100644 --- a/web/ajax/log.php +++ b/web/ajax/log.php @@ -1,12 +1,13 @@ "search text" pairs -// Bootstrap table sends json_ecoded array, which we must decode -$advsearch = isset($_REQUEST['filter']) ? json_decode($_REQUEST['filter'], JSON_OBJECT_AS_ARRAY) : array(); - -// Sort specifies the name of the column to sort on -$sort = 'TimeKey'; -if ( isset($_REQUEST['sort']) ) { - $sort = $_REQUEST['sort']; - if ( $sort == 'DateTime' ) $sort = 'TimeKey'; -} - -// Offset specifies the starting row to return, used for pagination -$offset = 0; -if ( isset($_REQUEST['offset']) ) { - if ( ( !is_int($_REQUEST['offset']) and !ctype_digit($_REQUEST['offset']) ) ) { - ZM\Error('Invalid value for offset: ' . $_REQUEST['offset']); - } else { - $offset = $_REQUEST['offset']; - } -} - -// Order specifies the sort direction, either asc or desc -$order = (isset($_REQUEST['order']) and (strtolower($_REQUEST['order']) == 'asc')) ? 'ASC' : 'DESC'; - -// Limit specifies the number of rows to return -$limit = 100; -if ( isset($_REQUEST['limit']) ) { - if ( ( !is_int($_REQUEST['limit']) and !ctype_digit($_REQUEST['limit']) ) ) { - ZM\Error('Invalid value for limit: ' . $_REQUEST['limit']); - } else { - $limit = $_REQUEST['limit']; - } -} - // // MAIN LOOP // @@ -69,7 +33,7 @@ switch ( $task ) { createRequest(); break; case 'query' : - $data = queryRequest($search, $advsearch, $sort, $offset, $order, $limit); + $data = queryRequest(); break; default : ZM\Fatal('Unrecognised task '.$task); @@ -105,9 +69,27 @@ function createRequest() { } } -function queryRequest($search, $advsearch, $sort, $offset, $order, $limit) { - global $Servers; +function queryRequest() { + // Offset specifies the starting row to return, used for pagination + $offset = 0; + if ( isset($_REQUEST['offset']) ) { + if ( ( !is_int($_REQUEST['offset']) and !ctype_digit($_REQUEST['offset']) ) ) { + ZM\Error('Invalid value for offset: ' . $_REQUEST['offset']); + } else { + $offset = $_REQUEST['offset']; + } + } + + // Limit specifies the number of rows to return + $limit = 100; + if ( isset($_REQUEST['limit']) ) { + if ( ( !is_int($_REQUEST['limit']) and !ctype_digit($_REQUEST['limit']) ) ) { + ZM\Error('Invalid value for limit: ' . $_REQUEST['limit']); + } else { + $limit = $_REQUEST['limit']; + } + } // The table we want our data from $table = 'Logs'; @@ -117,11 +99,19 @@ function queryRequest($search, $advsearch, $sort, $offset, $order, $limit) { // The names of columns shown in the log view that are NOT dB columns in the database $col_alt = array('DateTime', 'Server'); + $sort = 'TimeKey'; + if ( isset($_REQUEST['sort']) ) { + $sort = $_REQUEST['sort']; + if ( $sort == 'DateTime' ) $sort = 'TimeKey'; + } if ( !in_array($sort, array_merge($columns, $col_alt)) ) { ZM\Error('Invalid sort field: ' . $sort); return; } + // Order specifies the sort direction, either asc or desc + $order = (isset($_REQUEST['order']) and (strtolower($_REQUEST['order']) == 'asc')) ? 'ASC' : 'DESC'; + $col_str = implode(', ', $columns); $data = array(); $query = array(); @@ -131,11 +121,17 @@ function queryRequest($search, $advsearch, $sort, $offset, $order, $limit) { // There are two search bars in the log view, normal and advanced // Making an exuctive decision to ignore the normal search, when advanced search is in use // Alternatively we could try to do both + // + // Advanced search contains an array of "column name" => "search text" pairs + // Bootstrap table sends json_ecoded array, which we must decode + $advsearch = isset($_REQUEST['filter']) ? json_decode($_REQUEST['filter'], JSON_OBJECT_AS_ARRAY) : array(); + // Search contains a user entered string to search on + $search = isset($_REQUEST['search']) ? $_REQUEST['search'] : ''; if ( count($advsearch) ) { foreach ( $advsearch as $col=>$text ) { if ( !in_array($col, array_merge($columns, $col_alt)) ) { - ZM\Error("'$col' is not a sortable column name"); + ZM\Error("'$col' is not a searchable column name"); continue; } // Don't use wildcards on advanced search @@ -160,8 +156,6 @@ function queryRequest($search, $advsearch, $sort, $offset, $order, $limit) { $query['sql'] = 'SELECT ' .$col_str. ' FROM `' .$table. '` ' .$where. ' ORDER BY ' .$sort. ' ' .$order. ' LIMIT ?, ?'; array_push($query['values'], $offset, $limit); - //ZM\Warning('Calling the following sql query: ' .$query['sql']); - $data['totalNotFiltered'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table, 'Total'); if ( $search != '' || count($advsearch) ) { $data['total'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table.$where , 'Total', $wherevalues); @@ -169,18 +163,16 @@ function queryRequest($search, $advsearch, $sort, $offset, $order, $limit) { $data['total'] = $data['totalNotFiltered']; } - if ( !$Servers ) - $Servers = ZM\Server::find(); - $servers_by_Id = array(); - # There is probably a better way to do this. - foreach ( $Servers as $server ) { - $servers_by_Id[$server->Id()] = $server; + $rows = array(); + $results = dbFetchAll($query['sql'], NULL, $query['values']); + if ( !$results ) { + return $data; } - $rows = array(); - foreach ( dbFetchAll($query['sql'], NULL, $query['values']) as $row ) { + foreach ( $results as $row ) { $row['DateTime'] = strftime('%Y-%m-%d %H:%M:%S', intval($row['TimeKey'])); - $row['Server'] = ( $row['ServerId'] and isset($servers_by_Id[$row['ServerId']]) ) ? $servers_by_Id[$row['ServerId']]->Name() : ''; + $Server = new ZM\Server($row['ServerId']); + $row['Server'] = $Server->Name(); // First strip out any html tags // Second strip out all characters that are not ASCII 32-126 (yes, 126) $row['Message'] = preg_replace('/[^\x20-\x7E]/', '', strip_tags($row['Message'])); From 736e108b66f33eda18fab4a6618101b8c02b2ee5 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 11 Nov 2020 12:04:55 -0500 Subject: [PATCH 0616/2339] Revert to FriendsOfCake instead of our fork, as they have merged our patch. --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index eb0e282a2..9f21bb62b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "web/api/app/Plugin/Crud"] path = web/api/app/Plugin/Crud - url = https://github.com/ZoneMinder/crud.git + url = https://github.com/FriendsOfCake/crud.git branch = 3.0 [submodule "web/api/app/Plugin/CakePHP-Enum-Behavior"] path = web/api/app/Plugin/CakePHP-Enum-Behavior From 2c5b13d001c3ba1ebe0e6cf88860170e9f7c9578 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 11 Nov 2020 12:04:55 -0500 Subject: [PATCH 0617/2339] Revert to FriendsOfCake instead of our fork, as they have merged our patch. --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index eb0e282a2..9f21bb62b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "web/api/app/Plugin/Crud"] path = web/api/app/Plugin/Crud - url = https://github.com/ZoneMinder/crud.git + url = https://github.com/FriendsOfCake/crud.git branch = 3.0 [submodule "web/api/app/Plugin/CakePHP-Enum-Behavior"] path = web/api/app/Plugin/CakePHP-Enum-Behavior From d663683f47386c3641128c1c1468c4a82c113e5d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 11 Nov 2020 12:43:41 -0500 Subject: [PATCH 0618/2339] Add a bunch of debug statements to figure out crash --- src/zm_event.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index cd7ba1918..ed478ad20 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -255,7 +255,7 @@ Event::~Event() { } // endtime is set in AddFrame, so SHOULD be set to the value of the last frame timestamp. - if ( ! end_time.tv_sec ) { + if ( !end_time.tv_sec ) { Warning("Empty endtime for event. Should not happen. Setting to now."); gettimeofday(&end_time, nullptr); } @@ -503,7 +503,7 @@ void Event::updateNotes(const StringSetMap &newNoteSetMap) { } // void Event::updateNotes(const StringSetMap &newNoteSetMap) void Event::AddFrames(int n_frames, Image **images, struct timeval **timestamps) { - for (int i = 0; i < n_frames; i += ZM_SQL_BATCH_SIZE) { + for ( int i = 0; i < n_frames; i += ZM_SQL_BATCH_SIZE ) { AddFramesInternal(n_frames, i, images, timestamps); } } @@ -592,6 +592,7 @@ void Event::WriteDbFrames() { frame->delta.fsec, frame->score); delete frame; + Debug(1, "SQL: %s", frame_insert_sql); } *(frame_insert_values_ptr-1) = '\0'; // The -1 is for the extra , added for values above db_mutex.lock(); @@ -600,6 +601,8 @@ void Event::WriteDbFrames() { db_mutex.unlock(); if ( rc ) { + Error("Can't insert frames: rc %d", rc); + Error("Can't insert frames: sql %s", frame_insert_sql); Error("Can't insert frames: %s, sql was %s", mysql_error(&dbconn), frame_insert_sql); return; } else { @@ -719,6 +722,9 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a db_mutex.lock(); } db_mutex.unlock(); + } else { + Debug(1, "Not Adding %d frames to DB because write_to_db:%d or frames > analysis fps %f or BULK", + frame_data.size(), write_to_db, monitor->get_fps()); } // end if frame_type == BULK } // end if db_frame From f855f207e261c5755758ecc41e1a94889cb97fbe Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 11 Nov 2020 14:03:08 -0500 Subject: [PATCH 0619/2339] Limit that # of db frames to buffer to 120 because the sql will exceed 8192. --- src/zm_event.cpp | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index ed478ad20..c858b1877 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -39,6 +39,7 @@ //#define USE_PREPARED_SQL 1 const char * Event::frame_type_names[3] = { "Normal", "Bulk", "Alarm" }; +#define MAX_DB_FRAMES 120 char frame_insert_sql[ZM_SQL_LGE_BUFSIZ] = "INSERT INTO `Frames` (`EventId`, `FrameId`, `Type`, `TimeStamp`, `Delta`, `Score`) VALUES "; int Event::pre_alarm_count = 0; @@ -577,6 +578,9 @@ void Event::AddFramesInternal(int n_frames, int start_frame, Image **images, str void Event::WriteDbFrames() { char *frame_insert_values_ptr = (char *)&frame_insert_sql + 90; // 90 == strlen(frame_insert_sql); + + /* Each frame needs about 63 chars. So if we buffer too many frames, we will exceed the size of frame_insert_sql; + */ Debug(1, "Inserting %d frames", frame_data.size()); while ( frame_data.size() ) { Frame *frame = frame_data.front(); @@ -592,17 +596,13 @@ void Event::WriteDbFrames() { frame->delta.fsec, frame->score); delete frame; - Debug(1, "SQL: %s", frame_insert_sql); } *(frame_insert_values_ptr-1) = '\0'; // The -1 is for the extra , added for values above db_mutex.lock(); - Debug(1, "SQL: %s", frame_insert_sql); int rc = mysql_query(&dbconn, frame_insert_sql); db_mutex.unlock(); if ( rc ) { - Error("Can't insert frames: rc %d", rc); - Error("Can't insert frames: sql %s", frame_insert_sql); Error("Can't insert frames: %s, sql was %s", mysql_error(&dbconn), frame_insert_sql); return; } else { @@ -691,14 +691,23 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a Debug(1, "Frame delta is %d.%d - %d.%d = %d.%d", start_time.tv_sec, start_time.tv_usec, timestamp.tv_sec, timestamp.tv_usec, delta_time.sec, delta_time.fsec); + double fps = monitor->get_fps(); + bool db_frame = ( frame_type != BULK ) || (frames==1) || ((frames%config.bulk_frame_interval)==0) ; if ( db_frame ) { // The idea is to write out 1/sec frame_data.push(new Frame(id, frames, frame_type, timestamp, delta_time, score)); - if ( write_to_db or ( monitor->get_fps() and (frame_data.size() > monitor->get_fps())) or frame_type==BULK ) { + if ( write_to_db + or + (frame_data.size() > MAX_DB_FRAMES) + or + (frame_type==BULK) + or + ( fps and (frame_data.size() > fps) ) + ) { Debug(1, "Adding %d frames to DB because write_to_db:%d or frames > analysis fps %f or BULK", - frame_data.size(), write_to_db, monitor->get_fps()); + frame_data.size(), write_to_db, fps); WriteDbFrames(); last_db_frame = frames; @@ -724,7 +733,7 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a db_mutex.unlock(); } else { Debug(1, "Not Adding %d frames to DB because write_to_db:%d or frames > analysis fps %f or BULK", - frame_data.size(), write_to_db, monitor->get_fps()); + frame_data.size(), write_to_db, fps); } // end if frame_type == BULK } // end if db_frame From 4fdf7f79aee9a8509bf46c532970ee4622a209ec Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 11 Nov 2020 16:05:58 -0500 Subject: [PATCH 0620/2339] Include Record monitors in zmtrigger. --- scripts/zmtrigger.pl.in | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/scripts/zmtrigger.pl.in b/scripts/zmtrigger.pl.in index 1ee392c1e..be38c5e91 100644 --- a/scripts/zmtrigger.pl.in +++ b/scripts/zmtrigger.pl.in @@ -187,7 +187,7 @@ while (1) { } else { Fatal("Can't select: $!"); } - } # end if select returned activitiy + } # end if select returned activity # Check polled connections foreach my $connection ( @in_poll_connections ) { @@ -266,7 +266,7 @@ while (1) { Debug('Checking for timed actions'); my $now = time(); foreach my $action_time ( sort( grep { $_ < $now } @action_times ) ) { - Info("Found " . scalar @{$actions{$action_time}} . "actions expiring at $action_time"); + Info('Found '.(scalar @{$actions{$action_time}}).'actions expiring at '.$action_time); foreach my $action ( @{$actions{$action_time}} ) { my $connection = $action->{connection}; Info("Found action '$$action{message}'"); @@ -319,7 +319,7 @@ exit; sub loadMonitor { my $monitor = shift; - Debug("Loading monitor $monitor"); + Debug('Loading monitor '.$monitor); zmMemInvalidate($monitor); if ( zmMemVerify($monitor) ) { # This will re-init shared memory @@ -334,7 +334,7 @@ sub loadMonitors { my %new_monitors = (); my $sql = 'SELECT * FROM `Monitors` - WHERE find_in_set( `Function`, \'Modect,Mocord,Nodect\' )'. + WHERE find_in_set( `Function`, \'Modect,Mocord,Nodect,Record\' )'. ( $Config{ZM_SERVER_ID} ? ' AND `ServerId`=?' : '' ) ; my $sth = $dbh->prepare_cached( $sql ) @@ -387,12 +387,9 @@ sub handleMessage { } # Force a reload $monitor_reload_time = 0; - Info("Set monitor to $state"); + Info('Set monitor to '.$state); if ( $delay ) { - my $action_text = $id.'|'.( ($state eq 'enable') - ? 'disable' - : 'enable' - ); + my $action_text = $id.'|'.(($state eq 'enable') ? 'disable' : 'enable'); handleDelay($delay, $connection, $action_text); } } elsif ( $action =~ /^(on|off)(?:[ \+](\d+))?$/ ) { From 076d649189f2dcdf3b79d2b59c5c84514e27f3b3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 11 Nov 2020 16:12:30 -0500 Subject: [PATCH 0621/2339] Include Record Monitors in zmtrigger --- scripts/zmtrigger.pl.in | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/scripts/zmtrigger.pl.in b/scripts/zmtrigger.pl.in index 1ee392c1e..be38c5e91 100644 --- a/scripts/zmtrigger.pl.in +++ b/scripts/zmtrigger.pl.in @@ -187,7 +187,7 @@ while (1) { } else { Fatal("Can't select: $!"); } - } # end if select returned activitiy + } # end if select returned activity # Check polled connections foreach my $connection ( @in_poll_connections ) { @@ -266,7 +266,7 @@ while (1) { Debug('Checking for timed actions'); my $now = time(); foreach my $action_time ( sort( grep { $_ < $now } @action_times ) ) { - Info("Found " . scalar @{$actions{$action_time}} . "actions expiring at $action_time"); + Info('Found '.(scalar @{$actions{$action_time}}).'actions expiring at '.$action_time); foreach my $action ( @{$actions{$action_time}} ) { my $connection = $action->{connection}; Info("Found action '$$action{message}'"); @@ -319,7 +319,7 @@ exit; sub loadMonitor { my $monitor = shift; - Debug("Loading monitor $monitor"); + Debug('Loading monitor '.$monitor); zmMemInvalidate($monitor); if ( zmMemVerify($monitor) ) { # This will re-init shared memory @@ -334,7 +334,7 @@ sub loadMonitors { my %new_monitors = (); my $sql = 'SELECT * FROM `Monitors` - WHERE find_in_set( `Function`, \'Modect,Mocord,Nodect\' )'. + WHERE find_in_set( `Function`, \'Modect,Mocord,Nodect,Record\' )'. ( $Config{ZM_SERVER_ID} ? ' AND `ServerId`=?' : '' ) ; my $sth = $dbh->prepare_cached( $sql ) @@ -387,12 +387,9 @@ sub handleMessage { } # Force a reload $monitor_reload_time = 0; - Info("Set monitor to $state"); + Info('Set monitor to '.$state); if ( $delay ) { - my $action_text = $id.'|'.( ($state eq 'enable') - ? 'disable' - : 'enable' - ); + my $action_text = $id.'|'.(($state eq 'enable') ? 'disable' : 'enable'); handleDelay($delay, $connection, $action_text); } } elsif ( $action =~ /^(on|off)(?:[ \+](\d+))?$/ ) { From 73e8c04b6f32df882d8f6066b84e3a2cfd1dbd6d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 11 Nov 2020 17:39:20 -0500 Subject: [PATCH 0622/2339] Fix encoding of = in filter['Id']. Fixes redirect after saving --- web/includes/Filter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/includes/Filter.php b/web/includes/Filter.php index 84941dbeb..c4610de4d 100644 --- a/web/includes/Filter.php +++ b/web/includes/Filter.php @@ -61,7 +61,7 @@ class Filter extends ZM_Object { $this->_querystring .= $term->querystring($objectname, $separator); } # end foreach term if ( $this->Id() ) { - $this->_querystring .= $separator.$objectname.urlencode('[Id]=').$this->Id(); + $this->_querystring .= $separator.$objectname.urlencode('[Id]').'='.$this->Id(); } } return $this->_querystring; From fe733fe1e6e352f7129567a5dea9c587cfef48c6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 11 Nov 2020 17:39:37 -0500 Subject: [PATCH 0623/2339] Must use & instead of & in filter redirect --- web/includes/actions/filter.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/web/includes/actions/filter.php b/web/includes/actions/filter.php index 572cccf08..9216ef723 100644 --- a/web/includes/actions/filter.php +++ b/web/includes/actions/filter.php @@ -46,7 +46,6 @@ if ( isset($_REQUEST['object']) and ( $_REQUEST['object'] == 'filter' ) ) { } } else if ( ( $action == 'Save' ) or ( $action == 'SaveAs' ) or ( $action == 'execute' ) ) { - $sql = ''; $_REQUEST['filter']['Query']['sort_field'] = validStr($_REQUEST['filter']['Query']['sort_field']); $_REQUEST['filter']['Query']['sort_asc'] = validStr($_REQUEST['filter']['Query']['sort_asc']); $_REQUEST['filter']['Query']['limit'] = validInt($_REQUEST['filter']['Query']['limit']); @@ -95,7 +94,7 @@ if ( isset($_REQUEST['object']) and ( $_REQUEST['object'] == 'filter' ) ) { } else if ( $filter->Background() ) { $filter->control('start'); } - $redirect = '?view=filter'.$filter->querystring(); + $redirect = '?view=filter'.$filter->querystring('filter', '&'); } else if ( $action == 'control' ) { if ( $_REQUEST['command'] == 'start' From 95f8aad19b673e3f4167dc95fc607b96033bb1e7 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 11 Nov 2020 17:39:55 -0500 Subject: [PATCH 0624/2339] Fix detection of filter['id'] --- web/skins/classic/views/filter.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/views/filter.php b/web/skins/classic/views/filter.php index fe90681b3..723414f6e 100644 --- a/web/skins/classic/views/filter.php +++ b/web/skins/classic/views/filter.php @@ -37,8 +37,8 @@ $filter = NULL; $fid = 0; if ( isset($_REQUEST['Id']) and $_REQUEST['Id'] ) { $fid = validInt($_REQUEST['Id']); -} else if ( isset($_REQUEST['filter[Id]']) ) { - $fid = validInt($_REQUEST['filter[Id]']); +} else if ( isset($_REQUEST['filter']) and isset($_REQUEST['filter']['Id']) ) { + $fid = validInt($_REQUEST['filter']['Id']); } $filter = null; foreach ( ZM\Filter::find(null,array('order'=>'lower(Name)')) as $Filter ) { @@ -56,6 +56,7 @@ if ( !$filter ) { $filter = new ZM\Filter(); } +ZM\Debug('filter: ' . print_r($filter,true)); if ( isset($_REQUEST['filter']) ) { # Update our filter object with whatever changes we have made before saving $filter->set($_REQUEST['filter']); From 7b764d04d3a13f2f600868383a818291778594ff Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 11 Nov 2020 17:40:31 -0500 Subject: [PATCH 0625/2339] Fix use of next when it should be return. Improve some logging of errors. --- scripts/zmtrigger.pl.in | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/scripts/zmtrigger.pl.in b/scripts/zmtrigger.pl.in index be38c5e91..acd4ce255 100644 --- a/scripts/zmtrigger.pl.in +++ b/scripts/zmtrigger.pl.in @@ -372,9 +372,10 @@ sub handleMessage { Warning("Can't find monitor '$id' for message '$message'"); return; } - Debug("Found monitor for id '$id'"); - - next if !zmMemVerify($monitor); + if ( !zmMemVerify($monitor) ) { + Warning("Can't verify monitor '$id' for message '$message'"); + return; + } Debug("Handling action '$action'"); if ( $action =~ /^(enable|disable)(?:[\+ ](\d+))?$/ ) { @@ -393,12 +394,19 @@ sub handleMessage { handleDelay($delay, $connection, $action_text); } } elsif ( $action =~ /^(on|off)(?:[ \+](\d+))?$/ ) { - next if !$monitor->{Enabled}; + if ( !$monitor->{Enabled} ) { + Info('Motion detection not enabled on monitor '.$id); + return; + } my $trigger = $1; my $delay = $2; my $trigger_data; if ( $trigger eq 'on' ) { + if ( $score <= 0 ) { + Warning('Triggering on with invalid score will have no result.'); + return; + } zmTriggerEventOn($monitor, $score, $cause, $text); zmTriggerShowtext($monitor, $showtext) if defined($showtext); Info("Trigger '$trigger' '$cause'"); From 9636a76ccff7bbfdcc014ac3ef8ae1d28a25630a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 11 Nov 2020 17:42:29 -0500 Subject: [PATCH 0626/2339] drop db lock before reporting mysql_errors --- src/zm_monitor.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 0acfb3ded..e2ea20f88 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1307,10 +1307,11 @@ bool Monitor::Analyse() { db_mutex.lock(); static char sql[ZM_SQL_SML_BUFSIZ]; snprintf(sql, sizeof(sql), "INSERT INTO Monitor_Status (MonitorId,AnalysisFPS) VALUES (%d, %.2lf) ON DUPLICATE KEY UPDATE AnalysisFPS = %.2lf", id, fps, fps); - if ( mysql_query(&dbconn, sql) ) { - Error("Can't run query: %s", mysql_error(&dbconn)); - } + int rc = mysql_query(&dbconn, sql); db_mutex.unlock(); + if ( rc ) { + Error("Can't run query %s: %s", sql, mysql_error(&dbconn)); + } } // end if fps != new_fps last_fps_time = now.tv_sec; @@ -2583,11 +2584,11 @@ int Monitor::Capture() { "VALUES (%d, %.2lf, %u, 'Connected') ON DUPLICATE KEY UPDATE " "CaptureFPS = %.2lf, CaptureBandwidth=%u, Status='Connected'", id, fps, new_capture_bandwidth, fps, new_capture_bandwidth); - if ( mysql_query(&dbconn, sql) ) { - Error("Can't run query: %s", mysql_error(&dbconn)); - } + rc = mysql_query(&dbconn, sql); db_mutex.unlock(); - Debug(4,sql); + if ( rc ) { + Error("Can't run query %s: %s", sql, mysql_error(&dbconn)); + } } // end if time has changed since last update } // end if it might be time to report the fps } // end if captureResult From 02f2c86d430d95b275a6e60498e28316c5b7ad4c Mon Sep 17 00:00:00 2001 From: Bluemax <1403092+BlueMax@users.noreply.github.com> Date: Thu, 12 Nov 2020 01:32:15 +0100 Subject: [PATCH 0627/2339] Honor conf.d (zmlinkcontent.sh) Signed-off-by: Bluemax <1403092+BlueMax@users.noreply.github.com> --- zmlinkcontent.sh.in | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/zmlinkcontent.sh.in b/zmlinkcontent.sh.in index 409202cb1..f6e170ffa 100755 --- a/zmlinkcontent.sh.in +++ b/zmlinkcontent.sh.in @@ -88,16 +88,19 @@ if [[ -n "$ZM_CONFIG" && ! -f "$ZM_CONFIG" ]]; then fi # Load zm.conf -if [ -n "$ZM_CONFIG" ]; then - echo "Using custom zm.conf $ZM_CONFIG" - source "$ZM_CONFIG" -elif [ -f "zm.conf" ]; then - echo "Using local zm.conf" - source "zm.conf" -elif [ -f "/etc/zm.conf" ]; then - echo "Using system zm.conf" - source "/etc/zm.conf" -else +for zmconf in "$ZM_CONFIG" ./zm.conf /etc/zm.conf /etc/zoneminder/zm.conf; do + if [[ -f "$zmconf" ]]; then + echo "Using $zmconf" + source "$zmconf" + # remove filename from path + zmconf2="${zmconf%/*}" + # source conf.d + for i in $(find "${zmconf2}/conf.d" -name \*.conf |sort); do . "$i"; done; + break + fi +done + +if [[ -z "$zmconf2" ]]; then echo -e "Failed locating zoneminder configuration file (zm.conf)\nUse the -z option to specify the full path to the zoneminder configuration file" exit 45 fi From f91dcc9b6073041221b02cbd3c5fd6e04fd96f6e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 11 Nov 2020 20:05:47 -0500 Subject: [PATCH 0628/2339] declar rc as int --- src/zm_monitor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index e2ea20f88..d8e327eac 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -2584,7 +2584,7 @@ int Monitor::Capture() { "VALUES (%d, %.2lf, %u, 'Connected') ON DUPLICATE KEY UPDATE " "CaptureFPS = %.2lf, CaptureBandwidth=%u, Status='Connected'", id, fps, new_capture_bandwidth, fps, new_capture_bandwidth); - rc = mysql_query(&dbconn, sql); + int rc = mysql_query(&dbconn, sql); db_mutex.unlock(); if ( rc ) { Error("Can't run query %s: %s", sql, mysql_error(&dbconn)); From 7faf774cd060964783458a384997db9d812ade20 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 12 Nov 2020 09:15:02 -0500 Subject: [PATCH 0629/2339] Use FriendsOfCake crud 3.2.0 --- distros/redhat/zoneminder.spec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index af62cefba..16904e725 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -3,7 +3,7 @@ %global zmgid_final apache # Crud is configured as a git submodule -%global crud_version 3.1.0-zm +%global crud_version 3.2.0 # CakePHP-Enum-Behavior is configured as a git submodule %global ceb_version 1.0-zm @@ -44,7 +44,7 @@ License: GPLv2+ and LGPLv2+ and MIT URL: http://www.zoneminder.com/ Source0: https://github.com/ZoneMinder/ZoneMinder/archive/%{version}.tar.gz#/zoneminder-%{version}.tar.gz -Source1: https://github.com/ZoneMinder/crud/archive/v%{crud_version}.tar.gz#/crud-%{crud_version}.tar.gz +Source1: https://github.com/FriendOfCake/crud/archive/v%{crud_version}.tar.gz#/crud-%{crud_version}.tar.gz Source2: https://github.com/ZoneMinder/CakePHP-Enum-Behavior/archive/%{ceb_version}.tar.gz#/cakephp-enum-behavior-%{ceb_version}.tar.gz %{?rhel:BuildRequires: epel-rpm-macros} From 645dca6bc92262883a23dceacf1621e5b5350026 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 12 Nov 2020 09:59:32 -0500 Subject: [PATCH 0630/2339] Use FriendsOfCake 3.2.0 Crud --- utils/packpack/startpackpack.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/packpack/startpackpack.sh b/utils/packpack/startpackpack.sh index 1b2eafd8f..d464089d3 100755 --- a/utils/packpack/startpackpack.sh +++ b/utils/packpack/startpackpack.sh @@ -94,12 +94,12 @@ commonprep () { # The rpm specfile requires we download each submodule as a tarball then manually move it into place # Might as well do this for Debian as well, rather than git submodule init - CRUDVER="3.1.0-zm" + CRUDVER="3.2.0" if [ -e "build/crud-${CRUDVER}.tar.gz" ]; then echo "Found existing Crud ${CRUDVER} tarball..." else echo "Retrieving Crud ${CRUDVER} submodule..." - curl -L https://github.com/ZoneMinder/crud/archive/v${CRUDVER}.tar.gz > build/crud-${CRUDVER}.tar.gz + curl -L https://github.com/FriendsOfCake/crud/archive/v${CRUDVER}.tar.gz > build/crud-${CRUDVER}.tar.gz if [ $? -ne 0 ]; then echo "ERROR: Crud tarball retreival failed..." exit 1 From de74a15ab1df18c84647123eee552c5cfb775d82 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 12 Nov 2020 11:53:51 -0500 Subject: [PATCH 0631/2339] Move diag_fifo pipes in SOCKS_DIR instead of assigned Storage area. Storage areas could be a fs that cannot handle sockets or fifos like NFS. --- src/zm_fifo.cpp | 2 +- src/zm_monitor.cpp | 15 +++++++++------ src/zm_monitor.h | 4 ++-- src/zm_zone.cpp | 18 ++++++++++++------ 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/zm_fifo.cpp b/src/zm_fifo.cpp index 53025f597..8743fa844 100644 --- a/src/zm_fifo.cpp +++ b/src/zm_fifo.cpp @@ -221,7 +221,7 @@ void FifoStream::setStreamStart(int monitor_id, const char * format) { } snprintf(diag_path, sizeof(diag_path), "%s/%d/%s", - monitor->getStorage()->Path(), monitor->Id(), filename); + staticConfig.PATH_SOCKS.c_str(), monitor->Id(), filename); setStreamStart(diag_path); } diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index d8e327eac..741903a0c 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -540,11 +540,14 @@ Monitor::Monitor( ReloadLinkedMonitors(p_linked_monitors); if ( config.record_diag_images ) { - diag_path_r = stringtf(config.record_diag_images_fifo ? "%s/%d/diagpipe-r.jpg" : "%s/%d/diag-r.jpg", storage->Path(), id); - diag_path_d = stringtf(config.record_diag_images_fifo ? "%s/%d/diagpipe-d.jpg" : "%s/%d/diag-d.jpg", storage->Path(), id); if ( config.record_diag_images_fifo ) { - FifoStream::fifo_create_if_missing(diag_path_r.c_str()); - FifoStream::fifo_create_if_missing(diag_path_d.c_str()); + diag_path_ref = stringtf("%s/%d/diagpipe-r.jpg", staticConfig.PATH_SOCKS.c_str(), id); + diag_path_delta = stringtf("%s/%d/diagpipe-d.jpg", staticConfig.PATH_SOCKS.c_str(), id); + FifoStream::fifo_create_if_missing(diag_path_ref.c_str()); + FifoStream::fifo_create_if_missing(diag_path_delta.c_str()); + } else { + diag_path_ref = stringtf("%s/%d/diag-r.jpg", storage->Path(), id); + diag_path_delta = stringtf("%s/%d/diag-d.jpg", storage->Path(), id); } } } // end if purpose == ANALYSIS @@ -2683,8 +2686,8 @@ unsigned int Monitor::DetectMotion(const Image &comp_image, Event::StringSet &zo ref_image.Delta(comp_image, &delta_image); if ( config.record_diag_images ) { - ref_image.WriteJpeg(diag_path_r.c_str(), config.record_diag_images_fifo); - delta_image.WriteJpeg(diag_path_d.c_str(), config.record_diag_images_fifo); + ref_image.WriteJpeg(diag_path_ref.c_str(), config.record_diag_images_fifo); + delta_image.WriteJpeg(diag_path_delta.c_str(), config.record_diag_images_fifo); } // Blank out all exclusion zones diff --git a/src/zm_monitor.h b/src/zm_monitor.h index a6d5084bb..858ea5d72 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -313,8 +313,8 @@ protected: Image ref_image; Image alarm_image; // Used in creating analysis images, will be initialized in Analysis Image write_image; // Used when creating snapshot images - std::string diag_path_r; - std::string diag_path_d; + std::string diag_path_ref; + std::string diag_path_delta; Purpose purpose; // What this monitor has been created to do int event_count; diff --git a/src/zm_zone.cpp b/src/zm_zone.cpp index 8fc7f88c9..8ce486821 100644 --- a/src/zm_zone.cpp +++ b/src/zm_zone.cpp @@ -113,11 +113,16 @@ void Zone::Setup( } if ( config.record_diag_images ) { - snprintf(diag_path, sizeof(diag_path), - config.record_diag_images_fifo ? "%s/diagpipe-%d-poly.jpg" : "%s/diag-%d-poly.jpg", - monitor->getStorage()->Path(), id); - if ( config.record_diag_images_fifo ) + if ( config.record_diag_images_fifo ) { + snprintf(diag_path, sizeof(diag_path), + "%s/diagpipe-%d-poly.jpg", + staticConfig.PATH_SOCKS.c_str(), id); + FifoStream::fifo_create_if_missing(diag_path); + } else { + snprintf(diag_path, sizeof(diag_path), "%s/diag-%d-poly.jpg", + monitor->getStorage()->Path(), id); + } pg_image->WriteJpeg(diag_path, config.record_diag_images_fifo); } else { diag_path[0] = 0; @@ -139,10 +144,11 @@ void Zone::RecordStats(const Event *event) { "INSERT INTO Stats SET MonitorId=%d, ZoneId=%d, EventId=%" PRIu64 ", FrameId=%d, PixelDiff=%d, AlarmPixels=%d, FilterPixels=%d, BlobPixels=%d, Blobs=%d, MinBlobSize=%d, MaxBlobSize=%d, MinX=%d, MinY=%d, MaxX=%d, MaxY=%d, Score=%d", monitor->Id(), id, event->Id(), event->Frames(), pixel_diff, alarm_pixels, alarm_filter_pixels, alarm_blob_pixels, alarm_blobs, min_blob_size, max_blob_size, alarm_box.LoX(), alarm_box.LoY(), alarm_box.HiX(), alarm_box.HiY(), score ); - if ( mysql_query(&dbconn, sql) ) { + int rc = mysql_query(&dbconn, sql); + db_mutex.unlock(); + if ( rc ) { Error("Can't insert event stats: %s", mysql_error(&dbconn)); } - db_mutex.unlock(); } // end void Zone::RecordStats( const Event *event ) bool Zone::CheckOverloadCount() { From 15f1175f25745ace954173117146496efebbeee3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 12 Nov 2020 12:36:36 -0500 Subject: [PATCH 0632/2339] spacing --- src/zm_packet.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/zm_packet.h b/src/zm_packet.h index a2e914bd7..70be26a2a 100644 --- a/src/zm_packet.h +++ b/src/zm_packet.h @@ -58,8 +58,8 @@ class ZMPacket { int is_keyframe() { return keyframe; }; int decode( AVCodecContext *ctx ); void reset(); - explicit ZMPacket( Image *image ); - explicit ZMPacket( ZMPacket &packet ); + explicit ZMPacket(Image *image); + explicit ZMPacket(ZMPacket &packet); ZMPacket(); ~ZMPacket(); void lock() { From c8efddddf5ffae8835ec6fb4ea9195113107d474 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Thu, 12 Nov 2020 12:27:06 -0600 Subject: [PATCH 0633/2339] fix typo --- distros/redhat/zoneminder.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index 16904e725..c1d6283f2 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -44,7 +44,7 @@ License: GPLv2+ and LGPLv2+ and MIT URL: http://www.zoneminder.com/ Source0: https://github.com/ZoneMinder/ZoneMinder/archive/%{version}.tar.gz#/zoneminder-%{version}.tar.gz -Source1: https://github.com/FriendOfCake/crud/archive/v%{crud_version}.tar.gz#/crud-%{crud_version}.tar.gz +Source1: https://github.com/FriendsOfCake/crud/archive/v%{crud_version}.tar.gz#/crud-%{crud_version}.tar.gz Source2: https://github.com/ZoneMinder/CakePHP-Enum-Behavior/archive/%{ceb_version}.tar.gz#/cakephp-enum-behavior-%{ceb_version}.tar.gz %{?rhel:BuildRequires: epel-rpm-macros} From bbc2c2a607c49f70847b5d1611d297013d5f8e30 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 12 Nov 2020 13:27:10 -0500 Subject: [PATCH 0634/2339] Crud has more than 1 friend --- distros/redhat/zoneminder.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index 16904e725..c1d6283f2 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -44,7 +44,7 @@ License: GPLv2+ and LGPLv2+ and MIT URL: http://www.zoneminder.com/ Source0: https://github.com/ZoneMinder/ZoneMinder/archive/%{version}.tar.gz#/zoneminder-%{version}.tar.gz -Source1: https://github.com/FriendOfCake/crud/archive/v%{crud_version}.tar.gz#/crud-%{crud_version}.tar.gz +Source1: https://github.com/FriendsOfCake/crud/archive/v%{crud_version}.tar.gz#/crud-%{crud_version}.tar.gz Source2: https://github.com/ZoneMinder/CakePHP-Enum-Behavior/archive/%{ceb_version}.tar.gz#/cakephp-enum-behavior-%{ceb_version}.tar.gz %{?rhel:BuildRequires: epel-rpm-macros} From ad4d0efba6166873058d6331a95504d34484327c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 12 Nov 2020 17:00:32 -0500 Subject: [PATCH 0635/2339] 121 frames is too many, use >= instead --- src/zm_event.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index c858b1877..e2b697e48 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -276,7 +276,7 @@ Event::~Event() { // update frame deltas to refer to video start time which may be a few frames before event start struct timeval video_offset = {0}; - struct timeval video_start_time = monitor->GetVideoWriterStartTime(); + struct timeval video_start_time = monitor->GetVideoWriterStartTime(); if ( video_start_time.tv_sec > 0 ) { timersub(&video_start_time, &start_time, &video_offset); Debug(1, "Updating frames delta by %d sec %d usec", @@ -700,7 +700,7 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a frame_data.push(new Frame(id, frames, frame_type, timestamp, delta_time, score)); if ( write_to_db or - (frame_data.size() > MAX_DB_FRAMES) + (frame_data.size() >= MAX_DB_FRAMES) or (frame_type==BULK) or From c0225a35aade6977f1d3649225f856f4708e892a Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Fri, 13 Nov 2020 07:24:17 -0600 Subject: [PATCH 0636/2339] use different variable assignment for clarity --- web/ajax/events.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/ajax/events.php b/web/ajax/events.php index 3a2e6ad53..cde2acc08 100644 --- a/web/ajax/events.php +++ b/web/ajax/events.php @@ -173,7 +173,7 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim $unfiltered_rows[] = $row; } - ZM\Debug('Have ' . count($event_ids) . ' events matching base filter.'); + ZM\Debug('Have ' . count($unfiltered_rows) . ' events matching base filter.'); $filtered_rows = null; @@ -238,11 +238,11 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim $data['rows'] = $returned_rows; # totalNotFiltered must equal total, except when either search bar has been used - $data['totalNotFiltered'] = count($event_ids); + $data['totalNotFiltered'] = count($unfiltered_rows); if ( $search != '' || count($advsearch) ) { $data['total'] = count($filtered_rows); } else { - $data['total'] = count($unfiltered_rows); + $data['total'] = $data['totalNotFiltered']; } return $data; From 3cf31435a784a2a0f5f4dcb2a3ddc356c0edd451 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 13 Nov 2020 09:51:54 -0500 Subject: [PATCH 0637/2339] fix next/prev buttons by correcting the sort_field when it is StartTime or EndTime --- web/includes/functions.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/web/includes/functions.php b/web/includes/functions.php index 9ac46cd3c..d5478b74f 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -1003,10 +1003,18 @@ function parseSort($saveToSession=false, $querySep='&') { $sortColumn = 'E.DiskSpace'; break; case 'StartTime' : + # legacy + $_REQUEST['sort_field'] = 'StartDateTime'; + $sortColumn = 'E.StartDateTime'; + break; case 'StartDateTime' : $sortColumn = 'E.StartDateTime'; break; case 'EndTime' : + #legacy + $_REQUEST['sort_field'] = 'EndDateTime'; + $sortColumn = 'E.EndDateTime'; + break; case 'EndDateTime' : $sortColumn = 'E.EndDateTime'; break; From a581cb9de1e082cbb330a0a892cbf7a1a677a65f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 13 Nov 2020 10:18:35 -0500 Subject: [PATCH 0638/2339] Make various text input options be 90% --- web/skins/classic/css/base/views/options.css | 21 ++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/css/base/views/options.css b/web/skins/classic/css/base/views/options.css index e13409b35..8d7b9bc70 100644 --- a/web/skins/classic/css/base/views/options.css +++ b/web/skins/classic/css/base/views/options.css @@ -26,8 +26,25 @@ input.large { } input[name="newConfig[ZM_OPT_GOOG_RECAPTCHA_SITEKEY]"], -input[name="newConfig[ZM_OPT_GOOG_RECAPTCHA_SECRETKEY]"] { - width: 100%; +input[name="newConfig[ZM_OPT_GOOG_RECAPTCHA_SECRETKEY]"], +input[name="newConfig[ZM_OPT_GEOLOCATION_TILE_PROVIDER]"], +input[name="newConfig[ZM_OPT_GEOLOCATION_ACCESS_TOKEN]"], +input[name="newConfig[ZM_AUTH_HASH_SECRET]"], +input[name="newConfig[ZM_UPDATE_CHECK_PROXY]"], +input[name="newConfig[ZM_WEB_TITLE]"], +input[name="newConfig[ZM_WEB_TITLE_PREFIX]"], +input[name="newConfig[ZM_HOME_URL]"], +input[name="newConfig[ZM_HOME_CONTENT]"], +input[name="newConfig[ZM_WEB_CONSOLE_BANNER]"], +input[name="newConfig[ZM_LOG_DEBUG_TARGET]"], +input[name="newConfig[ZM_LOG_DEBUG_FILE]"], +input[name="newConfig[ZM_MESSAGE_ADDRESS]"], +input[name="newConfig[ZM_MESSAGE_SUBJECT]"], +input[name="newConfig[ZM_FROM_EMAIL]"], +input[name="newConfig[ZM_URL]"], +input[name="newConfig[ZM_SSMTP_PATH]"], +input[name="newConfig[ZM_CSP_REPORT_URI]"] { + width: 90%; } #options label { From da99426535cf3d426f77165e11287a9a6847b4a0 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 13 Nov 2020 10:40:55 -0500 Subject: [PATCH 0639/2339] if monitor is not found call loadMonitors to make sure it isn't new --- scripts/zmtrigger.pl.in | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/scripts/zmtrigger.pl.in b/scripts/zmtrigger.pl.in index acd4ce255..5fc632165 100644 --- a/scripts/zmtrigger.pl.in +++ b/scripts/zmtrigger.pl.in @@ -350,7 +350,7 @@ sub loadMonitors { $new_monitors{$monitor->{Id}} = $monitor; } # end while fetchrow %monitors = %new_monitors; -} +} # end sub loadMonitors sub handleMessage { my $connection = shift; @@ -369,8 +369,12 @@ sub handleMessage { my $monitor = $monitors{$id}; if ( !$monitor ) { - Warning("Can't find monitor '$id' for message '$message'"); - return; + loadMonitors(); + $monitor = $monitors{$id}; + if ( !$monitor ) { + Warning("Can't find monitor '$id' for message '$message'"); + return; + } } if ( !zmMemVerify($monitor) ) { Warning("Can't verify monitor '$id' for message '$message'"); From 08a8155b478af3e96f728df8fe757978616cc3f5 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 13 Nov 2020 12:27:51 -0500 Subject: [PATCH 0640/2339] Implement a Monitor::disconnect function. Fix Fatals during connect and cleanup Analysis Monitor code to wait around for zmc. Handle zmc going away gracefully. Fixes a slow zma startup due to zmc not being setup yet. --- src/zm_monitor.cpp | 173 +++++++++++++++++++++++++-------------------- src/zm_monitor.h | 1 + src/zma.cpp | 15 ++-- 3 files changed, 108 insertions(+), 81 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 741903a0c..8fed25acc 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -448,6 +448,8 @@ Monitor::Monitor( char monitor_dir[PATH_MAX]; snprintf(monitor_dir, sizeof(monitor_dir), "%s/%d", storage->Path(), id); + shared_data = nullptr; + if ( purpose == CAPTURE ) { if ( mkdir(monitor_dir, 0755) && ( errno != EEXIST ) ) { Error("Can't mkdir %s: %s", monitor_dir, strerror(errno)); @@ -489,9 +491,39 @@ Monitor::Monitor( video_store_data->size = sizeof(VideoStoreData); //video_store_data->frameNumber = 0; } else if ( purpose == ANALYSIS ) { - if ( ! (this->connect() && mem_ptr && shared_data->valid) ) { - Error("Shared data not initialised by capture daemon for monitor %s", name); - exit(-1); + while ( + (!zm_terminate) + and + ( !(this->connect() and shared_data->valid) ) + and + ( shared_data->last_write_index == (unsigned int)image_buffer_count ) + and + ( shared_data->last_write_time == 0 ) + ) { + Debug(1, "blah"); + Debug(1, "Waiting for capture daemon shared_data(%d) last_write_index(%d), last_write_time(%d)", + (shared_data ? 1:0), + (shared_data ? shared_data->last_write_index : 0), + (shared_data ? shared_data->last_write_time : 0)); + usleep(100000); + } + + ref_image.Assign(width, height, camera->Colours(), camera->SubpixelOrder(), + image_buffer[shared_data->last_write_index].image->Buffer(), camera->ImageSize()); + adaptive_skip = true; + + ReloadLinkedMonitors(p_linked_monitors); + + if ( config.record_diag_images ) { + if ( config.record_diag_images_fifo ) { + diag_path_ref = stringtf("%s/%d/diagpipe-r.jpg", staticConfig.PATH_SOCKS.c_str(), id); + diag_path_delta = stringtf("%s/%d/diagpipe-d.jpg", staticConfig.PATH_SOCKS.c_str(), id); + FifoStream::fifo_create_if_missing(diag_path_ref.c_str()); + FifoStream::fifo_create_if_missing(diag_path_delta.c_str()); + } else { + diag_path_ref = stringtf("%s/%d/diag-r.jpg", storage->Path(), id); + diag_path_delta = stringtf("%s/%d/diag-d.jpg", storage->Path(), id); + } } shared_data->state = IDLE; shared_data->last_read_time = 0; @@ -520,37 +552,6 @@ Monitor::Monitor( n_linked_monitors = 0; linked_monitors = nullptr; - if ( purpose == ANALYSIS ) { - while( - ( shared_data->last_write_index == (unsigned int)image_buffer_count ) - && - ( shared_data->last_write_time == 0 ) - && - ( !zm_terminate ) - ) { - Debug(1, "Waiting for capture daemon last_write_index(%d), last_write_time(%d)", - shared_data->last_write_index, shared_data->last_write_time ); - sleep(1); - } - - ref_image.Assign(width, height, camera->Colours(), camera->SubpixelOrder(), - image_buffer[shared_data->last_write_index].image->Buffer(), camera->ImageSize()); - adaptive_skip = true; - - ReloadLinkedMonitors(p_linked_monitors); - - if ( config.record_diag_images ) { - if ( config.record_diag_images_fifo ) { - diag_path_ref = stringtf("%s/%d/diagpipe-r.jpg", staticConfig.PATH_SOCKS.c_str(), id); - diag_path_delta = stringtf("%s/%d/diagpipe-d.jpg", staticConfig.PATH_SOCKS.c_str(), id); - FifoStream::fifo_create_if_missing(diag_path_ref.c_str()); - FifoStream::fifo_create_if_missing(diag_path_delta.c_str()); - } else { - diag_path_ref = stringtf("%s/%d/diag-r.jpg", storage->Path(), id); - diag_path_delta = stringtf("%s/%d/diag-d.jpg", storage->Path(), id); - } - } - } // end if purpose == ANALYSIS } // Monitor::Monitor bool Monitor::connect() { @@ -606,12 +607,12 @@ bool Monitor::connect() { } } #endif - if ( mem_ptr == MAP_FAILED ) - Fatal("Can't map file %s (%d bytes) to memory: %s(%d)", mem_file, mem_size, strerror(errno), errno); - if ( mem_ptr == nullptr ) { - Error("mmap gave a NULL address:"); - } else { - Debug(3, "mmapped to %p", mem_ptr); + if ( (mem_ptr == MAP_FAILED) or (mem_ptr == nullptr) ) { + Error("Can't map file %s (%d bytes) to memory: %s(%d)", mem_file, mem_size, strerror(errno), errno); + close(map_fd); + map_fd = -1; + mem_ptr = nullptr; + return false; } #else // ZM_MEM_MAPPED shm_id = shmget((config.shm_key&0xffff0000)|id, mem_size, IPC_CREAT|0700); @@ -669,6 +670,51 @@ Debug(3, "Success connecting"); return true; } // end Monitor::connect +bool Monitor::disconnect() { + if ( !mem_ptr ) + return true; + +#if ZM_MEM_MAPPED + if ( mem_ptr > (void *)0 ) { + msync(mem_ptr, mem_size, MS_ASYNC); + munmap(mem_ptr, mem_size); + } + if ( map_fd >= 0 ) + close(map_fd); + + map_fd = -1; + + if ( purpose == CAPTURE ) { + if ( unlink(mem_file) < 0 ) { + Warning("Can't unlink '%s': %s", mem_file, strerror(errno)); + } + } +#else // ZM_MEM_MAPPED + struct shmid_ds shm_data; + if ( shmctl(shm_id, IPC_STAT, &shm_data) < 0 ) { + Debug(3, "Can't shmctl: %s", strerror(errno)); + return false; + } + + shm_id = 0; + + if ( shm_data.shm_nattch <= 1 ) { + if ( shmctl(shm_id, IPC_RMID, 0) < 0 ) { + Debug(3, "Can't shmctl: %s", strerror(errno)); + return false; + } + } + + if ( shmdt(mem_ptr) < 0 ) { + Debug(3, "Can't shmdt: %s", strerror(errno)); + return false; + } +#endif // ZM_MEM_MAPPED + mem_ptr = nullptr; + shared_data = nullptr; + return true; +} // end bool Monitor::disconnect() + Monitor::~Monitor() { if ( n_linked_monitors ) { for( int i = 0; i < n_linked_monitors; i++ ) { @@ -712,14 +758,6 @@ Monitor::~Monitor() { delete[] image_buffer; } // end if mem_ptr - for ( int i = 0; i < n_zones; i++ ) { - delete zones[i]; - } - delete[] zones; - - delete camera; - delete storage; - if ( mem_ptr ) { if ( purpose == ANALYSIS ) { shared_data->state = state = IDLE; @@ -739,36 +777,17 @@ Monitor::~Monitor() { shared_data->valid = false; memset(mem_ptr, 0, mem_size); } - -#if ZM_MEM_MAPPED - if ( msync(mem_ptr, mem_size, MS_SYNC) < 0 ) - Error("Can't msync: %s", strerror(errno)); - if ( munmap(mem_ptr, mem_size) < 0 ) - Fatal("Can't munmap: %s", strerror(errno)); - close( map_fd ); - - if ( purpose == CAPTURE ) { - // How about we store this in the object on instantiation so that we don't have to do this again. - char mmap_path[PATH_MAX] = ""; - snprintf(mmap_path, sizeof(mmap_path), "%s/zm.mmap.%d", staticConfig.PATH_MAP.c_str(), id); - - if ( unlink(mmap_path) < 0 ) { - Warning("Can't unlink '%s': %s", mmap_path, strerror(errno)); - } - } -#else // ZM_MEM_MAPPED - struct shmid_ds shm_data; - if ( shmctl(shm_id, IPC_STAT, &shm_data) < 0 ) { - Fatal("Can't shmctl: %s", strerror(errno)); - } - if ( shm_data.shm_nattch <= 1 ) { - if ( shmctl(shm_id, IPC_RMID, 0) < 0 ) { - Fatal("Can't shmctl: %s", strerror(errno)); - } - } -#endif // ZM_MEM_MAPPED + disconnect(); } // end if mem_ptr -} + + for ( int i = 0; i < n_zones; i++ ) { + delete zones[i]; + } + delete[] zones; + + delete camera; + delete storage; +} // end Monitor::~Monitor() void Monitor::AddZones( int p_n_zones, Zone *p_zones[] ) { for ( int i = 0; i < n_zones; i++ ) diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 858ea5d72..9a023d53a 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -424,6 +424,7 @@ public: void AddPrivacyBitmask( Zone *p_zones[] ); bool connect(); + bool disconnect(); inline int ShmValid() const { return shared_data && shared_data->valid; diff --git a/src/zma.cpp b/src/zma.cpp index edaf9c722..5e71abcdc 100644 --- a/src/zma.cpp +++ b/src/zma.cpp @@ -106,9 +106,9 @@ int main( int argc, char *argv[] ) { } } - if (optind < argc) { + if ( optind < argc ) { fprintf(stderr, "Extraneous options, "); - while (optind < argc) + while ( optind < argc ) printf("%s ", argv[optind++]); printf("\n"); Usage(); @@ -130,7 +130,7 @@ int main( int argc, char *argv[] ) { hwcaps_detect(); Monitor *monitor = Monitor::Load(id, true, Monitor::ANALYSIS); - zmFifoDbgInit( monitor ); + zmFifoDbgInit(monitor); if ( monitor ) { Info("In mode %d/%d, warming up", monitor->GetFunction(), monitor->Enabled()); @@ -148,7 +148,14 @@ int main( int argc, char *argv[] ) { monitor->UpdateAdaptiveSkip(); last_analysis_update_time = time(nullptr); - while( (!zm_terminate) && monitor->ShmValid() ) { + while ( !zm_terminate ) { + if ( !monitor->ShmValid() ) { + monitor->disconnect(); + Info("Waiting for shm to become valid"); + usleep(100000); + monitor->connect(); + continue; + } // Process the next image sigprocmask(SIG_BLOCK, &block_set, nullptr); From 23f27d5a112ec90f7c501bad77804587f8a678b3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 13 Nov 2020 12:43:31 -0500 Subject: [PATCH 0641/2339] include frame_type in debug message --- src/zm_event.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index e2b697e48..efd7d8bc6 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -706,8 +706,8 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a or ( fps and (frame_data.size() > fps) ) ) { - Debug(1, "Adding %d frames to DB because write_to_db:%d or frames > analysis fps %f or BULK", - frame_data.size(), write_to_db, fps); + Debug(1, "Adding %d frames to DB because write_to_db:%d or frames > analysis fps %f or BULK(%d)", + frame_data.size(), write_to_db, fps, (frame_type==BULK)); WriteDbFrames(); last_db_frame = frames; From 52e747791d64f6050ed20499b52c87ebe7f3b234 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Fri, 13 Nov 2020 12:34:01 -0600 Subject: [PATCH 0642/2339] rough in frames server pagination backend --- web/ajax/frames.php | 165 +++++++++++++++++++++++ web/skins/classic/views/js/frames.js | 22 +++ web/skins/classic/views/js/frames.js.php | 1 + 3 files changed, 188 insertions(+) create mode 100644 web/ajax/frames.php create mode 100644 web/skins/classic/views/js/frames.js.php diff --git a/web/ajax/frames.php b/web/ajax/frames.php new file mode 100644 index 000000000..fb23980a8 --- /dev/null +++ b/web/ajax/frames.php @@ -0,0 +1,165 @@ + "search text" pairs +// Bootstrap table sends json_ecoded array, which we must decode +$advsearch = isset($_REQUEST['advsearch']) ? json_decode($_REQUEST['advsearch'], JSON_OBJECT_AS_ARRAY) : array(); + +// Sort specifies the name of the column to sort on +$sort = 'FrameId'; +if ( isset($_REQUEST['sort']) ) { + $sort = $_REQUEST['sort']; +} + +// Offset specifies the starting row to return, used for pagination +$offset = 0; +if ( isset($_REQUEST['offset']) ) { + if ( ( !is_int($_REQUEST['offset']) and !ctype_digit($_REQUEST['offset']) ) ) { + ZM\Error('Invalid value for offset: ' . $_REQUEST['offset']); + } else { + $offset = $_REQUEST['offset']; + } +} + +// Order specifies the sort direction, either asc or desc +$order = (isset($_REQUEST['order']) and (strtolower($_REQUEST['order']) == 'asc')) ? 'ASC' : 'DESC'; + +// Limit specifies the number of rows to return +$limit = 100; +if ( isset($_REQUEST['limit']) ) { + if ( ( !is_int($_REQUEST['limit']) and !ctype_digit($_REQUEST['limit']) ) ) { + ZM\Error('Invalid value for limit: ' . $_REQUEST['limit']); + } else { + $limit = $_REQUEST['limit']; + } +} + +// +// MAIN LOOP +// + +// Only one supported task at the moment +switch ( $task ) { + case 'query' : + $data = queryRequest($eid, $search, $advsearch, $sort, $offset, $order, $limit); + break; + default : + ZM\Fatal("Unrecognised task '$task'"); +} // end switch task + +ajaxResponse($data); + +// +// FUNCTION DEFINITIONS +// + +function queryRequest($eid, $search, $advsearch, $sort, $offset, $order, $limit) { + + // The table we want our data from + $table = 'Frames'; + + // The names of the dB columns in the events table we are interested in + $columns = array('EventId', 'FrameId', 'Type', 'TimeStamp', 'Delta', 'Score'); + + if ( !in_array($sort, $columns) ) { + ZM\Error('Invalid sort field: ' . $sort); + $sort = 'FrameId'; + } + + $Event = new ZM\Event($eid); + $Monitor = $Event->Monitor(); + $values = array(); + $likes = array(); + $where = 'EventId ='.$eid; + + // There are two search bars in the log view, normal and advanced + // Making an exuctive decision to ignore the normal search, when advanced search is in use + // Alternatively we could try to do both + if ( count($advsearch) ) { + + foreach ( $advsearch as $col=>$text ) { + if ( !in_array($col, array_merge($columns, $col_alt)) ) { + ZM\Error("'$col' is not a searchable column name"); + continue; + } + // Don't use wildcards on advanced search + //$text = '%' .$text. '%'; + array_push($likes, $col.' LIKE ?'); + array_push($query['values'], $text); + } + $wherevalues = $query['values']; + $where = ' WHERE (' .implode(' OR ', $likes). ')'; + + } else if ( $search != '' ) { + + $search = '%' .$search. '%'; + foreach ( $columns as $col ) { + array_push($likes, $col.' LIKE ?'); + array_push($query['values'], $search); + } + $wherevalues = $query['values']; + $where = ' WHERE (' .implode(' OR ', $likes). ')'; + } + + $query['sql'] = 'SELECT ' .$col_str. ' FROM `' .$table. '` ' .$where. ' ORDER BY ' .$sort. ' ' .$order. ' LIMIT ?, ?'; + array_push($query['values'], $offset, $limit); + + $data['totalNotFiltered'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table, 'Total'); + if ( $search != '' || count($advsearch) ) { + $data['total'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table.$where , 'Total', $wherevalues); + } else { + $data['total'] = $data['totalNotFiltered']; + } + + $returned_rows = array(); + $results = dbFetchAll($query['sql'], NULL, $query['values']); + if ( !$results ) { + return $data; + } + + foreach ( $results as $row ) { + $base_img_src = '?view=image&fid=' .$row['FrameId']; + $ratio_factor = $Monitor->ViewHeight() / $Monitor->ViewWidth(); + $thmb_width = ZM_WEB_LIST_THUMB_WIDTH ? 'width='.ZM_WEB_LIST_THUMB_WIDTH : ''; + $thmb_height = 'height="'.( ZM_WEB_LIST_THUMB_HEIGHT ? ZM_WEB_LIST_THUMB_HEIGHT : ZM_WEB_LIST_THUMB_WIDTH*$ratio_factor ) .'"'; + $thmb_fn = 'filename=' .$Event->MonitorId(). '_' .$row['EventId']. '_' .$row['FrameId']. '.jpg'; + $img_src = join('&', array_filter(array($base_img_src, $thmb_width, $thmb_height, $thmb_fn))); + $full_img_src = join('&', array_filter(array($base_img_src, $thmb_fn))); + $frame_src = '?view=frame&eid=' .$row['EventId']. '&fid=' .$row['FrameId']; + + $row['imgHtml'] = ''.PHP_EOL; + $returned_rows[] = $row; + } + $data['rows'] = $returned_rows; + + return $data; +} diff --git a/web/skins/classic/views/js/frames.js b/web/skins/classic/views/js/frames.js index 57bf8e4b0..fcdb27303 100644 --- a/web/skins/classic/views/js/frames.js +++ b/web/skins/classic/views/js/frames.js @@ -1,3 +1,25 @@ +// Called by bootstrap-table to retrieve zm frame data +function ajaxRequest(params) { + if ( params.data && params.data.filter ) { + params.data.advsearch = params.data.filter; + delete params.data.filter; + } + $j.getJSON(thisUrl + '?view=request&request=frames&task=query&eid='+eid, params.data) + .done(function(data) { + var rows = processRows(data.rows); + // rearrange the result into what bootstrap-table expects + params.success({total: data.total, totalNotFiltered: data.totalNotFiltered, rows: rows}); + }) + .fail(logAjaxFail); +} + +function processRows(rows) { + $j.each(rows, function(ndx, row) { + // WIP: process each row here + }); + return rows; +} + function thumbnail_onmouseover(event) { var img = event.target; img.src = ''; diff --git a/web/skins/classic/views/js/frames.js.php b/web/skins/classic/views/js/frames.js.php new file mode 100644 index 000000000..48b33b5e3 --- /dev/null +++ b/web/skins/classic/views/js/frames.js.php @@ -0,0 +1 @@ +var eid = ; From f1b8266e26fed5c842b227944dfc7ba355a7ccb8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 13 Nov 2020 17:03:51 -0500 Subject: [PATCH 0643/2339] Only join storage and Monitors if necessary --- scripts/ZoneMinder/lib/ZoneMinder/Filter.pm | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm index eb1b36077..0c78c33ca 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm @@ -148,15 +148,8 @@ sub Sql { } my $filter_expr = ZoneMinder::General::jsonDecode($self->{Query_json}); - my $sql = 'SELECT E.*, - unix_timestamp(E.StartDateTime) as Time, - M.Name as MonitorName, - M.DefaultRate, - M.DefaultScale - FROM Events as E - INNER JOIN Monitors as M on M.Id = E.MonitorId - LEFT JOIN Storage as S on S.Id = E.StorageId - '; + my $sql = 'SELECT E.*, unix_timestamp(E.StartDateTime) as Time + FROM Events as E'; if ( $filter_expr->{terms} ) { foreach my $term ( @{$filter_expr->{terms}} ) { @@ -174,12 +167,16 @@ sub Sql { if ( $term->{attr} eq 'AlarmedZoneId' ) { $term->{op} = 'EXISTS'; } elsif ( $term->{attr} =~ /^Monitor/ ) { + $sql = 'SELECT E.*, unix_timestamp(E.StartDateTime) as Time, M.Name as MonitorName + FROM Events as E INNER JOIN Monitors as M on M.Id = E.MonitorId'; my ( $temp_attr_name ) = $term->{attr} =~ /^Monitor(.+)$/; $self->{Sql} .= 'M.'.$temp_attr_name; } elsif ( $term->{attr} eq 'ServerId' or $term->{attr} eq 'MonitorServerId' ) { + $sql = 'SELECT E.*, unix_timestamp(E.StartDateTime) as Time, M.Name as MonitorName + FROM Events as E INNER JOIN Monitors as M on M.Id = E.MonitorId'; $self->{Sql} .= 'M.ServerId'; } elsif ( $term->{attr} eq 'StorageServerId' ) { - $self->{Sql} .= 'S.ServerId'; + $self->{Sql} .= '(SELECT Storage.ServerId FROM Storage WHERE Storage.Id=E.StorageId)'; } elsif ( $term->{attr} eq 'FilterServerId' ) { $self->{Sql} .= $Config{ZM_SERVER_ID}; # StartTime options @@ -308,7 +305,7 @@ sub Sql { } elsif ( $value eq 'Even' ) { $self->{Sql} .= ' % 2 = 0'; } else { - $self->{Sql} .= " IS $value"; + $self->{Sql} .= ' IS '.$value; } } elsif ( $term->{op} eq 'EXISTS' ) { $self->{Sql} .= ' EXISTS '.$value; @@ -373,6 +370,8 @@ sub Sql { if ( $filter_expr->{sort_field} eq 'Id' ) { $sort_column = 'E.Id'; } elsif ( $filter_expr->{sort_field} eq 'MonitorName' ) { + $sql = 'SELECT E.*, unix_timestamp(E.StartDateTime) as Time, M.Name as MonitorName + FROM Events as E INNER JOIN Monitors as M on M.Id = E.MonitorId'; $sort_column = 'M.Name'; } elsif ( $filter_expr->{sort_field} eq 'Name' ) { $sort_column = 'E.Name'; From a0dcdd135ad8c797e29175d293d0f692b0cf548d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 13 Nov 2020 17:04:22 -0500 Subject: [PATCH 0644/2339] DefaultRate and DefaultScale are Monitor properties, so just load them in a Monitor object so we don't have to JOIN the Monitors table --- scripts/zmfilter.pl.in | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/zmfilter.pl.in b/scripts/zmfilter.pl.in index 834da99f8..b2dd7a2b4 100644 --- a/scripts/zmfilter.pl.in +++ b/scripts/zmfilter.pl.in @@ -405,8 +405,9 @@ sub generateVideo { my $Event = shift; my $phone = shift; - my $rate = $Event->{DefaultRate}/100; - my $scale = $Event->{DefaultScale}/100; + my $Monitor = $Event->Monitor(); + my $rate = $$Monitor{DefaultRate}/100; + my $scale = $$Monitor{DefaultScale}/100; my $format; my @ffmpeg_formats = split(/\s+/, $Config{ZM_FFMPEG_FORMATS}); From d2a203014f03cd88ea15e327a8719b20b20f8bcc Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 13 Nov 2020 17:05:03 -0500 Subject: [PATCH 0645/2339] rename diagpipe-r so that we don't have to create directories in SOCKS_DIR --- src/zm_fifo.cpp | 15 ++++++++------- src/zm_monitor.cpp | 4 ++-- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/zm_fifo.cpp b/src/zm_fifo.cpp index 8743fa844..d3952a169 100644 --- a/src/zm_fifo.cpp +++ b/src/zm_fifo.cpp @@ -57,8 +57,8 @@ static bool zmFifoDbgOpen() { int zmFifoDbgInit(Monitor *monitor) { zm_fifodbg_inited = true; - snprintf(zm_fifodbg_log, sizeof(zm_fifodbg_log), "%s/%d/dbgpipe.log", - monitor->getStorage()->Path(), monitor->Id()); + snprintf(zm_fifodbg_log, sizeof(zm_fifodbg_log), "%s/dbgpipe-%d.log", + staticConfig.PATH_SOCKS.c_str(), monitor->Id()); zmFifoDbgOpen(); return 1; } @@ -211,17 +211,18 @@ void FifoStream::setStreamStart(int monitor_id, const char * format) { if ( !strcmp(format, "reference") ) { stream_type = MJPEG; - filename = "diagpipe-r.jpg"; + snprintf(diag_path, sizeof(diag_path), "%s/diagpipe-r-%d.jpg", + staticConfig.PATH_SOCKS.c_str(), monitor->Id()); } else if ( !strcmp(format, "delta") ) { - filename = "diagpipe-d.jpg"; + snprintf(diag_path, sizeof(diag_path), "%s/diagpipe-d-%d.jpg", + staticConfig.PATH_SOCKS.c_str(), monitor->Id()); stream_type = MJPEG; } else { + snprintf(diag_path, sizeof(diag_path), "%s/dbgpipe-%d.log", + staticConfig.PATH_SOCKS.c_str(), monitor->Id()); stream_type = RAW; - filename = "dbgpipe.log"; } - snprintf(diag_path, sizeof(diag_path), "%s/%d/%s", - staticConfig.PATH_SOCKS.c_str(), monitor->Id(), filename); setStreamStart(diag_path); } diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 8fed25acc..01779eed7 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -516,8 +516,8 @@ Monitor::Monitor( if ( config.record_diag_images ) { if ( config.record_diag_images_fifo ) { - diag_path_ref = stringtf("%s/%d/diagpipe-r.jpg", staticConfig.PATH_SOCKS.c_str(), id); - diag_path_delta = stringtf("%s/%d/diagpipe-d.jpg", staticConfig.PATH_SOCKS.c_str(), id); + diag_path_ref = stringtf("%s/diagpipe-r-%d.jpg", staticConfig.PATH_SOCKS.c_str(), id); + diag_path_delta = stringtf("%s/diagpipe-d-%d.jpg", staticConfig.PATH_SOCKS.c_str(), id); FifoStream::fifo_create_if_missing(diag_path_ref.c_str()); FifoStream::fifo_create_if_missing(diag_path_delta.c_str()); } else { From 66f7cc55dc670c0a5458b827b0d4f8345f7b4028 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 13 Nov 2020 17:05:23 -0500 Subject: [PATCH 0646/2339] Spacing code comments, quotes --- web/ajax/status.php | 74 ++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/web/ajax/status.php b/web/ajax/status.php index 795a4b581..994644afc 100644 --- a/web/ajax/status.php +++ b/web/ajax/status.php @@ -267,7 +267,6 @@ function collectData() { if ( count($fieldSql) ) { $sql = 'SELECT '.join(', ', $fieldSql).' FROM '.$entitySpec['table']; - #$sql = 'SELECT '.join(', ', array_map($fieldSql, function($f){return '`'.$f.'`';})).' FROM '.$entitySpec['table']; if ( $joinSql ) $sql .= ' '.join(' ', array_unique($joinSql)); if ( $id && !empty($entitySpec['selector']) ) { @@ -314,27 +313,27 @@ function collectData() { $limit = $entitySpec['limit']; elseif ( !empty($_REQUEST['count']) ) $limit = validInt($_REQUEST['count']); - $limit_offset=''; + $limit_offset = ''; if ( !empty($_REQUEST['offset']) ) $limit_offset = validInt($_REQUEST['offset']) . ', '; - if ( !empty( $limit ) ) + if ( !empty($limit) ) $sql .= ' limit '.$limit_offset.$limit; if ( isset($limit) && $limit == 1 ) { if ( $sqlData = dbFetchOne($sql, NULL, $values) ) { foreach ( $postFuncs as $element=>$func ) $sqlData[$element] = eval( 'return( '.$func.'( $sqlData ) );' ); - $data = array_merge( $data, $sqlData ); + $data = array_merge($data, $sqlData); } } else { $count = 0; - foreach( dbFetchAll( $sql, NULL, $values ) as $sqlData ) { + foreach ( dbFetchAll($sql, NULL, $values) as $sqlData ) { foreach ( $postFuncs as $element=>$func ) - $sqlData[$element] = eval( 'return( '.$func.'( $sqlData ) );' ); + $sqlData[$element] = eval('return( '.$func.'( $sqlData ) );'); $data[] = $sqlData; if ( isset($limi) && ++$count >= $limit ) break; - } - } + } # end foreach + } # end if have limit == 1 } } #ZM\Debug(print_r($data, true)); @@ -347,19 +346,19 @@ if ( !isset($_REQUEST['layout']) ) { $_REQUEST['layout'] = 'json'; } -switch( $_REQUEST['layout'] ) { +switch ( $_REQUEST['layout'] ) { case 'xml NOT CURRENTLY SUPPORTED' : - header('Content-type: application/xml'); - echo(' -'); - echo '<'.strtolower($_REQUEST['entity']).'> + header('Content-type: application/xml'); + echo(' + '); + echo '<'.strtolower($_REQUEST['entity']).'> '; - foreach ( $data as $key=>$value ) { - $key = strtolower($key); - echo "<$key>".htmlentities($value)."\n"; - } - echo '\n"; - break; + foreach ( $data as $key=>$value ) { + $key = strtolower($key); + echo "<$key>".htmlentities($value)."\n"; + } + echo '\n"; + break; case 'json' : { $response = array( strtolower(validJsStr($_REQUEST['entity'])) => $data ); @@ -369,11 +368,11 @@ switch( $_REQUEST['layout'] ) { break; } case 'text' : - header('Content-type: text/plain' ); - echo join( ' ', array_values( $data ) ); - break; + header('Content-type: text/plain'); + echo join(' ', array_values($data)); + break; default: - ZM\Error('Unsupported layout: '. $_REQUEST['layout']); + ZM\Error('Unsupported layout: '.$_REQUEST['layout']); } function getFrameImage() { @@ -381,38 +380,38 @@ function getFrameImage() { $frameId = $_REQUEST['id'][1]; $sql = 'SELECT * FROM Frames WHERE EventId = ? AND FrameId = ?'; - if ( !($frame = dbFetchOne( $sql, NULL, array($eventId, $frameId ) )) ) { + if ( !($frame = dbFetchOne($sql, NULL, array($eventId, $frameId))) ) { $frame = array(); $frame['EventId'] = $eventId; $frame['FrameId'] = $frameId; $frame['Type'] = 'Virtual'; } - $event = dbFetchOne( 'select * from Events where Id = ?', NULL, array( $frame['EventId'] ) ); - $frame['Image'] = getImageSrc( $event, $frame, SCALE_BASE ); - return( $frame ); + $event = dbFetchOne('SELECT * FROM Events WHERE Id = ?', NULL, array($frame['EventId'])); + $frame['Image'] = getImageSrc($event, $frame, SCALE_BASE); + return $frame; } function getNearFrame() { $eventId = $_REQUEST['id'][0]; $frameId = $_REQUEST['id'][1]; - $sql = 'select FrameId from Frames where EventId = ? and FrameId <= ? order by FrameId desc limit 1'; - if ( !$nearFrameId = dbFetchOne( $sql, 'FrameId', array( $eventId, $frameId ) ) ) { - $sql = 'select * from Frames where EventId = ? and FrameId > ? order by FrameId asc limit 1'; - if ( !$nearFrameId = dbFetchOne( $sql, 'FrameId', array( $eventId, $frameId ) ) ) { + $sql = 'SELECT FrameId FROM Frames WHERE EventId = ? AND FrameId <= ? ORDER BY FrameId DESC LIMIT 1'; + if ( !$nearFrameId = dbFetchOne($sql, 'FrameId', array($eventId, $frameId)) ) { + $sql = 'SELECT * FROM Frames WHERE EventId = ? AND FrameId > ? ORDER BY FrameId ASC LIMIT 1'; + if ( !$nearFrameId = dbFetchOne($sql, 'FrameId', array($eventId, $frameId)) ) { return( array() ); } } $_REQUEST['entity'] = 'frame'; $_REQUEST['id'][1] = $nearFrameId; - return( collectData() ); + return collectData(); } function getNearEvents() { global $user, $sortColumn, $sortOrder; $eventId = $_REQUEST['id']; - $NearEvents = array( 'EventId'=>$eventId ); + $NearEvents = array('EventId'=>$eventId); $event = dbFetchOne('SELECT * FROM Events WHERE Id=?', NULL, array($eventId)); if ( !$event ) return $NearEvents; @@ -423,7 +422,8 @@ function getNearEvents() { $filter = $filter->addTerm(array('cnj'=>'and', 'attr'=>'MonitorId', 'op'=>'IN', 'val'=>$user['MonitorIds'])); } - # When listing, it may make sense to list them in descending order. But when viewing Prev should timewise earlier and Next should be after. + # When listing, it may make sense to list them in descending order. + # But when viewing Prev should timewise earlier and Next should be after. if ( $sortColumn == 'E.Id' or $sortColumn == 'E.StartDateTime' ) { $sortOrder = 'ASC'; } @@ -436,7 +436,7 @@ function getNearEvents() { $sql .= ' LIMIT 1'; $result = dbQuery($sql); if ( !$result ) { - ZM\Error("Failed to load previous event using $sql"); + ZM\Error('Failed to load previous event using '.$sql); return $NearEvents; } @@ -450,7 +450,7 @@ function getNearEvents() { $sql .= ' LIMIT 1'; $result = dbQuery($sql); if ( !$result ) { - ZM\Error("Failed to load next event using $sql"); + ZM\Error('Failed to load next event using '.$sql); return $NearEvents; } $nextEvent = dbFetchNext($result); @@ -470,6 +470,6 @@ function getNearEvents() { $NearEvents['NextEventId'] = $NearEvents['NextEventStartTime'] = $NearEvents['NextEventDefVideoPath'] = 0; } return $NearEvents; -} +} # end function getNearEvents() ?> From f88d721ae3675b8f631f8bab0979c2aa4ce4c7f2 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 14 Nov 2020 10:27:33 -0600 Subject: [PATCH 0647/2339] fix issue with events view and ALL pagination --- web/ajax/events.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web/ajax/events.php b/web/ajax/events.php index cde2acc08..37e225527 100644 --- a/web/ajax/events.php +++ b/web/ajax/events.php @@ -58,7 +58,8 @@ if ( isset($_REQUEST['offset']) ) { $order = (isset($_REQUEST['order']) and (strtolower($_REQUEST['order']) == 'asc')) ? 'ASC' : 'DESC'; // Limit specifies the number of rows to return -$limit = 100; +// Set the default to 0 for events view, to prevent an issue with ALL pagination +$limit = 0; if ( isset($_REQUEST['limit']) ) { if ( ( !is_int($_REQUEST['limit']) and !ctype_digit($_REQUEST['limit']) ) ) { ZM\Error('Invalid value for limit: ' . $_REQUEST['limit']); From 9aa6fea6a3456411530f97924853dc7e559dce44 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 14 Nov 2020 14:19:28 -0600 Subject: [PATCH 0648/2339] frames view server pagination WIP --- web/ajax/frames.php | 118 ++++++++++++++--------- web/skins/classic/views/js/frames.js | 29 +++++- web/skins/classic/views/js/frames.js.php | 1 + 3 files changed, 99 insertions(+), 49 deletions(-) diff --git a/web/ajax/frames.php b/web/ajax/frames.php index fb23980a8..664f14bf7 100644 --- a/web/ajax/frames.php +++ b/web/ajax/frames.php @@ -14,6 +14,8 @@ if ( empty($_REQUEST['task']) ) { // query is the only supported task at the moment } else if ( $_REQUEST['task'] != 'query' ) { $message = 'Unrecognised task '.$_REQUEST['task']; + } else { + $task = $_REQUEST['task']; } if ( empty($_REQUEST['eid']) ) { @@ -54,7 +56,7 @@ if ( isset($_REQUEST['offset']) ) { $order = (isset($_REQUEST['order']) and (strtolower($_REQUEST['order']) == 'asc')) ? 'ASC' : 'DESC'; // Limit specifies the number of rows to return -$limit = 100; +$limit = 0; if ( isset($_REQUEST['limit']) ) { if ( ( !is_int($_REQUEST['limit']) and !ctype_digit($_REQUEST['limit']) ) ) { ZM\Error('Invalid value for limit: ' . $_REQUEST['limit']); @@ -84,8 +86,12 @@ ajaxResponse($data); function queryRequest($eid, $search, $advsearch, $sort, $offset, $order, $limit) { - // The table we want our data from - $table = 'Frames'; + $data = array( + 'total' => 0, + 'totalNotFiltered' => 0, + 'rows' => array(), + 'updated' => preg_match('/%/', DATE_FMT_CONSOLE_LONG) ? strftime(DATE_FMT_CONSOLE_LONG) : date(DATE_FMT_CONSOLE_LONG) + ); // The names of the dB columns in the events table we are interested in $columns = array('EventId', 'FrameId', 'Type', 'TimeStamp', 'Delta', 'Score'); @@ -99,56 +105,64 @@ function queryRequest($eid, $search, $advsearch, $sort, $offset, $order, $limit) $Monitor = $Event->Monitor(); $values = array(); $likes = array(); - $where = 'EventId ='.$eid; + $where = 'WHERE EventId = '.$eid; - // There are two search bars in the log view, normal and advanced - // Making an exuctive decision to ignore the normal search, when advanced search is in use - // Alternatively we could try to do both - if ( count($advsearch) ) { + $sql = 'SELECT * FROM `Frames` '.$where.' ORDER BY '.$sort.' '.$order; - foreach ( $advsearch as $col=>$text ) { - if ( !in_array($col, array_merge($columns, $col_alt)) ) { - ZM\Error("'$col' is not a searchable column name"); - continue; + //ZM\Debug('Calling the following sql query: ' .$sql); + + $unfiltered_rows = array(); + $frame_ids = array(); + require_once('includes/Frame.php'); + foreach ( dbFetchAll($sql, NULL, $values) as $row ) { + $frame = new ZM\Frame($row); + $frame_ids[] = $frame->Id(); + $unfiltered_rows[] = $row; + } + + ZM\Debug('Have ' . count($unfiltered_rows) . ' frames matching base filter.'); + + $filtered_rows = null; + require_once('includes/Filter.php'); + if ( count($advsearch) or $search != '' ) { + $search_filter = new ZM\Filter(); + $search_filter = $search_filter->addTerm(array('cnj'=>'and', 'attr'=>'Id', 'op'=>'IN', 'val'=>$frame_ids)); + + // There are two search bars in the log view, normal and advanced + // Making an exuctive decision to ignore the normal search, when advanced search is in use + // Alternatively we could try to do both + if ( count($advsearch) ) { + $terms = array(); + foreach ( $advsearch as $col=>$text ) { + $terms[] = array('cnj'=>'and', 'attr'=>$col, 'op'=>'LIKE', 'val'=>$text); + } # end foreach col in advsearch + $terms[0]['obr'] = 1; + $terms[count($terms)-1]['cbr'] = 1; + $search_filter->addTerms($terms); + } else if ( $search != '' ) { + $search = '%' .$search. '%'; + $terms = array(); + foreach ( $columns as $col ) { + $terms[] = array('cnj'=>'or', 'attr'=>$col, 'op'=>'LIKE', 'val'=>$search); } - // Don't use wildcards on advanced search - //$text = '%' .$text. '%'; - array_push($likes, $col.' LIKE ?'); - array_push($query['values'], $text); - } - $wherevalues = $query['values']; - $where = ' WHERE (' .implode(' OR ', $likes). ')'; + $terms[0]['obr'] = 1; + $terms[0]['cnj'] = 'and'; + $terms[count($terms)-1]['cbr'] = 1; + $search_filter = $search_filter->addTerms($terms, array('obr'=>1, 'cbr'=>1, 'op'=>'OR')); + } # end if search - } else if ( $search != '' ) { - - $search = '%' .$search. '%'; - foreach ( $columns as $col ) { - array_push($likes, $col.' LIKE ?'); - array_push($query['values'], $search); - } - $wherevalues = $query['values']; - $where = ' WHERE (' .implode(' OR ', $likes). ')'; - } - - $query['sql'] = 'SELECT ' .$col_str. ' FROM `' .$table. '` ' .$where. ' ORDER BY ' .$sort. ' ' .$order. ' LIMIT ?, ?'; - array_push($query['values'], $offset, $limit); - - $data['totalNotFiltered'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table, 'Total'); - if ( $search != '' || count($advsearch) ) { - $data['total'] = dbFetchOne('SELECT count(*) AS Total FROM ' .$table.$where , 'Total', $wherevalues); + $sql = 'SELECT * FROM `Frames` WHERE '.$search_filter->sql().' ORDER BY ' .$sort. ' ' .$order; + $filtered_rows = dbFetchAll($sql); + ZM\Debug('Have ' . count($filtered_rows) . ' frames matching search filter.'); } else { - $data['total'] = $data['totalNotFiltered']; - } + $filtered_rows = $unfiltered_rows; + } # end if search_filter->terms() > 1 $returned_rows = array(); - $results = dbFetchAll($query['sql'], NULL, $query['values']); - if ( !$results ) { - return $data; - } - - foreach ( $results as $row ) { + foreach ( array_slice($filtered_rows, $offset, $limit) as $row ) { + if ( ZM_WEB_LIST_THUMBS ) { $base_img_src = '?view=image&fid=' .$row['FrameId']; - $ratio_factor = $Monitor->ViewHeight() / $Monitor->ViewWidth(); + $ratio_factor = $Monitor->ViewHeight() / $Monitor->ViewWidth(); $thmb_width = ZM_WEB_LIST_THUMB_WIDTH ? 'width='.ZM_WEB_LIST_THUMB_WIDTH : ''; $thmb_height = 'height="'.( ZM_WEB_LIST_THUMB_HEIGHT ? ZM_WEB_LIST_THUMB_HEIGHT : ZM_WEB_LIST_THUMB_WIDTH*$ratio_factor ) .'"'; $thmb_fn = 'filename=' .$Event->MonitorId(). '_' .$row['EventId']. '_' .$row['FrameId']. '.jpg'; @@ -156,10 +170,20 @@ function queryRequest($eid, $search, $advsearch, $sort, $offset, $order, $limit) $full_img_src = join('&', array_filter(array($base_img_src, $thmb_fn))); $frame_src = '?view=frame&eid=' .$row['EventId']. '&fid=' .$row['FrameId']; - $row['imgHtml'] = ''.PHP_EOL; + $row['Thumbnail'] = ''; + } $returned_rows[] = $row; - } + } # end foreach row matching search + $data['rows'] = $returned_rows; + # totalNotFiltered must equal total, except when either search bar has been used + $data['totalNotFiltered'] = count($unfiltered_rows); + if ( $search != '' || count($advsearch) ) { + $data['total'] = count($filtered_rows); + } else { + $data['total'] = $data['totalNotFiltered']; + } + return $data; } diff --git a/web/skins/classic/views/js/frames.js b/web/skins/classic/views/js/frames.js index fcdb27303..ff407589b 100644 --- a/web/skins/classic/views/js/frames.js +++ b/web/skins/classic/views/js/frames.js @@ -1,3 +1,6 @@ +var backBtn = $j('#backBtn'); +var table = $j('#framesTable'); + // Called by bootstrap-table to retrieve zm frame data function ajaxRequest(params) { if ( params.data && params.data.filter ) { @@ -8,6 +11,8 @@ function ajaxRequest(params) { .done(function(data) { var rows = processRows(data.rows); // rearrange the result into what bootstrap-table expects + console.log('Total: '+data.total); + console.log('TotalnotFiltered: '+data.totalNotFiltered); params.success({total: data.total, totalNotFiltered: data.totalNotFiltered, rows: rows}); }) .fail(logAjaxFail); @@ -16,6 +21,7 @@ function ajaxRequest(params) { function processRows(rows) { $j.each(rows, function(ndx, row) { // WIP: process each row here + // VERIFY: Might not need to do anything here for the frames table }); return rows; } @@ -56,9 +62,10 @@ function detailFormatter(index, row, $detail) { }) .fail(logAjaxFail); } + function initPage() { - var backBtn = $j('#backBtn'); - var table = $j('#framesTable'); + // Remove the thumbnail column from the DOM if thumbnails are off globally + if ( !WEB_LIST_THUMBS ) $j('th[data-field="Thumbnail"]').remove(); // Init the bootstrap-table table.bootstrapTable({icons: icons}); @@ -93,6 +100,24 @@ function initPage() { evt.preventDefault(); window.location.reload(true); }); + + // Update table links each time after new data is loaded + table.on('post-body.bs.table', function(data) { + var type_ndx = $j('#framesTable tr th').filter(function() { + return $j(this).text().trim() == 'Type'; + }).index(); + + $j('#framesTable tr').each(function(ndx, row) { + var row = $j(row); + var type = row.find('td').eq(type_ndx).text().trim(); + row.addClass(type.toLowerCase()); + }); + + var thumb_ndx = $j('#framesTable tr th').filter(function() { + return $j(this).text().trim() == 'Thumbnail'; + }).index(); + table.find("tr td:nth-child(" + (thumb_ndx+1) + ")").addClass('colThumbnail zoom'); + }); } $j(document).ready(function() { diff --git a/web/skins/classic/views/js/frames.js.php b/web/skins/classic/views/js/frames.js.php index 48b33b5e3..e8aa37a4d 100644 --- a/web/skins/classic/views/js/frames.js.php +++ b/web/skins/classic/views/js/frames.js.php @@ -1 +1,2 @@ var eid = ; +var WEB_LIST_THUMBS = ; From f3756def08f49e08ffb47a9abaa5084ab331eb7a Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 14 Nov 2020 14:45:22 -0600 Subject: [PATCH 0649/2339] deploy server side pagination for frames view --- web/ajax/frames.php | 2 +- web/skins/classic/views/frames.php | 138 ++------------------------- web/skins/classic/views/js/frames.js | 2 +- 3 files changed, 11 insertions(+), 131 deletions(-) diff --git a/web/ajax/frames.php b/web/ajax/frames.php index 664f14bf7..440c9769e 100644 --- a/web/ajax/frames.php +++ b/web/ajax/frames.php @@ -161,7 +161,7 @@ function queryRequest($eid, $search, $advsearch, $sort, $offset, $order, $limit) $returned_rows = array(); foreach ( array_slice($filtered_rows, $offset, $limit) as $row ) { if ( ZM_WEB_LIST_THUMBS ) { - $base_img_src = '?view=image&fid=' .$row['FrameId']; + $base_img_src = '?view=image&fid=' .$row['Id']; $ratio_factor = $Monitor->ViewHeight() / $Monitor->ViewWidth(); $thmb_width = ZM_WEB_LIST_THUMB_WIDTH ? 'width='.ZM_WEB_LIST_THUMB_WIDTH : ''; $thmb_height = 'height="'.( ZM_WEB_LIST_THUMB_HEIGHT ? ZM_WEB_LIST_THUMB_HEIGHT : ZM_WEB_LIST_THUMB_WIDTH*$ratio_factor ) .'"'; diff --git a/web/skins/classic/views/frames.php b/web/skins/classic/views/frames.php index da2f4c2ae..fce04cc60 100644 --- a/web/skins/classic/views/frames.php +++ b/web/skins/classic/views/frames.php @@ -28,87 +28,6 @@ require_once('includes/Filter.php'); $eid = validInt($_REQUEST['eid']); $Event = new ZM\Event($eid); -$Monitor = $Event->Monitor(); - -$countSql = 'SELECT COUNT(*) AS FrameCount FROM Frames AS F WHERE 1 '; -$frameSql = 'SELECT *, unix_timestamp(TimeStamp) AS UnixTimeStamp FROM Frames AS F WHERE 1 '; - -// override the sort_field handling in parseSort for frames -if ( empty($_REQUEST['sort_field']) ) - $_REQUEST['sort_field'] = 'FramesTimeStamp'; - -if ( !isset($_REQUEST['sort_asc']) ) - $_REQUEST['sort_asc'] = true; - -if ( !isset($_REQUEST['filter']) ) { - // generate a dummy filter from the eid for pagination - $_REQUEST['filter'] = array('Query' => array('terms' => array())); - $_REQUEST['filter'] = addFilterTerm( - $_REQUEST['filter'], - 0, - array( 'cnj' => 'and', 'attr' => 'FramesEventId', 'op' => '=', 'val' => $eid ) - ); -} - -parseSort(); -$filter = ZM\Filter::parse($_REQUEST['filter']); -$filterQuery = $filter->querystring(); - -if ( $filter->sql() ) { - $countSql .= ' AND ('.$filter->sql().')'; - $frameSql .= ' AND ('.$filter->sql().')'; -} - -$frameSql .= " ORDER BY $sortColumn $sortOrder"; -if ( $sortColumn != 'Id' ) - $frameSql .= ',Id '.$sortOrder; - -if ( isset($_REQUEST['scale']) ) { - $scale = validNum($_REQUEST['scale']); -} else if ( isset($_COOKIE['zmWatchScale'.$Monitor->Id()]) ) { - $scale = validNum($_COOKIE['zmWatchScale'.$Monitor->Id()]); -} else if ( isset($_COOKIE['zmWatchScale']) ) { - $scale = validNum($_COOKIE['zmWatchScale']); -} else { - $scale = max(reScale(SCALE_BASE, $Monitor->DefaultScale(), ZM_WEB_DEFAULT_SCALE), SCALE_BASE); -} - -$page = isset($_REQUEST['page']) ? validInt($_REQUEST['page']) : 1; -$limit = isset($_REQUEST['limit']) ? validInt($_REQUEST['limit']) : 0; - -$nFrames = dbFetchOne($countSql, 'FrameCount'); - -if ( !empty($limit) && ($nFrames > $limit) ) { - $nFrames = $limit; -} - -$pages = (int)ceil($nFrames/ZM_WEB_EVENTS_PER_PAGE); - -if ( !empty($page) ) { - if ( $page <= 0 ) - $page = 1; - else if ( $pages and ( $page > $pages ) ) - $page = $pages; - - $limitStart = (($page-1)*ZM_WEB_EVENTS_PER_PAGE); - if ( empty($limit) ) { - $limitAmount = ZM_WEB_EVENTS_PER_PAGE; - } else { - $limitLeft = $limit - $limitStart; - $limitAmount = ($limitLeft>ZM_WEB_EVENTS_PER_PAGE)?ZM_WEB_EVENTS_PER_PAGE:$limitLeft; - } - $frameSql .= " LIMIT $limitStart, $limitAmount"; -} else if ( !empty($limit) ) { - $frameSql .= ' LIMIT 0, '.$limit; -} - -$maxShortcuts = 5; -$totalQuery = $sortQuery.'&eid='.$eid.$limitQuery.$filterQuery; -$pagination = getPagination($pages, $page, $maxShortcuts, $totalQuery); - -$frames = dbFetchAll($frameSql); - -$focusWindow = true; xhtmlHeaders(__FILE__, translate('Frames').' - '.$Event->Id()); ?> @@ -126,6 +45,8 @@ xhtmlHeaders(__FILE__, translate('Frames').' - '.$Event->Id()); Id()); data-detail-formatter="detailFormatter" data-show-toggle="true" data-show-jump-to="true" + data-show-refresh="true" class="table-sm table-borderless"> @@ -152,58 +74,16 @@ xhtmlHeaders(__FILE__, translate('Frames').' - '.$Event->Id()); - - - - - + + + + - - - - - - - - - -Id(); - $ratio_factor = $Monitor->ViewHeight() / $Monitor->ViewWidth(); - $thmb_width = ZM_WEB_LIST_THUMB_WIDTH ? 'width='.ZM_WEB_LIST_THUMB_WIDTH : ''; - $thmb_height = 'height="'.( ZM_WEB_LIST_THUMB_HEIGHT ? ZM_WEB_LIST_THUMB_HEIGHT : ZM_WEB_LIST_THUMB_WIDTH*$ratio_factor ) .'"'; - $thmb_fn = 'filename=' .$Event->MonitorId(). '_' .$frame['EventId']. '_' .$frame['FrameId']. '.jpg'; - $img_src = join('&', array_filter(array($base_img_src, $thmb_width, $thmb_height, $thmb_fn))); - $full_img_src = join('&', array_filter(array($base_img_src, $thmb_fn))); - $frame_src = '?view=frame&eid=' .$Event->Id(). '&fid=' .$frame['FrameId']; - - echo ''.PHP_EOL; - } -?> - - - - - - - + +
diff --git a/web/skins/classic/views/js/frames.js b/web/skins/classic/views/js/frames.js index ff407589b..c569d8447 100644 --- a/web/skins/classic/views/js/frames.js +++ b/web/skins/classic/views/js/frames.js @@ -46,7 +46,7 @@ function initThumbAnimation() { } function processClicks(event, field, value, row, $element) { - if ( field == 'FrameScore' ) { + if ( field == 'Score' ) { window.location.assign('?view=stats&eid='+row.EventId+'&fid='+row.FrameId); } else { window.location.assign('?view=frame&eid='+row.EventId+'&fid='+row.FrameId); From 45fbdfa0502768cea450db6901e330dbd0f5ca96 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 14 Nov 2020 16:01:34 -0600 Subject: [PATCH 0650/2339] rough in support for frames view search function --- web/includes/FilterTerm.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/web/includes/FilterTerm.php b/web/includes/FilterTerm.php index 6b41a2e1d..3675a502f 100644 --- a/web/includes/FilterTerm.php +++ b/web/includes/FilterTerm.php @@ -237,6 +237,9 @@ class FilterTerm { case 'StartDateTime': $sql .= 'E.StartDateTime'; break; + case 'FramesId': + $sql .= 'Id'; + break; case 'FramesEventId': $sql .= 'F.EventId'; break; @@ -419,6 +422,12 @@ class FilterTerm { public static function is_valid_attr($attr) { $attrs = array( + 'Score', + 'Delta', + 'TimeStamp', + 'Type', + 'FrameId', + 'EventId', 'ExistsInFileSystem', 'Emailed', 'DiskSpace', @@ -434,6 +443,7 @@ class FilterTerm { 'Time', 'Weekday', 'StartDateTime', + 'FramesId', 'FramesEventId', 'StartDate', 'StartTime', From 416d68a9718764dc09d8e4fa5f546632bf94df9b Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 14 Nov 2020 16:49:22 -0600 Subject: [PATCH 0651/2339] rough in support for frames view search function --- web/ajax/frames.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/ajax/frames.php b/web/ajax/frames.php index 440c9769e..6438b2b92 100644 --- a/web/ajax/frames.php +++ b/web/ajax/frames.php @@ -126,7 +126,7 @@ function queryRequest($eid, $search, $advsearch, $sort, $offset, $order, $limit) require_once('includes/Filter.php'); if ( count($advsearch) or $search != '' ) { $search_filter = new ZM\Filter(); - $search_filter = $search_filter->addTerm(array('cnj'=>'and', 'attr'=>'Id', 'op'=>'IN', 'val'=>$frame_ids)); + $search_filter = $search_filter->addTerm(array('cnj'=>'and', 'attr'=>'FramesId', 'op'=>'IN', 'val'=>$frame_ids)); // There are two search bars in the log view, normal and advanced // Making an exuctive decision to ignore the normal search, when advanced search is in use From 0ffb5e153c23642282d8aae0772d01b8fab8477c Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 14 Nov 2020 17:33:18 -0600 Subject: [PATCH 0652/2339] modify FilterTerm to support Frames view searches --- web/ajax/frames.php | 638 ++++++++++++++++++++++++++---------- web/includes/FilterTerm.php | 16 + 2 files changed, 481 insertions(+), 173 deletions(-) diff --git a/web/ajax/frames.php b/web/ajax/frames.php index 440c9769e..42f939128 100644 --- a/web/ajax/frames.php +++ b/web/ajax/frames.php @@ -1,189 +1,481 @@ "search text" pairs -// Bootstrap table sends json_ecoded array, which we must decode -$advsearch = isset($_REQUEST['advsearch']) ? json_decode($_REQUEST['advsearch'], JSON_OBJECT_AS_ARRAY) : array(); - -// Sort specifies the name of the column to sort on -$sort = 'FrameId'; -if ( isset($_REQUEST['sort']) ) { - $sort = $_REQUEST['sort']; -} - -// Offset specifies the starting row to return, used for pagination -$offset = 0; -if ( isset($_REQUEST['offset']) ) { - if ( ( !is_int($_REQUEST['offset']) and !ctype_digit($_REQUEST['offset']) ) ) { - ZM\Error('Invalid value for offset: ' . $_REQUEST['offset']); - } else { - $offset = $_REQUEST['offset']; +function getFilterQueryConjunctionTypes() { + if ( !isset($validConjunctionTypes ) ) { + $validConjunctionTypes = array( + 'and' => translate('ConjAnd'), + 'or' => translate('ConjOr') + ); } + return $validConjunctionTypes; } -// Order specifies the sort direction, either asc or desc -$order = (isset($_REQUEST['order']) and (strtolower($_REQUEST['order']) == 'asc')) ? 'ASC' : 'DESC'; -// Limit specifies the number of rows to return -$limit = 0; -if ( isset($_REQUEST['limit']) ) { - if ( ( !is_int($_REQUEST['limit']) and !ctype_digit($_REQUEST['limit']) ) ) { - ZM\Error('Invalid value for limit: ' . $_REQUEST['limit']); - } else { - $limit = $_REQUEST['limit']; - } -} +class FilterTerm { + public $filter; + public $index; + public $attr; + public $op; + public $val; + public $values; + public $cnj; + public $obr; + public $cbr; -// -// MAIN LOOP -// -// Only one supported task at the moment -switch ( $task ) { - case 'query' : - $data = queryRequest($eid, $search, $advsearch, $sort, $offset, $order, $limit); - break; - default : - ZM\Fatal("Unrecognised task '$task'"); -} // end switch task + public function __construct($filter = null, $term = NULL, $index=0) { + $this->filter = $filter; + $validConjunctionTypes = getFilterQueryConjunctionTypes(); -ajaxResponse($data); - -// -// FUNCTION DEFINITIONS -// - -function queryRequest($eid, $search, $advsearch, $sort, $offset, $order, $limit) { - - $data = array( - 'total' => 0, - 'totalNotFiltered' => 0, - 'rows' => array(), - 'updated' => preg_match('/%/', DATE_FMT_CONSOLE_LONG) ? strftime(DATE_FMT_CONSOLE_LONG) : date(DATE_FMT_CONSOLE_LONG) - ); - - // The names of the dB columns in the events table we are interested in - $columns = array('EventId', 'FrameId', 'Type', 'TimeStamp', 'Delta', 'Score'); - - if ( !in_array($sort, $columns) ) { - ZM\Error('Invalid sort field: ' . $sort); - $sort = 'FrameId'; - } - - $Event = new ZM\Event($eid); - $Monitor = $Event->Monitor(); - $values = array(); - $likes = array(); - $where = 'WHERE EventId = '.$eid; - - $sql = 'SELECT * FROM `Frames` '.$where.' ORDER BY '.$sort.' '.$order; - - //ZM\Debug('Calling the following sql query: ' .$sql); - - $unfiltered_rows = array(); - $frame_ids = array(); - require_once('includes/Frame.php'); - foreach ( dbFetchAll($sql, NULL, $values) as $row ) { - $frame = new ZM\Frame($row); - $frame_ids[] = $frame->Id(); - $unfiltered_rows[] = $row; - } - - ZM\Debug('Have ' . count($unfiltered_rows) . ' frames matching base filter.'); - - $filtered_rows = null; - require_once('includes/Filter.php'); - if ( count($advsearch) or $search != '' ) { - $search_filter = new ZM\Filter(); - $search_filter = $search_filter->addTerm(array('cnj'=>'and', 'attr'=>'Id', 'op'=>'IN', 'val'=>$frame_ids)); - - // There are two search bars in the log view, normal and advanced - // Making an exuctive decision to ignore the normal search, when advanced search is in use - // Alternatively we could try to do both - if ( count($advsearch) ) { - $terms = array(); - foreach ( $advsearch as $col=>$text ) { - $terms[] = array('cnj'=>'and', 'attr'=>$col, 'op'=>'LIKE', 'val'=>$text); - } # end foreach col in advsearch - $terms[0]['obr'] = 1; - $terms[count($terms)-1]['cbr'] = 1; - $search_filter->addTerms($terms); - } else if ( $search != '' ) { - $search = '%' .$search. '%'; - $terms = array(); - foreach ( $columns as $col ) { - $terms[] = array('cnj'=>'or', 'attr'=>$col, 'op'=>'LIKE', 'val'=>$search); + $this->index = $index; + $this->attr = $term['attr']; + $this->op = $term['op']; + $this->val = $term['val']; + if ( isset($term['cnj']) ) { + if ( array_key_exists($term['cnj'], $validConjunctionTypes) ) { + $this->cnj = $term['cnj']; + } else { + Warning('Invalid cnj ' . $term['cnj'].' in '.print_r($term, true)); } - $terms[0]['obr'] = 1; - $terms[0]['cnj'] = 'and'; - $terms[count($terms)-1]['cbr'] = 1; - $search_filter = $search_filter->addTerms($terms, array('obr'=>1, 'cbr'=>1, 'op'=>'OR')); - } # end if search - - $sql = 'SELECT * FROM `Frames` WHERE '.$search_filter->sql().' ORDER BY ' .$sort. ' ' .$order; - $filtered_rows = dbFetchAll($sql); - ZM\Debug('Have ' . count($filtered_rows) . ' frames matching search filter.'); - } else { - $filtered_rows = $unfiltered_rows; - } # end if search_filter->terms() > 1 - - $returned_rows = array(); - foreach ( array_slice($filtered_rows, $offset, $limit) as $row ) { - if ( ZM_WEB_LIST_THUMBS ) { - $base_img_src = '?view=image&fid=' .$row['Id']; - $ratio_factor = $Monitor->ViewHeight() / $Monitor->ViewWidth(); - $thmb_width = ZM_WEB_LIST_THUMB_WIDTH ? 'width='.ZM_WEB_LIST_THUMB_WIDTH : ''; - $thmb_height = 'height="'.( ZM_WEB_LIST_THUMB_HEIGHT ? ZM_WEB_LIST_THUMB_HEIGHT : ZM_WEB_LIST_THUMB_WIDTH*$ratio_factor ) .'"'; - $thmb_fn = 'filename=' .$Event->MonitorId(). '_' .$row['EventId']. '_' .$row['FrameId']. '.jpg'; - $img_src = join('&', array_filter(array($base_img_src, $thmb_width, $thmb_height, $thmb_fn))); - $full_img_src = join('&', array_filter(array($base_img_src, $thmb_fn))); - $frame_src = '?view=frame&eid=' .$row['EventId']. '&fid=' .$row['FrameId']; - - $row['Thumbnail'] = ''; } - $returned_rows[] = $row; - } # end foreach row matching search - $data['rows'] = $returned_rows; + if ( isset($term['obr']) ) { + if ( (string)(int)$term['obr'] == $term['obr'] ) { + $this->obr = $term['obr']; + } else { + Warning('Invalid obr ' . $term['obr'] . ' in ' . print_r($term, true)); + } + } + if ( isset($term['cbr']) ) { + if ( (string)(int)$term['cbr'] == $term['cbr'] ) { + $this->cbr = $term['cbr']; + } else { + Warning('Invalid cbr ' . $term['cbr'] . ' in ' . print_r($term, true)); + } + } + } # end function __construct - # totalNotFiltered must equal total, except when either search bar has been used - $data['totalNotFiltered'] = count($unfiltered_rows); - if ( $search != '' || count($advsearch) ) { - $data['total'] = count($filtered_rows); - } else { - $data['total'] = $data['totalNotFiltered']; + # Returns an array of values. AS term->value can be a list, we will break it apart, remove quotes etc + public function sql_values() { + $values = array(); + if ( !isset($this->val) ) { + Logger::Warning('No value in term'.$this->attr); + return $values; + } + + $vals = is_array($this->val) ? $this->val : preg_split('/["\'\s]*?,["\'\s]*?/', preg_replace('/^["\']+?(.+)["\']+?$/', '$1', $this->val)); + foreach ( $vals as $value ) { + + switch ( $this->attr ) { + + case 'AlarmedZoneId': + $value = '(SELECT * FROM Stats WHERE EventId=E.Id AND ZoneId='.$value.')'; + break; + case 'ExistsInFileSystem': + $value = ''; + break; + case 'DiskPercent': + $value = ''; + break; + case 'MonitorName': + case 'MonitorName': + case 'Name': + case 'Cause': + case 'Notes': + if ( strstr($this->op, 'LIKE') and ! strstr($this->val, '%' ) ) { + $value = '%'.$value.'%'; + } + $value = dbEscape($value); + break; + case 'MonitorServerId': + case 'FilterServerId': + case 'StorageServerId': + case 'ServerId': + if ( $value == 'ZM_SERVER_ID' ) { + $value = ZM_SERVER_ID; + } else if ( $value == 'NULL' ) { + + } else { + $value = dbEscape($value); + } + break; + case 'StorageId': + if ( $value != 'NULL' ) { + $value = dbEscape($value); + } + break; + case 'DateTime': + case 'StartDateTime': + case 'EndDateTime': + if ( $value != 'NULL' ) + $value = '\''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\''; + break; + case 'Date': + case 'StartDate': + case 'EndDate': + if ( $value == 'CURDATE()' or $value == 'NOW()' ) { + $value = 'to_days('.$value.')'; + } else if ( $value != 'NULL' ) { + $value = 'to_days(\''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\')'; + } + break; + case 'Time': + case 'StartTime': + case 'EndTime': + if ( $value != 'NULL' ) + $value = 'extract(hour_second from \''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\')'; + break; + default : + if ( $value == 'Odd' ) { + $value = 1; + } else if ( $value == 'Even' ) { + $value = 0; + } else if ( $value != 'NULL' ) + $value = dbEscape($value); + break; + } + $values[] = $value; + } // end foreach value + return $values; + } # end function sql_values + + public function sql_operator() { + switch ( $this->attr ) { + case 'AlarmZoneId': + return ' EXISTS '; + case 'ExistsInFileSystem': + case 'DiskPercent': + return ''; + } + + + switch ( $this->op ) { + case '=' : + case '!=' : + case '>=' : + case '>' : + case '<' : + case '<=' : + case 'LIKE' : + case 'NOT LIKE': + return ' '.$this->op.' '; + case '=~' : + return ' regexp '; + case '!~' : + return ' not regexp '; + case '=[]' : + case 'IN' : + return ' IN '; + case '![]' : + return ' NOT IN '; + case 'EXISTS' : + return ' EXISTS '; + case 'IS' : + # Odd will be replaced with 1 + # Even will be replaced with 0 + if ( $this->val == 'Odd' or $this->val == 'Even' ) { + return ' % 2 = '; + } else { + return ' IS '; + } + case 'IS NOT' : + if ( $this->val == 'Odd' or $this->val == 'Even' ) { + return ' % 2 = '; + } + return ' IS NOT '; + default: + Warning('Invalid operator in filter: ' . print_r($this->op, true)); + } // end switch op + } # end public function sql_operator + + /* Some terms don't have related SQL */ + public function sql() { + + $sql = ''; + if ( isset($this->cnj) ) { + $sql .= ' '.$this->cnj.' '; + } + if ( isset($this->obr) ) { + $sql .= ' '.str_repeat('(', $this->obr).' '; + } + + switch ( $this->attr ) { + case 'ExistsInFileSystem': + case 'DiskPercent': + $sql .= 'TRUE /*'.$this->attr.'*/'; + break; + case 'MonitorName': + $sql .= 'M.Name'; + break; + case 'ServerId': + case 'MonitorServerId': + $sql .= 'M.ServerId'; + break; + case 'StorageServerId': + $sql .= 'S.ServerId'; + break; + case 'FilterServerId': + $sql .= ZM_SERVER_ID; + break; + # Unspecified start or end, so assume start, this is to support legacy filters + case 'DateTime': + $sql .= 'E.StartDateTime'; + break; + case 'Date': + $sql .= 'to_days(E.StartDateTime)'; + break; + case 'Time': + $sql .= 'extract(hour_second FROM E.StartDateTime)'; + break; + case 'Weekday': + $sql .= 'weekday(E.StartDateTime)'; + break; + # Starting Time + case 'StartDateTime': + $sql .= 'E.StartDateTime'; + break; + case 'FrameId': + $sql .= 'Id'; + break; + case 'Type': + case 'TimeStamp': + case 'Delta': + case 'Score': + $sql .= $this->attr; + break; + case 'FramesEventId': + $sql .= 'F.EventId'; + break; + case 'StartDate': + $sql .= 'to_days(E.StartDateTime)'; + break; + case 'StartTime': + $sql .= 'extract(hour_second FROM E.StartDateTime)'; + break; + case 'StartWeekday': + $sql .= 'weekday(E.StartDateTime)'; + break; + # Ending Time + case 'EndDateTime': + $sql .= 'E.EndDateTime'; + break; + case 'EndDate': + $sql .= 'to_days(E.EndDateTime)'; + break; + case 'EndTime': + $sql .= 'extract(hour_second FROM E.EndDateTime)'; + break; + case 'EndWeekday': + $sql .= 'weekday(E.EndDateTime)'; + break; + case 'Emailed': + case 'Id': + case 'Name': + case 'DiskSpace': + case 'MonitorId': + case 'StorageId': + case 'SecondaryStorageId': + case 'Length': + case 'Frames': + case 'AlarmFrames': + case 'TotScore': + case 'AvgScore': + case 'MaxScore': + case 'Cause': + case 'Notes': + case 'StateId': + case 'Archived': + $sql .= 'E.'.$this->attr; + } + $sql .= $this->sql_operator(); + $values = $this->sql_values(); + if ( (count($values) > 1) or ($this->op == 'IN') or ($this->op == 'NOT IN') ) { + $sql .= '('.join(',', $values).')'; + } else { + $sql .= $values[0]; + } + + if ( isset($this->cbr) ) { + $sql .= ' '.str_repeat(')', $this->cbr).' '; + } + return $sql; + } # end public function sql + + public function querystring($objectname='filter', $querySep='&') { + # We don't validate the term parameters here + $query = ''; + if ( $this->cnj ) + $query .= $querySep.urlencode($objectname.'[Query][terms]['.$this->index.'][cnj]').'='.$this->cnj; + if ( $this->obr ) + $query .= $querySep.urlencode($objectname.'[Query][terms]['.$this->index.'][obr]').'='.$this->obr; + + $query .= $querySep.urlencode($objectname.'[Query][terms]['.$this->index.'][attr]').'='.urlencode($this->attr); + $query .= $querySep.urlencode($objectname.'[Query][terms]['.$this->index.'][op]').'='.urlencode($this->op); + $query .= $querySep.urlencode($objectname.'[Query][terms]['.$this->index.'][val]').'='.urlencode($this->val); + if ( $this->cbr ) + $query .= $querySep.urlencode($objectname.'[Query][terms]['.$this->index.'][cbr]').'='.$this->cbr; + return $query; + } # end public function querystring + + public function hidden_fields() { + $html =''; + if ( $this->cnj ) + $html .= ''.PHP_EOL; + + if ( $this->obr ) + $html .= ''.PHP_EOL; + + # attr should have been already validation, so shouldn't need htmlspecialchars + $html .= ''.PHP_EOL; + $html .= ''.PHP_EOL; + $html .= ''.PHP_EOL; + if ( $this->cbr ) + $html .= ''.PHP_EOL; + + return $html; + } # end public function hiddens_fields + + public function test($event=null) { + if ( !isset($event) ) { + # Is a Pre Condition + Debug("Testing " . $this->attr); + if ( $this->attr == 'DiskPercent' ) { + # The logic on this is really ugly. We are going to treat it as an OR + foreach ( $this->filter->get_StorageAreas() as $storage ) { + $string_to_eval = 'return $storage->disk_usage_percent() '.$this->op.' '.$this->val.';'; + try { + $ret = eval($string_to_eval); + Debug("Evalled $string_to_eval = $ret"); + if ( $ret ) + return true; + } catch ( Throwable $t ) { + Error('Failed evaluating '.$string_to_eval); + return false; + } + } # end foreach Storage Area + } else if ( $this->attr == 'SystemLoad' ) { + $string_to_eval = 'return getLoad() '.$this->op.' '.$this->val.';'; + try { + $ret = eval($string_to_eval); + Debug("Evaled $string_to_eval = $ret"); + if ( $ret ) + return true; + } catch ( Throwable $t ) { + Error('Failed evaluating '.$string_to_eval); + return false; + } + } else { + Error('testing unsupported pre term ' . $this->attr); + } + } else { + # Is a Post Condition + if ( $this->attr == 'ExistsInFileSystem' ) { + if ( + ($this->op == 'IS' and $this->val == 'True') + or + ($this->op == 'IS NOT' and $this->val == 'False') + ) { + return file_exists($event->Path()); + } else { + return !file_exists($event->Path()); + } + } else if ( $this->attr == 'DiskPercent' ) { + $string_to_eval = 'return $event->Storage()->disk_usage_percent() '.$this->op.' '.$this->val.';'; + try { + $ret = eval($string_to_eval); + Debug("Evalled $string_to_eval = $ret"); + if ( $ret ) + return true; + } catch ( Throwable $t ) { + Error('Failed evaluating '.$string_to_eval); + return false; + } + } else if ( $this->attr == 'DiskBlocks' ) { + $string_to_eval = 'return $event->Storage()->disk_usage_blocks() '.$this->op.' '.$this->val.';'; + try { + $ret = eval($string_to_eval); + Debug("Evalled $string_to_eval = $ret"); + if ( $ret ) + return true; + } catch ( Throwable $t ) { + Error('Failed evaluating '.$string_to_eval); + return false; + } + } else { + Error('testing unsupported post term ' . $this->attr); + } + } + return false; + } + + public function is_pre_sql() { + if ( $this->attr == 'DiskPercent' ) + return true; + if ( $this->attr == 'DiskBlocks' ) + return true; + return false; } - return $data; -} + public function is_post_sql() { + if ( $this->attr == 'ExistsInFileSystem' ) { + return true; + } + return false; + } + + public static function is_valid_attr($attr) { + $attrs = array( + 'Score', + 'Delta', + 'TimeStamp', + 'Type', + 'FrameId', + 'EventId', + 'ExistsInFileSystem', + 'Emailed', + 'DiskSpace', + 'DiskPercent', + 'DiskBlocks', + 'MonitorName', + 'ServerId', + 'MonitorServerId', + 'StorageServerId', + 'FilterServerId', + 'DateTime', + 'Date', + 'Time', + 'Weekday', + 'StartDateTime', + 'FramesId', + 'FramesEventId', + 'StartDate', + 'StartTime', + 'StartWeekday', + 'EndDateTime', + 'EndDate', + 'EndTime', + 'EndWeekday', + 'Id', + 'Name', + 'MonitorId', + 'StorageId', + 'SecondaryStorageId', + 'Length', + 'Frames', + 'AlarmFrames', + 'TotScore', + 'AvgScore', + 'MaxScore', + 'Cause', + 'Notes', + 'StateId', + 'Archived' + ); + return in_array($attr, $attrs); + } +} # end class FilterTerm + +?> diff --git a/web/includes/FilterTerm.php b/web/includes/FilterTerm.php index 6b41a2e1d..42f939128 100644 --- a/web/includes/FilterTerm.php +++ b/web/includes/FilterTerm.php @@ -237,6 +237,15 @@ class FilterTerm { case 'StartDateTime': $sql .= 'E.StartDateTime'; break; + case 'FrameId': + $sql .= 'Id'; + break; + case 'Type': + case 'TimeStamp': + case 'Delta': + case 'Score': + $sql .= $this->attr; + break; case 'FramesEventId': $sql .= 'F.EventId'; break; @@ -419,6 +428,12 @@ class FilterTerm { public static function is_valid_attr($attr) { $attrs = array( + 'Score', + 'Delta', + 'TimeStamp', + 'Type', + 'FrameId', + 'EventId', 'ExistsInFileSystem', 'Emailed', 'DiskSpace', @@ -434,6 +449,7 @@ class FilterTerm { 'Time', 'Weekday', 'StartDateTime', + 'FramesId', 'FramesEventId', 'StartDate', 'StartTime', From a2b5271835654c559850214b12ac0c9f6892de6f Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 14 Nov 2020 17:34:59 -0600 Subject: [PATCH 0653/2339] fix copy/paste typo --- web/ajax/frames.php | 638 ++++++++++++-------------------------------- 1 file changed, 173 insertions(+), 465 deletions(-) diff --git a/web/ajax/frames.php b/web/ajax/frames.php index 42f939128..e85988dbc 100644 --- a/web/ajax/frames.php +++ b/web/ajax/frames.php @@ -1,481 +1,189 @@ translate('ConjAnd'), - 'or' => translate('ConjOr') - ); - } - return $validConjunctionTypes; +if ( !canView('Events') ) $message = 'Insufficient permissions to view frames for user '.$user['Username']; + +// task must be set +if ( empty($_REQUEST['task']) ) { + $message = 'This request requires a task to be set'; +// query is the only supported task at the moment +} else if ( $_REQUEST['task'] != 'query' ) { + $message = 'Unrecognised task '.$_REQUEST['task']; + } else { + $task = $_REQUEST['task']; } +if ( empty($_REQUEST['eid']) ) { + $message = 'No event id supplied'; +} else { + $eid = validInt($_REQUEST['eid']); +} -class FilterTerm { - public $filter; - public $index; - public $attr; - public $op; - public $val; - public $values; - public $cnj; - public $obr; - public $cbr; +if ( $message ) { + ajaxError($message); + return; +} +// Search contains a user entered string to search on +$search = isset($_REQUEST['search']) ? $_REQUEST['search'] : ''; - public function __construct($filter = null, $term = NULL, $index=0) { - $this->filter = $filter; - $validConjunctionTypes = getFilterQueryConjunctionTypes(); +// Advanced search contains an array of "column name" => "search text" pairs +// Bootstrap table sends json_ecoded array, which we must decode +$advsearch = isset($_REQUEST['advsearch']) ? json_decode($_REQUEST['advsearch'], JSON_OBJECT_AS_ARRAY) : array(); - $this->index = $index; - $this->attr = $term['attr']; - $this->op = $term['op']; - $this->val = $term['val']; - if ( isset($term['cnj']) ) { - if ( array_key_exists($term['cnj'], $validConjunctionTypes) ) { - $this->cnj = $term['cnj']; - } else { - Warning('Invalid cnj ' . $term['cnj'].' in '.print_r($term, true)); - } - } +// Sort specifies the name of the column to sort on +$sort = 'FrameId'; +if ( isset($_REQUEST['sort']) ) { + $sort = $_REQUEST['sort']; +} - if ( isset($term['obr']) ) { - if ( (string)(int)$term['obr'] == $term['obr'] ) { - $this->obr = $term['obr']; - } else { - Warning('Invalid obr ' . $term['obr'] . ' in ' . print_r($term, true)); - } - } - if ( isset($term['cbr']) ) { - if ( (string)(int)$term['cbr'] == $term['cbr'] ) { - $this->cbr = $term['cbr']; - } else { - Warning('Invalid cbr ' . $term['cbr'] . ' in ' . print_r($term, true)); - } - } - } # end function __construct - - # Returns an array of values. AS term->value can be a list, we will break it apart, remove quotes etc - public function sql_values() { - $values = array(); - if ( !isset($this->val) ) { - Logger::Warning('No value in term'.$this->attr); - return $values; - } - - $vals = is_array($this->val) ? $this->val : preg_split('/["\'\s]*?,["\'\s]*?/', preg_replace('/^["\']+?(.+)["\']+?$/', '$1', $this->val)); - foreach ( $vals as $value ) { - - switch ( $this->attr ) { - - case 'AlarmedZoneId': - $value = '(SELECT * FROM Stats WHERE EventId=E.Id AND ZoneId='.$value.')'; - break; - case 'ExistsInFileSystem': - $value = ''; - break; - case 'DiskPercent': - $value = ''; - break; - case 'MonitorName': - case 'MonitorName': - case 'Name': - case 'Cause': - case 'Notes': - if ( strstr($this->op, 'LIKE') and ! strstr($this->val, '%' ) ) { - $value = '%'.$value.'%'; - } - $value = dbEscape($value); - break; - case 'MonitorServerId': - case 'FilterServerId': - case 'StorageServerId': - case 'ServerId': - if ( $value == 'ZM_SERVER_ID' ) { - $value = ZM_SERVER_ID; - } else if ( $value == 'NULL' ) { - - } else { - $value = dbEscape($value); - } - break; - case 'StorageId': - if ( $value != 'NULL' ) { - $value = dbEscape($value); - } - break; - case 'DateTime': - case 'StartDateTime': - case 'EndDateTime': - if ( $value != 'NULL' ) - $value = '\''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\''; - break; - case 'Date': - case 'StartDate': - case 'EndDate': - if ( $value == 'CURDATE()' or $value == 'NOW()' ) { - $value = 'to_days('.$value.')'; - } else if ( $value != 'NULL' ) { - $value = 'to_days(\''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\')'; - } - break; - case 'Time': - case 'StartTime': - case 'EndTime': - if ( $value != 'NULL' ) - $value = 'extract(hour_second from \''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\')'; - break; - default : - if ( $value == 'Odd' ) { - $value = 1; - } else if ( $value == 'Even' ) { - $value = 0; - } else if ( $value != 'NULL' ) - $value = dbEscape($value); - break; - } - $values[] = $value; - } // end foreach value - return $values; - } # end function sql_values - - public function sql_operator() { - switch ( $this->attr ) { - case 'AlarmZoneId': - return ' EXISTS '; - case 'ExistsInFileSystem': - case 'DiskPercent': - return ''; - } - - - switch ( $this->op ) { - case '=' : - case '!=' : - case '>=' : - case '>' : - case '<' : - case '<=' : - case 'LIKE' : - case 'NOT LIKE': - return ' '.$this->op.' '; - case '=~' : - return ' regexp '; - case '!~' : - return ' not regexp '; - case '=[]' : - case 'IN' : - return ' IN '; - case '![]' : - return ' NOT IN '; - case 'EXISTS' : - return ' EXISTS '; - case 'IS' : - # Odd will be replaced with 1 - # Even will be replaced with 0 - if ( $this->val == 'Odd' or $this->val == 'Even' ) { - return ' % 2 = '; - } else { - return ' IS '; - } - case 'IS NOT' : - if ( $this->val == 'Odd' or $this->val == 'Even' ) { - return ' % 2 = '; - } - return ' IS NOT '; - default: - Warning('Invalid operator in filter: ' . print_r($this->op, true)); - } // end switch op - } # end public function sql_operator - - /* Some terms don't have related SQL */ - public function sql() { - - $sql = ''; - if ( isset($this->cnj) ) { - $sql .= ' '.$this->cnj.' '; - } - if ( isset($this->obr) ) { - $sql .= ' '.str_repeat('(', $this->obr).' '; - } - - switch ( $this->attr ) { - case 'ExistsInFileSystem': - case 'DiskPercent': - $sql .= 'TRUE /*'.$this->attr.'*/'; - break; - case 'MonitorName': - $sql .= 'M.Name'; - break; - case 'ServerId': - case 'MonitorServerId': - $sql .= 'M.ServerId'; - break; - case 'StorageServerId': - $sql .= 'S.ServerId'; - break; - case 'FilterServerId': - $sql .= ZM_SERVER_ID; - break; - # Unspecified start or end, so assume start, this is to support legacy filters - case 'DateTime': - $sql .= 'E.StartDateTime'; - break; - case 'Date': - $sql .= 'to_days(E.StartDateTime)'; - break; - case 'Time': - $sql .= 'extract(hour_second FROM E.StartDateTime)'; - break; - case 'Weekday': - $sql .= 'weekday(E.StartDateTime)'; - break; - # Starting Time - case 'StartDateTime': - $sql .= 'E.StartDateTime'; - break; - case 'FrameId': - $sql .= 'Id'; - break; - case 'Type': - case 'TimeStamp': - case 'Delta': - case 'Score': - $sql .= $this->attr; - break; - case 'FramesEventId': - $sql .= 'F.EventId'; - break; - case 'StartDate': - $sql .= 'to_days(E.StartDateTime)'; - break; - case 'StartTime': - $sql .= 'extract(hour_second FROM E.StartDateTime)'; - break; - case 'StartWeekday': - $sql .= 'weekday(E.StartDateTime)'; - break; - # Ending Time - case 'EndDateTime': - $sql .= 'E.EndDateTime'; - break; - case 'EndDate': - $sql .= 'to_days(E.EndDateTime)'; - break; - case 'EndTime': - $sql .= 'extract(hour_second FROM E.EndDateTime)'; - break; - case 'EndWeekday': - $sql .= 'weekday(E.EndDateTime)'; - break; - case 'Emailed': - case 'Id': - case 'Name': - case 'DiskSpace': - case 'MonitorId': - case 'StorageId': - case 'SecondaryStorageId': - case 'Length': - case 'Frames': - case 'AlarmFrames': - case 'TotScore': - case 'AvgScore': - case 'MaxScore': - case 'Cause': - case 'Notes': - case 'StateId': - case 'Archived': - $sql .= 'E.'.$this->attr; - } - $sql .= $this->sql_operator(); - $values = $this->sql_values(); - if ( (count($values) > 1) or ($this->op == 'IN') or ($this->op == 'NOT IN') ) { - $sql .= '('.join(',', $values).')'; - } else { - $sql .= $values[0]; - } - - if ( isset($this->cbr) ) { - $sql .= ' '.str_repeat(')', $this->cbr).' '; - } - return $sql; - } # end public function sql - - public function querystring($objectname='filter', $querySep='&') { - # We don't validate the term parameters here - $query = ''; - if ( $this->cnj ) - $query .= $querySep.urlencode($objectname.'[Query][terms]['.$this->index.'][cnj]').'='.$this->cnj; - if ( $this->obr ) - $query .= $querySep.urlencode($objectname.'[Query][terms]['.$this->index.'][obr]').'='.$this->obr; - - $query .= $querySep.urlencode($objectname.'[Query][terms]['.$this->index.'][attr]').'='.urlencode($this->attr); - $query .= $querySep.urlencode($objectname.'[Query][terms]['.$this->index.'][op]').'='.urlencode($this->op); - $query .= $querySep.urlencode($objectname.'[Query][terms]['.$this->index.'][val]').'='.urlencode($this->val); - if ( $this->cbr ) - $query .= $querySep.urlencode($objectname.'[Query][terms]['.$this->index.'][cbr]').'='.$this->cbr; - return $query; - } # end public function querystring - - public function hidden_fields() { - $html =''; - if ( $this->cnj ) - $html .= ''.PHP_EOL; - - if ( $this->obr ) - $html .= ''.PHP_EOL; - - # attr should have been already validation, so shouldn't need htmlspecialchars - $html .= ''.PHP_EOL; - $html .= ''.PHP_EOL; - $html .= ''.PHP_EOL; - if ( $this->cbr ) - $html .= ''.PHP_EOL; - - return $html; - } # end public function hiddens_fields - - public function test($event=null) { - if ( !isset($event) ) { - # Is a Pre Condition - Debug("Testing " . $this->attr); - if ( $this->attr == 'DiskPercent' ) { - # The logic on this is really ugly. We are going to treat it as an OR - foreach ( $this->filter->get_StorageAreas() as $storage ) { - $string_to_eval = 'return $storage->disk_usage_percent() '.$this->op.' '.$this->val.';'; - try { - $ret = eval($string_to_eval); - Debug("Evalled $string_to_eval = $ret"); - if ( $ret ) - return true; - } catch ( Throwable $t ) { - Error('Failed evaluating '.$string_to_eval); - return false; - } - } # end foreach Storage Area - } else if ( $this->attr == 'SystemLoad' ) { - $string_to_eval = 'return getLoad() '.$this->op.' '.$this->val.';'; - try { - $ret = eval($string_to_eval); - Debug("Evaled $string_to_eval = $ret"); - if ( $ret ) - return true; - } catch ( Throwable $t ) { - Error('Failed evaluating '.$string_to_eval); - return false; - } - } else { - Error('testing unsupported pre term ' . $this->attr); - } - } else { - # Is a Post Condition - if ( $this->attr == 'ExistsInFileSystem' ) { - if ( - ($this->op == 'IS' and $this->val == 'True') - or - ($this->op == 'IS NOT' and $this->val == 'False') - ) { - return file_exists($event->Path()); - } else { - return !file_exists($event->Path()); - } - } else if ( $this->attr == 'DiskPercent' ) { - $string_to_eval = 'return $event->Storage()->disk_usage_percent() '.$this->op.' '.$this->val.';'; - try { - $ret = eval($string_to_eval); - Debug("Evalled $string_to_eval = $ret"); - if ( $ret ) - return true; - } catch ( Throwable $t ) { - Error('Failed evaluating '.$string_to_eval); - return false; - } - } else if ( $this->attr == 'DiskBlocks' ) { - $string_to_eval = 'return $event->Storage()->disk_usage_blocks() '.$this->op.' '.$this->val.';'; - try { - $ret = eval($string_to_eval); - Debug("Evalled $string_to_eval = $ret"); - if ( $ret ) - return true; - } catch ( Throwable $t ) { - Error('Failed evaluating '.$string_to_eval); - return false; - } - } else { - Error('testing unsupported post term ' . $this->attr); - } - } - return false; +// Offset specifies the starting row to return, used for pagination +$offset = 0; +if ( isset($_REQUEST['offset']) ) { + if ( ( !is_int($_REQUEST['offset']) and !ctype_digit($_REQUEST['offset']) ) ) { + ZM\Error('Invalid value for offset: ' . $_REQUEST['offset']); + } else { + $offset = $_REQUEST['offset']; } - - public function is_pre_sql() { - if ( $this->attr == 'DiskPercent' ) - return true; - if ( $this->attr == 'DiskBlocks' ) - return true; - return false; +} + +// Order specifies the sort direction, either asc or desc +$order = (isset($_REQUEST['order']) and (strtolower($_REQUEST['order']) == 'asc')) ? 'ASC' : 'DESC'; + +// Limit specifies the number of rows to return +$limit = 0; +if ( isset($_REQUEST['limit']) ) { + if ( ( !is_int($_REQUEST['limit']) and !ctype_digit($_REQUEST['limit']) ) ) { + ZM\Error('Invalid value for limit: ' . $_REQUEST['limit']); + } else { + $limit = $_REQUEST['limit']; + } +} + +// +// MAIN LOOP +// + +// Only one supported task at the moment +switch ( $task ) { + case 'query' : + $data = queryRequest($eid, $search, $advsearch, $sort, $offset, $order, $limit); + break; + default : + ZM\Fatal("Unrecognised task '$task'"); +} // end switch task + +ajaxResponse($data); + +// +// FUNCTION DEFINITIONS +// + +function queryRequest($eid, $search, $advsearch, $sort, $offset, $order, $limit) { + + $data = array( + 'total' => 0, + 'totalNotFiltered' => 0, + 'rows' => array(), + 'updated' => preg_match('/%/', DATE_FMT_CONSOLE_LONG) ? strftime(DATE_FMT_CONSOLE_LONG) : date(DATE_FMT_CONSOLE_LONG) + ); + + // The names of the dB columns in the events table we are interested in + $columns = array('FrameId', 'Type', 'TimeStamp', 'Delta', 'Score'); + + if ( !in_array($sort, $columns) ) { + ZM\Error('Invalid sort field: ' . $sort); + $sort = 'FrameId'; } - public function is_post_sql() { - if ( $this->attr == 'ExistsInFileSystem' ) { - return true; + $Event = new ZM\Event($eid); + $Monitor = $Event->Monitor(); + $values = array(); + $likes = array(); + $where = 'WHERE EventId = '.$eid; + + $sql = 'SELECT * FROM `Frames` '.$where.' ORDER BY '.$sort.' '.$order; + + //ZM\Debug('Calling the following sql query: ' .$sql); + + $unfiltered_rows = array(); + $frame_ids = array(); + require_once('includes/Frame.php'); + foreach ( dbFetchAll($sql, NULL, $values) as $row ) { + $frame = new ZM\Frame($row); + $frame_ids[] = $frame->Id(); + $unfiltered_rows[] = $row; + } + + ZM\Debug('Have ' . count($unfiltered_rows) . ' frames matching base filter.'); + + $filtered_rows = null; + require_once('includes/Filter.php'); + if ( count($advsearch) or $search != '' ) { + $search_filter = new ZM\Filter(); + $search_filter = $search_filter->addTerm(array('cnj'=>'and', 'attr'=>'FrameId', 'op'=>'IN', 'val'=>$frame_ids)); + + // There are two search bars in the log view, normal and advanced + // Making an exuctive decision to ignore the normal search, when advanced search is in use + // Alternatively we could try to do both + if ( count($advsearch) ) { + $terms = array(); + foreach ( $advsearch as $col=>$text ) { + $terms[] = array('cnj'=>'and', 'attr'=>$col, 'op'=>'LIKE', 'val'=>$text); + } # end foreach col in advsearch + $terms[0]['obr'] = 1; + $terms[count($terms)-1]['cbr'] = 1; + $search_filter->addTerms($terms); + } else if ( $search != '' ) { + $search = '%' .$search. '%'; + $terms = array(); + foreach ( $columns as $col ) { + $terms[] = array('cnj'=>'or', 'attr'=>$col, 'op'=>'LIKE', 'val'=>$search); + } + $terms[0]['obr'] = 1; + $terms[0]['cnj'] = 'and'; + $terms[count($terms)-1]['cbr'] = 1; + $search_filter = $search_filter->addTerms($terms, array('obr'=>1, 'cbr'=>1, 'op'=>'OR')); + } # end if search + + $sql = 'SELECT * FROM `Frames` WHERE '.$search_filter->sql().' ORDER BY ' .$sort. ' ' .$order; + $filtered_rows = dbFetchAll($sql); + ZM\Debug('Have ' . count($filtered_rows) . ' frames matching search filter.'); + } else { + $filtered_rows = $unfiltered_rows; + } # end if search_filter->terms() > 1 + + $returned_rows = array(); + foreach ( array_slice($filtered_rows, $offset, $limit) as $row ) { + if ( ZM_WEB_LIST_THUMBS ) { + $base_img_src = '?view=image&fid=' .$row['Id']; + $ratio_factor = $Monitor->ViewHeight() / $Monitor->ViewWidth(); + $thmb_width = ZM_WEB_LIST_THUMB_WIDTH ? 'width='.ZM_WEB_LIST_THUMB_WIDTH : ''; + $thmb_height = 'height="'.( ZM_WEB_LIST_THUMB_HEIGHT ? ZM_WEB_LIST_THUMB_HEIGHT : ZM_WEB_LIST_THUMB_WIDTH*$ratio_factor ) .'"'; + $thmb_fn = 'filename=' .$Event->MonitorId(). '_' .$row['EventId']. '_' .$row['FrameId']. '.jpg'; + $img_src = join('&', array_filter(array($base_img_src, $thmb_width, $thmb_height, $thmb_fn))); + $full_img_src = join('&', array_filter(array($base_img_src, $thmb_fn))); + $frame_src = '?view=frame&eid=' .$row['EventId']. '&fid=' .$row['FrameId']; + + $row['Thumbnail'] = ''; } - return false; + $returned_rows[] = $row; + } # end foreach row matching search + + $data['rows'] = $returned_rows; + + # totalNotFiltered must equal total, except when either search bar has been used + $data['totalNotFiltered'] = count($unfiltered_rows); + if ( $search != '' || count($advsearch) ) { + $data['total'] = count($filtered_rows); + } else { + $data['total'] = $data['totalNotFiltered']; } - public static function is_valid_attr($attr) { - $attrs = array( - 'Score', - 'Delta', - 'TimeStamp', - 'Type', - 'FrameId', - 'EventId', - 'ExistsInFileSystem', - 'Emailed', - 'DiskSpace', - 'DiskPercent', - 'DiskBlocks', - 'MonitorName', - 'ServerId', - 'MonitorServerId', - 'StorageServerId', - 'FilterServerId', - 'DateTime', - 'Date', - 'Time', - 'Weekday', - 'StartDateTime', - 'FramesId', - 'FramesEventId', - 'StartDate', - 'StartTime', - 'StartWeekday', - 'EndDateTime', - 'EndDate', - 'EndTime', - 'EndWeekday', - 'Id', - 'Name', - 'MonitorId', - 'StorageId', - 'SecondaryStorageId', - 'Length', - 'Frames', - 'AlarmFrames', - 'TotScore', - 'AvgScore', - 'MaxScore', - 'Cause', - 'Notes', - 'StateId', - 'Archived' - ); - return in_array($attr, $attrs); - } -} # end class FilterTerm - -?> + return $data; +} From a47b72af49a2a1d8299b5f9f5b082c4a96b7de40 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 16 Nov 2020 11:31:36 -0500 Subject: [PATCH 0654/2339] Fixes recovering frames from jpegs. Use Time::HiRes stat to get microseconds. --- scripts/ZoneMinder/lib/ZoneMinder/Event.pm | 32 +++++++++++++--------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm index 2664830dd..49c2e47f3 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm @@ -41,7 +41,7 @@ require Number::Bytes::Human; require Date::Parse; require POSIX; use Date::Format qw(time2str); -use Time::HiRes qw(gettimeofday tv_interval); +use Time::HiRes qw(gettimeofday tv_interval stat); #our @ISA = qw(ZoneMinder::Object); use parent qw(ZoneMinder::Object); @@ -791,44 +791,50 @@ sub recover_timestamps { return; } my @contents = readdir(DIR); - Debug('Have ' . @contents . " files in $path"); + Debug('Have ' . @contents . ' files in '.$path); closedir(DIR); - my @mp4_files = grep( /^\d+\-video\.mp4$/, @contents); + my @mp4_files = grep(/^\d+\-video\.mp4$/, @contents); if ( @mp4_files ) { $$Event{DefaultVideo} = $mp4_files[0]; } - my @analyse_jpgs = grep( /^\d+\-analyse\.jpg$/, @contents); + my @analyse_jpgs = grep(/^\d+\-analyse\.jpg$/, @contents); if ( @analyse_jpgs ) { - $$Event{Save_JPEGs} |= 2; + $$Event{SaveJPEGs} |= 2; } - my @capture_jpgs = grep( /^\d+\-capture\.jpg$/, @contents); + my @capture_jpgs = grep(/^\d+\-capture\.jpg$/, @contents); if ( @capture_jpgs ) { $$Event{Frames} = scalar @capture_jpgs; - $$Event{Save_JPEGs} |= 1; + $$Event{SaveJPEGs} |= 1; # can get start and end times from stat'ing first and last jpg @capture_jpgs = sort { $a cmp $b } @capture_jpgs; my $first_file = "$path/$capture_jpgs[0]"; ( $first_file ) = $first_file =~ /^(.*)$/; my $first_timestamp = (stat($first_file))[9]; - my $last_file = "$path/$capture_jpgs[@capture_jpgs-1]"; + my $last_file = $path.'/'.$capture_jpgs[@capture_jpgs-1]; ( $last_file ) = $last_file =~ /^(.*)$/; my $last_timestamp = (stat($last_file))[9]; my $duration = $last_timestamp - $first_timestamp; $Event->Length($duration); $Event->StartDateTime( Date::Format::time2str('%Y-%m-%d %H:%M:%S', $first_timestamp) ); + if ( $Event->Scheme() eq 'Deep' and $Event->RelativePath(undef) and ($path ne $Event->Path(undef)) ) { + my ( $year, $month, $day, $hour, $minute, $second ) = + ($path =~ /(\d{2})\/(\d{2})\/(\d{2})\/(\d{2})\/(\d{2})\/(\d{2})$/); + Error("Updating starttime to $path $year/$month/$day $hour:$minute:$second"); + $Event->StartDateTime(sprintf('%.4d-%.2d-%.2d %.2d:%.2d:%.2d', 2000+$year, $month, $day, $hour, $minute, $second)); + } $Event->EndDateTime( Date::Format::time2str('%Y-%m-%d %H:%M:%S', $last_timestamp) ); Debug("From capture Jpegs have duration $duration = $last_timestamp - $first_timestamp : $$Event{StartDateTime} to $$Event{EndDateTime}"); $ZoneMinder::Database::dbh->begin_work(); foreach my $jpg ( @capture_jpgs ) { my ( $id ) = $jpg =~ /^(\d+)\-capture\.jpg$/; - if ( ! ZoneMinder::Frame->find_one( EventId=>$$Event{Id}, FrameId=>$id ) ) { - my $file = "$path/$jpg"; + if ( ! ZoneMinder::Frame->find_one(EventId=>$$Event{Id}, FrameId=>$id) ) { + my $file = $path.'/'.$jpg; ( $file ) = $file =~ /^(.*)$/; my $timestamp = (stat($file))[9]; my $Frame = new ZoneMinder::Frame(); @@ -839,11 +845,11 @@ sub recover_timestamps { Type=>'Normal', Score=>0, }); - } - } + } # end if Frame not found + } # end foreach capture jpg $ZoneMinder::Database::dbh->commit(); } elsif ( @mp4_files ) { - my $file = "$path/$mp4_files[0]"; + my $file = $path.'/'.$mp4_files[0]; ( $file ) = $file =~ /^(.*)$/; my $first_timestamp = (stat($file))[9]; From 5bf5d58ac125f14f28f22725bbfd951229b91806 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 16 Nov 2020 11:31:36 -0500 Subject: [PATCH 0655/2339] Fixes recovering frames from jpegs. Use Time::HiRes stat to get microseconds. --- scripts/ZoneMinder/lib/ZoneMinder/Event.pm | 32 +++++++++++++--------- web/api/app/Plugin/Crud | 2 +- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm index 589e4bbba..f2c7ea210 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm @@ -41,7 +41,7 @@ require Number::Bytes::Human; require Date::Parse; require POSIX; use Date::Format qw(time2str); -use Time::HiRes qw(gettimeofday tv_interval); +use Time::HiRes qw(gettimeofday tv_interval stat); #our @ISA = qw(ZoneMinder::Object); use parent qw(ZoneMinder::Object); @@ -765,44 +765,50 @@ sub recover_timestamps { return; } my @contents = readdir(DIR); - Debug('Have ' . @contents . " files in $path"); + Debug('Have ' . @contents . ' files in '.$path); closedir(DIR); - my @mp4_files = grep( /^\d+\-video\.mp4$/, @contents); + my @mp4_files = grep(/^\d+\-video\.mp4$/, @contents); if ( @mp4_files ) { $$Event{DefaultVideo} = $mp4_files[0]; } - my @analyse_jpgs = grep( /^\d+\-analyse\.jpg$/, @contents); + my @analyse_jpgs = grep(/^\d+\-analyse\.jpg$/, @contents); if ( @analyse_jpgs ) { - $$Event{Save_JPEGs} |= 2; + $$Event{SaveJPEGs} |= 2; } - my @capture_jpgs = grep( /^\d+\-capture\.jpg$/, @contents); + my @capture_jpgs = grep(/^\d+\-capture\.jpg$/, @contents); if ( @capture_jpgs ) { $$Event{Frames} = scalar @capture_jpgs; - $$Event{Save_JPEGs} |= 1; + $$Event{SaveJPEGs} |= 1; # can get start and end times from stat'ing first and last jpg @capture_jpgs = sort { $a cmp $b } @capture_jpgs; my $first_file = "$path/$capture_jpgs[0]"; ( $first_file ) = $first_file =~ /^(.*)$/; my $first_timestamp = (stat($first_file))[9]; - my $last_file = "$path/$capture_jpgs[@capture_jpgs-1]"; + my $last_file = $path.'/'.$capture_jpgs[@capture_jpgs-1]; ( $last_file ) = $last_file =~ /^(.*)$/; my $last_timestamp = (stat($last_file))[9]; my $duration = $last_timestamp - $first_timestamp; $Event->Length($duration); $Event->StartTime( Date::Format::time2str('%Y-%m-%d %H:%M:%S', $first_timestamp) ); + if ( $Event->Scheme() eq 'Deep' and $Event->RelativePath(undef) and ($path ne $Event->Path(undef)) ) { + my ( $year, $month, $day, $hour, $minute, $second ) = + ($path =~ /(\d{2})\/(\d{2})\/(\d{2})\/(\d{2})\/(\d{2})\/(\d{2})$/); + Error("Updating starttime to $path $year/$month/$day $hour:$minute:$second"); + $Event->StartTime(sprintf('%.4d-%.2d-%.2d %.2d:%.2d:%.2d', 2000+$year, $month, $day, $hour, $minute, $second)); + } $Event->EndTime( Date::Format::time2str('%Y-%m-%d %H:%M:%S', $last_timestamp) ); Debug("From capture Jpegs have duration $duration = $last_timestamp - $first_timestamp : $$Event{StartTime} to $$Event{EndTime}"); $ZoneMinder::Database::dbh->begin_work(); foreach my $jpg ( @capture_jpgs ) { my ( $id ) = $jpg =~ /^(\d+)\-capture\.jpg$/; - if ( ! ZoneMinder::Frame->find_one( EventId=>$$Event{Id}, FrameId=>$id ) ) { - my $file = "$path/$jpg"; + if ( ! ZoneMinder::Frame->find_one(EventId=>$$Event{Id}, FrameId=>$id) ) { + my $file = $path.'/'.$jpg; ( $file ) = $file =~ /^(.*)$/; my $timestamp = (stat($file))[9]; my $Frame = new ZoneMinder::Frame(); @@ -813,11 +819,11 @@ sub recover_timestamps { Type=>'Normal', Score=>0, }); - } - } + } # end if Frame not found + } # end foreach capture jpg $ZoneMinder::Database::dbh->commit(); } elsif ( @mp4_files ) { - my $file = "$path/$mp4_files[0]"; + my $file = $path.'/'.$mp4_files[0]; ( $file ) = $file =~ /^(.*)$/; my $first_timestamp = (stat($file))[9]; diff --git a/web/api/app/Plugin/Crud b/web/api/app/Plugin/Crud index 0bd63fb46..2ab7e23fb 160000 --- a/web/api/app/Plugin/Crud +++ b/web/api/app/Plugin/Crud @@ -1 +1 @@ -Subproject commit 0bd63fb464957080ead342db58ca9e01532cf1ef +Subproject commit 2ab7e23fb4f5b31a2f043ba9b9f607a518007f75 From d5295a4464df788f95521bd44876067682e962f3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 17 Nov 2020 11:08:11 -0500 Subject: [PATCH 0656/2339] Fix segfaults and valgrind complaints. Initialize vncClientData, handle failure to connect freeing our client. --- src/zm_libvnc_camera.cpp | 90 ++++++++++++++++++++++++---------------- src/zm_libvnc_camera.h | 7 +--- 2 files changed, 56 insertions(+), 41 deletions(-) diff --git a/src/zm_libvnc_camera.cpp b/src/zm_libvnc_camera.cpp index 315cc19dd..f7a3c05ec 100644 --- a/src/zm_libvnc_camera.cpp +++ b/src/zm_libvnc_camera.cpp @@ -40,10 +40,14 @@ void bind_libvnc_symbols() { static void GotFrameBufferUpdateCallback(rfbClient *rfb, int x, int y, int w, int h){ VncPrivateData *data = (VncPrivateData *)(*rfbClientGetClientData_f)(rfb, &TAG_0); data->buffer = rfb->frameBuffer; + Debug(1, "GotFrameBufferUpdateallback x:%d y:%d w%d h:%d width: %d, height: %d", + x,y,w,h, rfb->width, rfb->height); } static char* GetPasswordCallback(rfbClient* cl){ - return strdup((const char *)(*rfbClientGetClientData_f)(cl, &TAG_1)); + Debug(1, "Getcredentials: %s", (*rfbClientGetClientData_f)(cl, &TAG_1)); + return strdup( + (const char *)(*rfbClientGetClientData_f)(cl, &TAG_1)); } static rfbCredential* GetCredentialsCallback(rfbClient* cl, int credentialType){ @@ -53,6 +57,7 @@ static rfbCredential* GetCredentialsCallback(rfbClient* cl, int credentialType){ return nullptr; } + Debug(1, "Getcredentials: %s:%s", (*rfbClientGetClientData_f)(cl, &TAG_1), (*rfbClientGetClientData_f)(cl, &TAG_2)); c->userCredential.password = strdup((const char *)(*rfbClientGetClientData_f)(cl, &TAG_1)); c->userCredential.username = strdup((const char *)(*rfbClientGetClientData_f)(cl, &TAG_2)); return c; @@ -87,6 +92,7 @@ VncCamera::VncCamera( p_capture, p_record_audio ), + mRfb(nullptr), mHost(host), mPort(port), mUser(user), @@ -110,52 +116,61 @@ VncCamera::VncCamera( Panic("Unexpected colours: %d", colours); } - if ( capture ) - Initialise(); -} + if ( capture ) { + Debug(3, "Initializing Client"); + bind_libvnc_symbols(); + scale.init(); + } +} VncCamera::~VncCamera() { - if ( capture ) - Terminate(); -} - -void VncCamera::Initialise() { - Debug(2, "Initializing Client"); - bind_libvnc_symbols(); - mRfb = (*rfbGetClient_f)(8, 3, 4); - - (*rfbClientSetClientData_f)(mRfb, &TAG_0, &mVncData); - (*rfbClientSetClientData_f)(mRfb, &TAG_1, (void *)mPass.c_str()); - (*rfbClientSetClientData_f)(mRfb, &TAG_2, (void *)mUser.c_str()); - - mRfb->GotFrameBufferUpdate = GotFrameBufferUpdateCallback; - mRfb->GetPassword = GetPasswordCallback; - mRfb->GetCredential = GetCredentialsCallback; - - mRfb->programName = "Zoneminder VNC Monitor"; - mRfb->serverHost = strdup(mHost.c_str()); - mRfb->serverPort = atoi(mPort.c_str()); - scale.init(); -} - -void VncCamera::Terminate() { - if ( mRfb->frameBuffer ) - free(mRfb->frameBuffer); - (*rfbClientCleanup_f)(mRfb); - return; + if ( capture ) { + if ( mRfb->frameBuffer ) + free(mRfb->frameBuffer); + (*rfbClientCleanup_f)(mRfb); + } } int VncCamera::PrimeCapture() { Debug(1, "Priming capture from %s", mHost.c_str()); + + if ( ! mRfb ) { + mVncData.buffer = nullptr; + mVncData.width = 0; + mVncData.height = 0; + + mRfb = (*rfbGetClient_f)(8 /* bits per sample */, 3 /* samples per pixel */, 4 /* bytes Per Pixel */); + mRfb->frameBuffer = (uint8_t *)av_malloc(8*4*width*height); + mRfb->canHandleNewFBSize = false; + + (*rfbClientSetClientData_f)(mRfb, &TAG_0, &mVncData); + (*rfbClientSetClientData_f)(mRfb, &TAG_1, (void *)mPass.c_str()); + (*rfbClientSetClientData_f)(mRfb, &TAG_2, (void *)mUser.c_str()); + + mRfb->GotFrameBufferUpdate = GotFrameBufferUpdateCallback; + mRfb->GetPassword = GetPasswordCallback; + mRfb->GetCredential = GetCredentialsCallback; + + mRfb->programName = "Zoneminder VNC Monitor"; + mRfb->serverHost = strdup(mHost.c_str()); + mRfb->serverPort = atoi(mPort.c_str()); + } if ( ! (*rfbInitClient_f)(mRfb, 0, nullptr) ) { + /* IF rfbInitClient fails, it calls rdbClientCleanup which will free mRfb */ + Warning("Failed to Priming capture from %s", mHost.c_str()); + mRfb = nullptr; return -1; } + if ( (mRfb->width != width) or (mRfb->height != height) ) { + Warning("Specified dimensions do not match screen size monitor: (%dx%d) != vnc: (%dx%d)", + width, height, mRfb->width, mRfb->height); + } + return 0; } int VncCamera::PreCapture() { - Debug(2, "PreCapture"); int rc = (*WaitForMessage_f)(mRfb, 500); if ( rc < 0 ) { return -1; @@ -163,13 +178,16 @@ int VncCamera::PreCapture() { return rc; } rfbBool res = (*HandleRFBServerMessage_f)(mRfb); + Debug(3, "PreCapture rc from HandleMessage %d", res == TRUE ? 1 : -1); return res == TRUE ? 1 : -1; } int VncCamera::Capture(Image &image) { - Debug(2, "Capturing"); + if ( ! mVncData.buffer ) { + return 0; + } uint8_t *directbuffer = image.WriteBuffer(width, height, colours, subpixelorder); - scale.Convert( + int rc = scale.Convert( mVncData.buffer, mRfb->si.framebufferHeight * mRfb->si.framebufferWidth * 4, directbuffer, @@ -180,7 +198,7 @@ int VncCamera::Capture(Image &image) { mRfb->si.framebufferHeight, width, height); - return 1; + return rc == 0 ? 1 : rc; } int VncCamera::PostCapture() { diff --git a/src/zm_libvnc_camera.h b/src/zm_libvnc_camera.h index 250cfaa2e..8ffa0d9eb 100644 --- a/src/zm_libvnc_camera.h +++ b/src/zm_libvnc_camera.h @@ -9,9 +9,9 @@ #if HAVE_LIBVNC #include + // Used by vnc callbacks -struct VncPrivateData -{ +struct VncPrivateData { uint8_t *buffer; uint8_t width; uint8_t height; @@ -47,9 +47,6 @@ public: ~VncCamera(); - void Initialise(); - void Terminate(); - int PreCapture(); int PrimeCapture(); int Capture( Image &image ); From 65420723349d08e4ada31968b5f53b4c354039df Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 18 Nov 2020 09:56:13 -0500 Subject: [PATCH 0657/2339] fix logic causing segfault instead of waiting for zmc. Remove trailing whitespaces --- src/zm_monitor.cpp | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 01779eed7..e29036e4c 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -425,8 +425,6 @@ Monitor::Monitor( else event_close_mode = CLOSE_IDLE; - Debug(1, "monitor purpose=%d", purpose); - mem_size = sizeof(SharedData) + sizeof(TriggerData) + sizeof(VideoStoreData) //Information to pass back to the capture process @@ -491,21 +489,19 @@ Monitor::Monitor( video_store_data->size = sizeof(VideoStoreData); //video_store_data->frameNumber = 0; } else if ( purpose == ANALYSIS ) { - while ( - (!zm_terminate) - and + while ( ( !(this->connect() and shared_data->valid) ) - and + or ( shared_data->last_write_index == (unsigned int)image_buffer_count ) - and + or ( shared_data->last_write_time == 0 ) ) { - Debug(1, "blah"); Debug(1, "Waiting for capture daemon shared_data(%d) last_write_index(%d), last_write_time(%d)", (shared_data ? 1:0), (shared_data ? shared_data->last_write_index : 0), (shared_data ? shared_data->last_write_time : 0)); - usleep(100000); + sleep(1); + if ( zm_terminate ) break; } ref_image.Assign(width, height, camera->Colours(), camera->SubpixelOrder(), @@ -666,7 +662,7 @@ bool Monitor::connect() { images = new Image *[pre_event_count]; last_signal = shared_data->signal; } // end if purpose == ANALYSIS -Debug(3, "Success connecting"); + Debug(3, "Success connecting"); return true; } // end Monitor::connect @@ -1480,7 +1476,7 @@ bool Monitor::Analyse() { } if ( last_motion_score ) { score += last_motion_score; - // cause is calculated every frame, + // cause is calculated every frame, //if ( !event ) { if ( cause.length() ) cause += ", "; @@ -1518,7 +1514,7 @@ bool Monitor::Analyse() { } // end foreach linked_monit if ( noteSet.size() > 0 ) noteSetMap[LINKED_CAUSE] = noteSet; - } // end if linked_monitors + } // end if linked_monitors //TODO: What happens is the event closes and sets recording to false then recording to true again so quickly that our capture daemon never picks it up. Maybe need a refresh flag? if ( function == RECORD || function == MOCORD ) { @@ -1527,7 +1523,7 @@ bool Monitor::Analyse() { if ( section_length && ( ( timestamp->tv_sec - video_store_data->recording.tv_sec ) >= section_length ) - && ( (function == MOCORD && (event_close_mode != CLOSE_TIME)) || ! ( timestamp->tv_sec % section_length ) ) + && ( (function == MOCORD && (event_close_mode != CLOSE_TIME)) || ! ( timestamp->tv_sec % section_length ) ) ) { Info("%s: %03d - Closing event %" PRIu64 ", section end forced %d - %d = %d >= %d", name, image_count, event->Id(), @@ -1572,7 +1568,7 @@ bool Monitor::Analyse() { } else if ( event ) { // This is so if we need more than 1 alarm frame before going into alarm, so it is basically if we have enough alarm frames Debug(3, "pre-alarm-count in event %d, event frames %d, alarm frames %d event length %d >=? %d min", - Event::PreAlarmCount(), event->Frames(), event->AlarmFrames(), + Event::PreAlarmCount(), event->Frames(), event->AlarmFrames(), ( timestamp->tv_sec - video_store_data->recording.tv_sec ), min_section_length ); } @@ -1600,7 +1596,7 @@ bool Monitor::Analyse() { // compute the index for pre event images in the dedicated buffer pre_index = pre_event_buffer_count ? image_count % pre_event_buffer_count : 0; Debug(3, "pre-index %d = image_count(%d) %% pre_event_buffer_count(%d)", - pre_index, image_count, pre_event_buffer_count); + pre_index, image_count, pre_event_buffer_count); // Seek forward the next filled slot in to the buffer (oldest data) // from the current position @@ -1610,7 +1606,7 @@ bool Monitor::Analyse() { pre_event_images--; } Debug(3, "pre-index %d, pre-event_images %d", - pre_index, pre_event_images); + pre_index, pre_event_images); event = new Event(this, *(pre_event_buffer[pre_index].timestamp), cause, noteSetMap); } else { @@ -1685,7 +1681,7 @@ bool Monitor::Analyse() { Info("%s: %03d - Gone into alert state", name, image_count); shared_data->state = state = ALERT; } else if ( state == ALERT ) { - if ( + if ( ( image_count-last_alarm_count > post_event_count ) && ( ( timestamp->tv_sec - video_store_data->recording.tv_sec ) >= min_section_length ) ) { @@ -1751,7 +1747,7 @@ bool Monitor::Analyse() { } } // end if config.record_event_stats } - } // end if savejpegs > 1 + } // end if savejpegs > 1 if ( event ) { if ( noteSetMap.size() > 0 ) @@ -1842,7 +1838,7 @@ void Monitor::Reload() { static char sql[ZM_SQL_MED_BUFSIZ]; // This seems to have fallen out of date. - snprintf(sql, sizeof(sql), + snprintf(sql, sizeof(sql), "SELECT `Function`+0, `Enabled`, `LinkedMonitors`, `EventPrefix`, `LabelFormat`, " "`LabelX`, `LabelY`, `LabelSize`, `WarmupCount`, `PreEventCount`, `PostEventCount`, " "`AlarmFrameCount`, `SectionLength`, `MinSectionLength`, `FrameSkip`, " @@ -2369,7 +2365,7 @@ Monitor *Monitor::Load(MYSQL_ROW dbrow, bool load_zones, Purpose purpose) { width, height, colours, - brightness, + brightness, contrast, hue, colour, From cf08010ebe520565bb0672b55146f176104974e3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 18 Nov 2020 13:04:56 -0500 Subject: [PATCH 0658/2339] Fix redirect on zone editing --- web/includes/actions/zone.php | 4 +++- web/skins/classic/views/zone.php | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/web/includes/actions/zone.php b/web/includes/actions/zone.php index 0b2809fcb..9515fc626 100644 --- a/web/includes/actions/zone.php +++ b/web/includes/actions/zone.php @@ -71,7 +71,9 @@ if ( !empty($_REQUEST['mid']) && canEdit('Monitors', $_REQUEST['mid']) ) { $monitor->sendControlCommand('quit'); } } // end if changes - $redirect = $_SERVER['HTTP_REFERER']; + # HTTP_REFERER will typically be ?view=zone so no good. + # if a referer is passed in $_REQUEST then use it otherwise go to ?view=zones + $redirect = isset($_REQUEST['REFERER']) ? $_REQUEST['REFERER'] : '?view=zones'; } // end if action } // end if $mid and canEdit($mid) ?> diff --git a/web/skins/classic/views/zone.php b/web/skins/classic/views/zone.php index cf03104c7..2c41a885c 100644 --- a/web/skins/classic/views/zone.php +++ b/web/skins/classic/views/zone.php @@ -131,6 +131,7 @@ xhtmlHeaders(__FILE__, translate('Zone'));
+ From d4253be69f620a44ab4f13583eb83b343c44d00c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 18 Nov 2020 13:15:07 -0500 Subject: [PATCH 0659/2339] Use proper C++ initializer for Config. Don't copy the sql string, just use it from whereever in ram it is. --- src/zm_config.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/zm_config.cpp b/src/zm_config.cpp index 015095472..9c91d7d96 100644 --- a/src/zm_config.cpp +++ b/src/zm_config.cpp @@ -324,10 +324,7 @@ const char *ConfigItem::StringValue() const { return cfg_value.string_value; } -Config::Config() { - n_items = 0; - items = 0; -} +Config::Config() : n_items(0), items(nullptr) { } Config::~Config() { if ( items ) { @@ -341,10 +338,7 @@ Config::~Config() { } 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, "SELECT `Name`, `Value`, `Type` FROM `Config` ORDER BY `Id`") ) { Error("Can't run query: %s", mysql_error(&dbconn)); exit(mysql_errno(&dbconn)); } @@ -362,10 +356,11 @@ void Config::Load() { } 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); + result = nullptr; } void Config::Assign() { From 74972be9b5b505b2bfd35e2d9e5ad3d286e73c0d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 18 Nov 2020 13:15:52 -0500 Subject: [PATCH 0660/2339] spacing, code style. Set row=nullptr to quiet valgrind --- src/zm_db.cpp | 44 +++++++++++++++++++++++++++++++++----------- src/zm_db.h | 4 ++-- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/src/zm_db.cpp b/src/zm_db.cpp index 37c3cd0f7..1f40b9790 100644 --- a/src/zm_db.cpp +++ b/src/zm_db.cpp @@ -40,38 +40,59 @@ bool zmDbConnect() { Error("Can't initialise database connection: %s", mysql_error(&dbconn)); return false; } + bool reconnect = 1; if ( mysql_options(&dbconn, MYSQL_OPT_RECONNECT, &reconnect) ) Error("Can't set database auto reconnect option: %s", mysql_error(&dbconn)); - if ( !staticConfig.DB_SSL_CA_CERT.empty() ) + + if ( !staticConfig.DB_SSL_CA_CERT.empty() ) { mysql_ssl_set(&dbconn, staticConfig.DB_SSL_CLIENT_KEY.c_str(), staticConfig.DB_SSL_CLIENT_CERT.c_str(), staticConfig.DB_SSL_CA_CERT.c_str(), nullptr, nullptr); + } + std::string::size_type colonIndex = staticConfig.DB_HOST.find(":"); if ( colonIndex == std::string::npos ) { - if ( !mysql_real_connect(&dbconn, staticConfig.DB_HOST.c_str(), staticConfig.DB_USER.c_str(), staticConfig.DB_PASS.c_str(), nullptr, 0, nullptr, 0) ) { - Error( "Can't connect to server: %s", mysql_error(&dbconn)); + if ( !mysql_real_connect( + &dbconn, + staticConfig.DB_HOST.c_str(), + staticConfig.DB_USER.c_str(), + staticConfig.DB_PASS.c_str(), + nullptr, 0, nullptr, 0) ) { + Error("Can't connect to server: %s", mysql_error(&dbconn)); return false; } } else { - std::string dbHost = staticConfig.DB_HOST.substr( 0, colonIndex ); - std::string dbPortOrSocket = staticConfig.DB_HOST.substr( colonIndex+1 ); + std::string dbHost = staticConfig.DB_HOST.substr(0, colonIndex); + std::string dbPortOrSocket = staticConfig.DB_HOST.substr(colonIndex+1); if ( dbPortOrSocket[0] == '/' ) { - if ( !mysql_real_connect(&dbconn, nullptr, staticConfig.DB_USER.c_str(), staticConfig.DB_PASS.c_str(), nullptr, 0, dbPortOrSocket.c_str(), 0) ) { + if ( !mysql_real_connect( + &dbconn, + nullptr, + staticConfig.DB_USER.c_str(), + staticConfig.DB_PASS.c_str(), + nullptr, 0, dbPortOrSocket.c_str(), 0) ) { Error("Can't connect to server: %s", mysql_error(&dbconn)); return false; } } else { - if ( !mysql_real_connect( &dbconn, dbHost.c_str(), staticConfig.DB_USER.c_str(), staticConfig.DB_PASS.c_str(), nullptr, atoi(dbPortOrSocket.c_str()), nullptr, 0 ) ) { - Error( "Can't connect to server: %s", mysql_error( &dbconn ) ); + if ( !mysql_real_connect( + &dbconn, + dbHost.c_str(), + staticConfig.DB_USER.c_str(), + staticConfig.DB_PASS.c_str(), + nullptr, + atoi(dbPortOrSocket.c_str()), + nullptr, 0) ) { + Error("Can't connect to server: %s", mysql_error(&dbconn)); return false; } } } - if ( mysql_select_db( &dbconn, staticConfig.DB_NAME.c_str() ) ) { - Error( "Can't select database: %s", mysql_error( &dbconn ) ); + if ( mysql_select_db(&dbconn, staticConfig.DB_NAME.c_str()) ) { + Error("Can't select database: %s", mysql_error(&dbconn)); return false; } zmDbConnected = true; @@ -140,7 +161,7 @@ MYSQL_RES *zmDbRow::fetch(const char *query) { } row = mysql_fetch_row(result_set); - if ( ! row ) { + if ( !row ) { mysql_free_result(result_set); result_set = nullptr; Error("Error getting row from query %s. Error is %s", query, mysql_error(&dbconn)); @@ -155,4 +176,5 @@ zmDbRow::~zmDbRow() { mysql_free_result(result_set); result_set = nullptr; } + row = nullptr; } diff --git a/src/zm_db.h b/src/zm_db.h index f9f168cd0..8c641b0c2 100644 --- a/src/zm_db.h +++ b/src/zm_db.h @@ -29,8 +29,8 @@ class zmDbRow { MYSQL_ROW row; public: zmDbRow() : result_set(nullptr), row(nullptr) { }; - MYSQL_RES *fetch( const char *query ); - zmDbRow( MYSQL_RES *, MYSQL_ROW *row ); + MYSQL_RES *fetch(const char *query); + zmDbRow(MYSQL_RES *, MYSQL_ROW *row); ~zmDbRow(); MYSQL_ROW mysql_row() const { return row; }; From ae4e2a1d5ef04541afb147726f8793bc7f8b76c5 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 19 Nov 2020 10:42:17 -0500 Subject: [PATCH 0661/2339] We were overwriting the privacy/inactive zone with a more general one. Slight memleak --- src/zm_zone.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/zm_zone.cpp b/src/zm_zone.cpp index 8ce486821..deb0b6ed1 100644 --- a/src/zm_zone.cpp +++ b/src/zm_zone.cpp @@ -911,14 +911,15 @@ int Zone::Load(Monitor *monitor, Zone **&zones) { zones[i] = new Zone(monitor, Id, Name, polygon); } else if ( atoi(dbrow[2]) == Zone::PRIVACY ) { zones[i] = new Zone(monitor, Id, Name, (Zone::ZoneType)Type, polygon); + } else { + zones[i] = new Zone( + monitor, Id, Name, (Zone::ZoneType)Type, polygon, AlarmRGB, + (Zone::CheckMethod)CheckMethod, MinPixelThreshold, MaxPixelThreshold, + MinAlarmPixels, MaxAlarmPixels, Coord( FilterX, FilterY ), + MinFilterPixels, MaxFilterPixels, + MinBlobPixels, MaxBlobPixels, MinBlobs, MaxBlobs, + OverloadFrames, ExtendAlarmFrames); } - zones[i] = new Zone( - monitor, Id, Name, (Zone::ZoneType)Type, polygon, AlarmRGB, - (Zone::CheckMethod)CheckMethod, MinPixelThreshold, MaxPixelThreshold, - MinAlarmPixels, MaxAlarmPixels, Coord( FilterX, FilterY ), - MinFilterPixels, MaxFilterPixels, - MinBlobPixels, MaxBlobPixels, MinBlobs, MaxBlobs, - OverloadFrames, ExtendAlarmFrames); } // end foreach row mysql_free_result(result); return n_zones; From 634a3dbe81bb06453c13bb476c918cfb2f6459e6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 19 Nov 2020 10:43:02 -0500 Subject: [PATCH 0662/2339] fix crashes/memleaks when waiting for a zmc process to start. Fix other memleaks --- src/zm_monitor.cpp | 49 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index e29036e4c..1636ff5e3 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -373,10 +373,10 @@ Monitor::Monitor( privacy_bitmask( nullptr ), event_delete_thread(nullptr) { - if (analysis_fps > 0.0) { - uint64_t usec = round(1000000*pre_event_count/analysis_fps); - video_buffer_duration.tv_sec = usec/1000000; - video_buffer_duration.tv_usec = usec % 1000000; + if ( analysis_fps > 0.0 ) { + uint64_t usec = round(1000000*pre_event_count/analysis_fps); + video_buffer_duration.tv_sec = usec/1000000; + video_buffer_duration.tv_usec = usec % 1000000; } strncpy(name, p_name, sizeof(name)-1); @@ -500,6 +500,7 @@ Monitor::Monitor( (shared_data ? 1:0), (shared_data ? shared_data->last_write_index : 0), (shared_data ? shared_data->last_write_time : 0)); + this->disconnect(); sleep(1); if ( zm_terminate ) break; } @@ -706,6 +707,35 @@ bool Monitor::disconnect() { return false; } #endif // ZM_MEM_MAPPED + if ( image_buffer ) { + for ( int i = 0; i < image_buffer_count; i++ ) { + delete image_buffer[i].image; + image_buffer[i].image = nullptr; + } + delete[] image_buffer; + image_buffer = nullptr; + } + if ( purpose == ANALYSIS ) { + if ( analysis_fps ) { + // Size of pre event buffer must be greater than pre_event_count + // if alarm_frame_count > 1, because in this case the buffer contains + // alarmed images that must be discarded when event is created + for ( int i = 0; i < pre_event_buffer_count; i++ ) { + delete pre_event_buffer[i].timestamp; + pre_event_buffer[i].timestamp = nullptr; + delete pre_event_buffer[i].image; + pre_event_buffer[i].image = nullptr; + } + delete[] pre_event_buffer; + pre_event_buffer = nullptr; + } // end if max_analysis_fps + + delete[] timestamps; + timestamps = nullptr; + delete[] images; + images = nullptr; + } // end if purpose == ANALYSIS + mem_ptr = nullptr; shared_data = nullptr; return true; @@ -1849,7 +1879,9 @@ void Monitor::Reload() { zmDbRow *row = zmDbFetchOne(sql); if ( !row ) { Error("Can't run query: %s", mysql_error(&dbconn)); - } else if ( MYSQL_ROW dbrow = row->mysql_row() ) { + return; + } + if ( MYSQL_ROW dbrow = row->mysql_row() ) { int index = 0; function = (Function)atoi(dbrow[index++]); enabled = atoi(dbrow[index++]); @@ -1900,8 +1932,8 @@ void Monitor::Reload() { ready_count = image_count+warmup_count; ReloadLinkedMonitors(p_linked_monitors); - delete row; } // end if row + delete row; ReloadZones(); } // end void Monitor::Reload() @@ -2030,6 +2062,7 @@ int Monitor::LoadMonitors(std::string sql, Monitor **&monitors, Purpose purpose) } if ( mysql_errno(&dbconn) ) { Error("Can't fetch row: %s", mysql_error(&dbconn)); + mysql_free_result(result); return 0; } mysql_free_result(result); @@ -2124,7 +2157,7 @@ Monitor *Monitor::Load(MYSQL_ROW dbrow, bool load_zones, Purpose purpose) { int format = atoi(dbrow[col]); col++; bool v4l_multi_buffer = config.v4l_multi_buffer; if ( dbrow[col] ) { - if (*dbrow[col] == '0' ) { + if ( *dbrow[col] == '0' ) { v4l_multi_buffer = false; } else if ( *dbrow[col] == '1' ) { v4l_multi_buffer = true; @@ -2442,7 +2475,7 @@ Monitor *Monitor::Load(unsigned int p_id, bool load_zones, Purpose purpose) { std::string sql = load_monitor_sql + stringtf(" WHERE `Id`=%d", p_id); zmDbRow dbrow; - if ( ! dbrow.fetch(sql.c_str()) ) { + if ( !dbrow.fetch(sql.c_str()) ) { Error("Can't use query result: %s", mysql_error(&dbconn)); return nullptr; } From 58ccea6aa80862ac32ef2f0f73e4d943dc11260d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 19 Nov 2020 16:37:28 -0500 Subject: [PATCH 0663/2339] use better c++ class initialisation. Use ZM_BUFTYPE_DONTFREE instead of 0 for init buffertype. --- src/zm_image.cpp | 50 ++++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/src/zm_image.cpp b/src/zm_image.cpp index b2707dd52..6848633ca 100644 --- a/src/zm_image.cpp +++ b/src/zm_image.cpp @@ -116,7 +116,7 @@ Image::Image() { size = 0; allocation = 0; buffer = 0; - buffertype = 0; + buffertype = ZM_BUFTYPE_DONTFREE; holdbuffer = 0; text[0] = '\0'; blend = fptr_blend; @@ -134,24 +134,26 @@ Image::Image(const char *filename) { size = 0; allocation = 0; buffer = 0; - buffertype = 0; + buffertype = ZM_BUFTYPE_DONTFREE; holdbuffer = 0; ReadJpeg(filename, ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB); text[0] = '\0'; update_function_pointers(); } -Image::Image(int p_width, int p_height, int p_colours, int p_subpixelorder, uint8_t *p_buffer, unsigned int p_padding) { +Image::Image(int p_width, int p_height, int p_colours, int p_subpixelorder, uint8_t *p_buffer, unsigned int p_padding) : + width(p_width), + height(p_height), + colours(p_colours), + padding(p_padding), + subpixelorder(p_subpixelorder), + buffer(p_buffer) { + if ( !initialised ) Initialise(); - width = p_width; - height = p_height; - pixels = width*height; - colours = p_colours; + pixels = width * height; linesize = p_width * p_colours; - padding = p_padding; - subpixelorder = p_subpixelorder; - size = linesize*height + padding; + size = linesize * height + padding; buffer = nullptr; holdbuffer = 0; if ( p_buffer ) { @@ -166,16 +168,18 @@ Image::Image(int p_width, int p_height, int p_colours, int p_subpixelorder, uint update_function_pointers(); } -Image::Image(int p_width, int p_linesize, int p_height, int p_colours, int p_subpixelorder, uint8_t *p_buffer, unsigned int p_padding) { +Image::Image(int p_width, int p_linesize, int p_height, int p_colours, int p_subpixelorder, uint8_t *p_buffer, unsigned int p_padding) : + width(p_width), + linesize(p_linesize), + height(p_height), + colours(p_colours), + padding(p_padding), + subpixelorder(p_subpixelorder), + buffer(p_buffer) +{ if ( !initialised ) Initialise(); - width = p_width; - linesize = p_linesize; - height = p_height; pixels = width*height; - colours = p_colours; - padding = p_padding; - subpixelorder = p_subpixelorder; size = linesize*height + padding; buffer = nullptr; holdbuffer = 0; @@ -651,7 +655,7 @@ void Image::Assign( return; } } else { - if ( new_size > allocation || !buffer ) { + if ( (new_size > allocation) || !buffer ) { DumpImgBuffer(); AllocImgBuffer(new_size); } @@ -886,8 +890,8 @@ bool Image::ReadJpeg(const char *filename, unsigned int p_colours, unsigned int jpeg_read_header(cinfo, TRUE); - if ( cinfo->num_components != 1 && cinfo->num_components != 3 ) { - Error( "Unexpected colours when reading jpeg image: %d", colours ); + if ( (cinfo->num_components != 1) && (cinfo->num_components != 3) ) { + Error("Unexpected colours when reading jpeg image: %d", colours); jpeg_abort_decompress(cinfo); fclose(infile); return false; @@ -902,7 +906,7 @@ bool Image::ReadJpeg(const char *filename, unsigned int p_colours, unsigned int new_width = cinfo->image_width; new_height = cinfo->image_height; - if ( width != new_width || height != new_height ) { + if ( (width != new_width) || (height != new_height) ) { Debug(9, "Image dimensions differ. Old: %ux%u New: %ux%u", width, height, new_width, new_height); } @@ -1106,7 +1110,7 @@ cinfo->out_color_space = JCS_EXT_RGB; #else cinfo->out_color_space = JCS_RGB; #endif - */ +*/ cinfo->in_color_space = JCS_RGB; } break; @@ -1197,7 +1201,7 @@ bool Image::DecodeJpeg( new_width = cinfo->image_width; new_height = cinfo->image_height; - if ( width != new_width || height != new_height ) { + if ( (width != new_width) || (height != new_height) ) { Debug(9, "Image dimensions differ. Old: %ux%u New: %ux%u", width, height, new_width, new_height); } From 3f1e7e793fe5b37b8e38d379f54c4638c9b3acc7 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 19 Nov 2020 16:38:49 -0500 Subject: [PATCH 0664/2339] update buffertype after DumpBUffer --- src/zm_image.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/zm_image.h b/src/zm_image.h index 3e07e41eb..a444f5e53 100644 --- a/src/zm_image.h +++ b/src/zm_image.h @@ -64,7 +64,7 @@ inline static uint8_t* AllocBuffer(size_t p_bufsize) { } inline static void DumpBuffer(uint8_t* buffer, int buffertype) { - if ( buffer && buffertype != ZM_BUFTYPE_DONTFREE ) { + if ( buffer && (buffertype != ZM_BUFTYPE_DONTFREE) ) { if ( buffertype == ZM_BUFTYPE_ZM ) { zm_freealigned(buffer); } else if ( buffertype == ZM_BUFTYPE_MALLOC ) { @@ -122,6 +122,7 @@ protected: inline void DumpImgBuffer() { DumpBuffer(buffer, buffertype); + buffertype = ZM_BUFTYPE_DONTFREE; buffer = nullptr; allocation = 0; } From 03f033cf367e93b5232b5a67f63b1adce411a60a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 19 Nov 2020 16:39:14 -0500 Subject: [PATCH 0665/2339] cleanup MOnitor destructor. Most of the freeing is done in disconnect now. Fixes zms crash --- src/zm_monitor.cpp | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 1636ff5e3..4ea7ffdfc 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -774,34 +774,20 @@ Monitor::~Monitor() { } } - if ( (deinterlacing & 0xff) == 4) { - delete next_buffer.image; - delete next_buffer.timestamp; - } - for ( int i = 0; i < image_buffer_count; i++ ) { - delete image_buffer[i].image; - } - delete[] image_buffer; - } // end if mem_ptr - - if ( mem_ptr ) { if ( purpose == ANALYSIS ) { shared_data->state = state = IDLE; shared_data->last_read_index = image_buffer_count; shared_data->last_read_time = 0; - if ( analysis_fps ) { - for ( int i = 0; i < pre_event_buffer_count; i++ ) { - delete pre_event_buffer[i].image; - delete pre_event_buffer[i].timestamp; - } - delete[] pre_event_buffer; - } if ( Event::PreAlarmCount() ) Event::EmptyPreAlarmFrames(); } else if ( purpose == CAPTURE ) { shared_data->valid = false; memset(mem_ptr, 0, mem_size); + if ( (deinterlacing & 0xff) == 4 ) { + delete next_buffer.image; + delete next_buffer.timestamp; + } } disconnect(); } // end if mem_ptr From 4f178e47bcde3e05b7eb646c0a27d13744c84214 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 19 Nov 2020 16:39:53 -0500 Subject: [PATCH 0666/2339] Break early after setting zm_terminate so that zms quits faster. Use a basic assignment instead of memcpy for last_frame_timestamp --- src/zm_monitorstream.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/zm_monitorstream.cpp b/src/zm_monitorstream.cpp index 58039b2bf..ea34f4d89 100644 --- a/src/zm_monitorstream.cpp +++ b/src/zm_monitorstream.cpp @@ -691,6 +691,7 @@ void MonitorStream::runStream() { if ( !sendFrame(snap->image, snap->timestamp) ) { Debug(2, "sendFrame failed, quiting."); zm_terminate = true; + break; } if ( frame_count == 0 ) { // Chrome will not display the first frame until it receives another. @@ -698,14 +699,18 @@ void MonitorStream::runStream() { if ( !sendFrame(snap->image, snap->timestamp) ) { Debug(2, "sendFrame failed, quiting."); zm_terminate = true; + break; } } // Perhaps we should use NOW instead. + last_frame_timestamp = *snap->timestamp; + /* memcpy( &last_frame_timestamp, snap->timestamp, sizeof(last_frame_timestamp) ); + */ // frame_sent = true; temp_read_index = temp_write_index; From 65d4c43cc27a03c13e0be8a14e930a624789a493 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 20 Nov 2020 16:29:10 -0500 Subject: [PATCH 0667/2339] Use BOUNDARY instead of ZoneMinderFrame. If we get EAGAIN when flocking, try again. --- src/zm_fifo.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/zm_fifo.cpp b/src/zm_fifo.cpp index d3952a169..577281890 100644 --- a/src/zm_fifo.cpp +++ b/src/zm_fifo.cpp @@ -181,7 +181,7 @@ bool FifoStream::sendMJEGFrames() { return true; if ( fprintf(stdout, - "--ZoneMinderFrame\r\n" + "--" BOUNDARY "\r\n" "Content-Type: image/jpeg\r\n" "Content-Length: %d\r\n\r\n", total_read) < 0 ) { @@ -210,9 +210,9 @@ void FifoStream::setStreamStart(int monitor_id, const char * format) { Monitor * monitor = Monitor::Load(monitor_id, false, Monitor::QUERY); if ( !strcmp(format, "reference") ) { - stream_type = MJPEG; snprintf(diag_path, sizeof(diag_path), "%s/diagpipe-r-%d.jpg", staticConfig.PATH_SOCKS.c_str(), monitor->Id()); + stream_type = MJPEG; } else if ( !strcmp(format, "delta") ) { snprintf(diag_path, sizeof(diag_path), "%s/diagpipe-d-%d.jpg", staticConfig.PATH_SOCKS.c_str(), monitor->Id()); @@ -228,14 +228,16 @@ void FifoStream::setStreamStart(int monitor_id, const char * format) { void FifoStream::runStream() { if ( stream_type == MJPEG ) { - fprintf(stdout, "Content-Type: multipart/x-mixed-replace;boundary=ZoneMinderFrame\r\n\r\n"); + fprintf(stdout, "Content-Type: multipart/x-mixed-replace;boundary=" BOUNDARY "\r\n\r\n"); } else { fprintf(stdout, "Content-Type: text/html\r\n\r\n"); } + /* only 1 person can read from a fifo at a time, so use a lock */ char lock_file[PATH_MAX]; snprintf(lock_file, sizeof(lock_file), "%s.rlock", stream_path); file_create_if_missing(lock_file, false); + Debug(1, "Locking %s", lock_file); int fd_lock = open(lock_file, O_RDONLY); if ( fd_lock < 0 ) { @@ -243,6 +245,11 @@ void FifoStream::runStream() { return; } int res = flock(fd_lock, LOCK_EX | LOCK_NB); + while ( (res == EAGAIN) and (! zm_terminate) ) { + Warning("Flocking problem on %s: - %s", lock_file, strerror(errno)); + sleep(1); + res = flock(fd_lock, LOCK_EX | LOCK_NB); + } if ( res < 0 ) { Error("Flocking problem on %s: - %s", lock_file, strerror(errno)); close(fd_lock); From e1a0c4f9735590299744a5e1c94d417ee8aaf8ea Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 20 Nov 2020 16:31:12 -0500 Subject: [PATCH 0668/2339] Don't log a warning of comms not open if no connkey --- src/zm_stream.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/zm_stream.cpp b/src/zm_stream.cpp index e73813b4b..613e6c97e 100644 --- a/src/zm_stream.cpp +++ b/src/zm_stream.cpp @@ -124,11 +124,14 @@ bool StreamBase::checkCommandQueue() { processCommand(&msg); return true; } - } else { + } else if ( connkey ) { Warning("No sd in checkCommandQueue, comms not open?"); + } else { + // Perfectly valid if only getting a snapshot + Debug(1, "No sd in checkCommandQueue, comms not open?"); } return false; -} +} // end bool StreamBase::checkCommandQueue() Image *StreamBase::prepareImage(Image *image) { From 7653a058a372abef93d15c656a5070bb83f24dba Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 20 Nov 2020 16:31:40 -0500 Subject: [PATCH 0669/2339] More correct code for setting source --- src/zms.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/zms.cpp b/src/zms.cpp index 4e77ea4c1..38917a388 100644 --- a/src/zms.cpp +++ b/src/zms.cpp @@ -118,9 +118,13 @@ int main(int argc, const char *argv[], char **envp) { if ( !value ) value = ""; if ( !strcmp(name, "source") ) { - source = !strcmp(value, "event")?ZMS_EVENT:ZMS_MONITOR; - if ( !strcmp(value, "fifo") ) + if ( !strcmp(value, "event") ) { + source = ZMS_EVENT; + } else if ( !strcmp(value, "fifo") ) { source = ZMS_FIFO; + } else { + source = ZMS_MONITOR; + } } else if ( !strcmp(name, "mode") ) { mode = !strcmp(value, "jpeg")?ZMS_JPEG:ZMS_MPEG; mode = !strcmp(value, "raw")?ZMS_RAW:mode; @@ -329,6 +333,7 @@ int main(int argc, const char *argv[], char **envp) { Error("Neither a monitor or event was specified."); } // end if monitor or event + Debug(1, "Terminating"); logTerm(); zmDbClose(); From 1b5448ede4b0a0ed70d10dee025b20d318a007b0 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 20 Nov 2020 16:35:48 -0500 Subject: [PATCH 0670/2339] Handle there being no services in the response --- onvif/modules/lib/ONVIF/Client.pm | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/onvif/modules/lib/ONVIF/Client.pm b/onvif/modules/lib/ONVIF/Client.pm index 9676dff85..945e96075 100644 --- a/onvif/modules/lib/ONVIF/Client.pm +++ b/onvif/modules/lib/ONVIF/Client.pm @@ -117,12 +117,15 @@ sub get_service_urls { } ); if ( $result ) { - foreach my $svc ( @{ $result->get_Service() } ) { - my $short_name = $namespace_map{$svc->get_Namespace()}; - my $url_svc = $svc->get_XAddr()->get_value(); - if ( defined $short_name && defined $url_svc ) { - #print "Got $short_name service\n"; - $self->set_service($short_name, 'url', $url_svc); + my $services = $result->get_Service(); + if ( $services ) { + foreach my $svc ( @{ $services } ) { + my $short_name = $namespace_map{$svc->get_Namespace()}; + my $url_svc = $svc->get_XAddr()->get_value(); + if ( defined $short_name && defined $url_svc ) { + #print "Got $short_name service\n"; + $self->set_service($short_name, 'url', $url_svc); + } } } #} else { From 271dcbc4e8506c809cba48e9d4c8a8125aaf6f11 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 21 Nov 2020 09:12:41 -0500 Subject: [PATCH 0671/2339] select returns EINTR when HUP'd. This is not fatal. Handling this gracefully reduces log spam --- scripts/zmcontrol.pl.in | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/scripts/zmcontrol.pl.in b/scripts/zmcontrol.pl.in index c9a548eef..32c1132d6 100644 --- a/scripts/zmcontrol.pl.in +++ b/scripts/zmcontrol.pl.in @@ -27,7 +27,7 @@ use strict; use ZoneMinder; use Getopt::Long; use autouse 'Pod::Usage'=>qw(pod2usage); -use POSIX qw/strftime EPIPE/; +use POSIX qw/strftime EPIPE EINTR/; use Socket; use Data::Dumper; use Module::Load::Conditional qw{can_load}; @@ -191,7 +191,10 @@ if ( $options{command} ) { Fatal('Bogus descriptor'); } } elsif ( $nfound < 0 ) { - if ( $! == EPIPE ) { + if ( $! == EINTR ) { + # Likely just SIGHUP + Debug("Can't select: $!"); + } elsif ( $! == EPIPE ) { Error("Can't select: $!"); } else { Fatal("Can't select: $!"); From 2cdf0da3c05820a6e971d96ebe04702aa9c76d08 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 21 Nov 2020 09:15:36 -0500 Subject: [PATCH 0672/2339] Remove unused includes and apply google code style --- src/zm_buffer.cpp | 39 ++++++++++++++------------------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/src/zm_buffer.cpp b/src/zm_buffer.cpp index 73c9603e1..be20c008e 100644 --- a/src/zm_buffer.cpp +++ b/src/zm_buffer.cpp @@ -17,62 +17,51 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include -#include - #include "zm.h" #include "zm_buffer.h" -unsigned int Buffer::assign( const unsigned char *pStorage, unsigned int pSize ) -{ - if ( mAllocation < pSize ) - { +unsigned int Buffer::assign(const unsigned char *pStorage, unsigned int pSize) { + if ( mAllocation < pSize ) { delete[] mStorage; mAllocation = pSize; mHead = mStorage = new unsigned char[pSize]; } mSize = pSize; - memcpy( mStorage, pStorage, mSize ); + memcpy(mStorage, pStorage, mSize); mHead = mStorage; mTail = mHead + mSize; - return( mSize ); + return mSize; } -unsigned int Buffer::expand( unsigned int count ) -{ +unsigned int Buffer::expand(unsigned int count) { int spare = mAllocation - mSize; int headSpace = mHead - mStorage; int tailSpace = spare - headSpace; int width = mTail - mHead; - if ( spare > (int)count ) - { - if ( tailSpace < (int)count ) - { - memmove( mStorage, mHead, mSize ); + if ( spare > static_castcount ) { + if ( tailSpace < static_castcount ) { + memmove(mStorage, mHead, mSize); mHead = mStorage; mTail = mHead + width; } - } - else - { + } else { mAllocation += count; unsigned char *newStorage = new unsigned char[mAllocation]; - if ( mStorage ) - { - memcpy( newStorage, mHead, mSize ); + if ( mStorage ) { + memcpy(newStorage, mHead, mSize); delete[] mStorage; } mStorage = newStorage; mHead = mStorage; mTail = mHead + width; } - return( mSize ); + return mSize; } -int Buffer::read_into( int sd, unsigned int bytes ) { +int Buffer::read_into(int sd, unsigned int bytes) { // Make sure there is enough space this->expand(bytes); - int bytes_read = read( sd, mTail, bytes ); + int bytes_read = read(sd, mTail, bytes); if ( bytes_read > 0 ) { mTail += bytes_read; mSize += bytes_read; From 5f4fb4200f80a2c497b6fbf715ec23641a495a92 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 21 Nov 2020 09:25:10 -0500 Subject: [PATCH 0673/2339] googe code style --- src/zm_comms.cpp | 890 ++++++++++++++++++++--------------------------- 1 file changed, 383 insertions(+), 507 deletions(-) diff --git a/src/zm_comms.cpp b/src/zm_comms.cpp index b7231d4fd..ccf84ba91 100644 --- a/src/zm_comms.cpp +++ b/src/zm_comms.cpp @@ -18,20 +18,19 @@ // #include "zm_comms.h" - #include "zm_logger.h" #include #include #include -//#include +#include + #if defined(BSD) #include #else #include #endif -//#include #include #include #include @@ -42,793 +41,677 @@ #include // define FIONREAD #endif -int CommsBase::readV( int iovcnt, /* const void *, int, */ ... ) { +int CommsBase::readV(int iovcnt, /* const void *, int, */ ...) { va_list arg_ptr; struct iovec iov[iovcnt]; - //struct iovec *iov = (struct iovec *)alloca( sizeof(struct iovec)*iovcnt ); - va_start( arg_ptr, iovcnt ); - for ( int i = 0; i < iovcnt; i++ ) - { - iov[i].iov_base = va_arg( arg_ptr, void * ); - iov[i].iov_len = va_arg( arg_ptr, int ); + va_start(arg_ptr, iovcnt); + for ( int i = 0; i < iovcnt; i++ ) { + iov[i].iov_base = va_arg(arg_ptr, void *); + iov[i].iov_len = va_arg(arg_ptr, int); } - va_end( arg_ptr ); + va_end(arg_ptr); - int nBytes = ::readv( mRd, iov, iovcnt ); + int nBytes = ::readv(mRd, iov, iovcnt); if ( nBytes < 0 ) - Debug( 1, "Readv of %d buffers max on rd %d failed: %s", iovcnt, mRd, strerror(errno) ); - return( nBytes ); + Debug(1, "Readv of %d buffers max on rd %d failed: %s", iovcnt, mRd, strerror(errno)); + return nBytes; } -int CommsBase::writeV( int iovcnt, /* const void *, int, */ ... ) { +int CommsBase::writeV(int iovcnt, /* const void *, int, */ ...) { va_list arg_ptr; struct iovec iov[iovcnt]; - //struct iovec *iov = (struct iovec *)alloca( sizeof(struct iovec)*iovcnt ); - va_start( arg_ptr, iovcnt ); - for ( int i = 0; i < iovcnt; i++ ) - { - iov[i].iov_base = va_arg( arg_ptr, void * ); - iov[i].iov_len = va_arg( arg_ptr, int ); + va_start(arg_ptr, iovcnt); + for ( int i = 0; i < iovcnt; i++ ) { + iov[i].iov_base = va_arg(arg_ptr, void *); + iov[i].iov_len = va_arg(arg_ptr, int); } - va_end( arg_ptr ); + va_end(arg_ptr); - ssize_t nBytes = ::writev( mWd, iov, iovcnt ); + ssize_t nBytes = ::writev(mWd, iov, iovcnt); if ( nBytes < 0 ) - Debug( 1, "Writev of %d buffers on wd %d failed: %s", iovcnt, mWd, strerror(errno) ); - return( nBytes ); + Debug(1, "Writev of %d buffers on wd %d failed: %s", iovcnt, mWd, strerror(errno)); + return nBytes; } -bool Pipe::open() -{ - if ( ::pipe( mFd ) < 0 ) - { - Error( "pipe(), errno = %d, error = %s", errno, strerror(errno) ); - return( false ); +bool Pipe::open() { + if ( ::pipe(mFd) < 0 ) { + Error("pipe(), errno = %d, error = %s", errno, strerror(errno)); + return false; } - return( true ); + return true; } -bool Pipe::close() -{ +bool Pipe::close() { if ( mFd[0] > -1 ) ::close( mFd[0] ); mFd[0] = -1; if ( mFd[1] > -1 ) ::close( mFd[1] ); mFd[1] = -1; - return( true ); + return true; } -bool Pipe::setBlocking( bool blocking ) -{ +bool Pipe::setBlocking(bool blocking) { int flags; /* Now set it for non-blocking I/O */ - if ( (flags = fcntl( mFd[1], F_GETFL )) < 0 ) - { - Error( "fcntl(), errno = %d, error = %s", errno, strerror(errno) ); - return( false ); + if ( (flags = fcntl(mFd[1], F_GETFL)) < 0 ) { + Error("fcntl(), errno = %d, error = %s", errno, strerror(errno)); + return false; } - if ( blocking ) - { + if ( blocking ) { flags &= ~O_NONBLOCK; - } - else - { + } else { flags |= O_NONBLOCK; } - if ( fcntl( mFd[1], F_SETFL, flags ) < 0 ) - { - Error( "fcntl(), errno = %d, error = %s", errno, strerror(errno) ); - return( false ); + if ( fcntl(mFd[1], F_SETFL, flags) < 0 ) { + Error("fcntl(), errno = %d, error = %s", errno, strerror(errno)); + return false; } - return( true ); + return true; } -SockAddr::SockAddr( const struct sockaddr *addr ) : mAddr( addr ) -{ +SockAddr::SockAddr(const struct sockaddr *addr) : mAddr(addr) { } -SockAddr *SockAddr::newSockAddr( const struct sockaddr &addr, socklen_t len ) -{ - if ( addr.sa_family == AF_INET && len == SockAddrInet::addrSize() ) - { - return( new SockAddrInet( (const struct sockaddr_in *)&addr ) ); +SockAddr *SockAddr::newSockAddr(const struct sockaddr &addr, socklen_t len) { + if ( (addr.sa_family == AF_INET) && (len == SockAddrInet::addrSize()) ) { + return new SockAddrInet((const struct sockaddr_in *)&addr); + } else if ( (addr.sa_family == AF_UNIX) && (len == SockAddrUnix::addrSize()) ) { + return new SockAddrUnix((const struct sockaddr_un *)&addr); } - else if ( addr.sa_family == AF_UNIX && len == SockAddrUnix::addrSize() ) - { - return( new SockAddrUnix( (const struct sockaddr_un *)&addr ) ); - } - Error( "Unable to create new SockAddr from addr family %d with size %d", addr.sa_family, len ); + Error("Unable to create new SockAddr from addr family %d with size %d", addr.sa_family, len); return nullptr; } -SockAddr *SockAddr::newSockAddr( const SockAddr *addr ) -{ +SockAddr *SockAddr::newSockAddr(const SockAddr *addr) { if ( !addr ) return nullptr; - if ( addr->getDomain() == AF_INET ) - { - return( new SockAddrInet( *(SockAddrInet *)addr ) ); + if ( addr->getDomain() == AF_INET ) { + return new SockAddrInet(*(SockAddrInet *)addr); + } else if ( addr->getDomain() == AF_UNIX ) { + return new SockAddrUnix(*(SockAddrUnix *)addr); } - else if ( addr->getDomain() == AF_UNIX ) - { - return( new SockAddrUnix( *(SockAddrUnix *)addr ) ); - } - Error( "Unable to create new SockAddr from addr family %d", addr->getDomain() ); + Error("Unable to create new SockAddr from addr family %d", addr->getDomain()); return nullptr; } -SockAddrInet::SockAddrInet() : SockAddr( (struct sockaddr *)&mAddrIn ) -{ +SockAddrInet::SockAddrInet() : SockAddr( (struct sockaddr *)&mAddrIn ) { } -bool SockAddrInet::resolve( const char *host, const char *serv, const char *proto ) -{ - memset( &mAddrIn, 0, sizeof(mAddrIn) ); +bool SockAddrInet::resolve(const char *host, const char *serv, const char *proto) { + memset(&mAddrIn, 0, sizeof(mAddrIn)); - struct hostent *hostent=nullptr; - if ( !(hostent = ::gethostbyname( host ) ) ) - { - Error( "gethostbyname( %s ), h_errno = %d", host, h_errno ); - return( false ); + struct hostent *hostent = nullptr; + if ( !(hostent = ::gethostbyname(host) ) ) { + Error("gethostbyname(%s), h_errno = %d", host, h_errno); + return false; } - struct servent *servent=nullptr; - if ( !(servent = ::getservbyname( serv, proto ) ) ) - { - Error( "getservbyname( %s ), errno = %d, error = %s", serv, errno, strerror(errno) ); - return( false ); + struct servent *servent = nullptr; + if ( !(servent = ::getservbyname(serv, proto) ) ) { + Error("getservbyname( %s ), errno = %d, error = %s", serv, errno, strerror(errno)); + return false; } mAddrIn.sin_port = servent->s_port; mAddrIn.sin_family = AF_INET; mAddrIn.sin_addr.s_addr = ((struct in_addr *)(hostent->h_addr))->s_addr; - return( true ); + return true; } -bool SockAddrInet::resolve( const char *host, int port, const char *proto ) -{ - memset( &mAddrIn, 0, sizeof(mAddrIn) ); +bool SockAddrInet::resolve(const char *host, int port, const char *proto) { + memset(&mAddrIn, 0, sizeof(mAddrIn)); - struct hostent *hostent=nullptr; - if ( !(hostent = ::gethostbyname( host ) ) ) - { - Error( "gethostbyname( %s ), h_errno = %d", host, h_errno ); - return( false ); + struct hostent *hostent = nullptr; + if ( !(hostent = ::gethostbyname(host)) ) { + Error("gethostbyname(%s), h_errno = %d", host, h_errno); + return false; } mAddrIn.sin_port = htons(port); mAddrIn.sin_family = AF_INET; mAddrIn.sin_addr.s_addr = ((struct in_addr *)(hostent->h_addr))->s_addr; - return( true ); + return true; } -bool SockAddrInet::resolve( const char *serv, const char *proto ) -{ - memset( &mAddrIn, 0, sizeof(mAddrIn) ); +bool SockAddrInet::resolve(const char *serv, const char *proto) { + memset(&mAddrIn, 0, sizeof(mAddrIn)); - struct servent *servent=nullptr; - if ( !(servent = ::getservbyname( serv, proto ) ) ) - { - Error( "getservbyname( %s ), errno = %d, error = %s", serv, errno, strerror(errno) ); - return( false ); + struct servent *servent = nullptr; + if ( !(servent = ::getservbyname(serv, proto)) ) { + Error("getservbyname(%s), errno = %d, error = %s", serv, errno, strerror(errno)); + return false; } mAddrIn.sin_port = servent->s_port; mAddrIn.sin_family = AF_INET; mAddrIn.sin_addr.s_addr = INADDR_ANY; - return( true ); + return true; } -bool SockAddrInet::resolve( int port, const char *proto ) -{ - memset( &mAddrIn, 0, sizeof(mAddrIn) ); +bool SockAddrInet::resolve(int port, const char *proto) { + memset(&mAddrIn, 0, sizeof(mAddrIn)); mAddrIn.sin_port = htons(port); mAddrIn.sin_family = AF_INET; mAddrIn.sin_addr.s_addr = INADDR_ANY; - return( true ); + return true; } -SockAddrUnix::SockAddrUnix() : SockAddr( (struct sockaddr *)&mAddrUn ) -{ +SockAddrUnix::SockAddrUnix() : SockAddr((struct sockaddr *)&mAddrUn ) { } -bool SockAddrUnix::resolve( const char *path, const char *proto ) -{ - memset( &mAddrUn, 0, sizeof(mAddrUn) ); +bool SockAddrUnix::resolve(const char *path, const char *proto) { + memset(&mAddrUn, 0, sizeof(mAddrUn)); - strncpy( mAddrUn.sun_path, path, sizeof(mAddrUn.sun_path) ); + strncpy(mAddrUn.sun_path, path, sizeof(mAddrUn.sun_path)); mAddrUn.sun_family = AF_UNIX; - return( true ); + return true; } -bool Socket::socket() -{ +bool Socket::socket() { if ( mSd >= 0 ) - return( true ); + return true; - if ( (mSd = ::socket( getDomain(), getType(), 0 ) ) < 0 ) - { - Error( "socket(), errno = %d, error = %s", errno, strerror(errno) ); - return( false ); + if ( (mSd = ::socket(getDomain(), getType(), 0) ) < 0 ) { + Error("socket(), errno = %d, error = %s", errno, strerror(errno)); + return false; } int val = 1; - (void)::setsockopt( mSd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val) ); - (void)::setsockopt( mSd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val) ); + (void)::setsockopt(mSd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); + (void)::setsockopt(mSd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)); mState = DISCONNECTED; - return( true ); + return true; } -bool Socket::connect() -{ - if ( !socket() ) - return( false ); +bool Socket::connect() { + if ( !socket() ) + return false; - if ( ::connect( mSd, mRemoteAddr->getAddr(), getAddrSize() ) == -1 ) - { - Error( "connect(), errno = %d, error = %s", errno, strerror(errno) ); + if ( ::connect(mSd, mRemoteAddr->getAddr(), getAddrSize()) == -1 ) { + Error("connect(), errno = %d, error = %s", errno, strerror(errno)); close(); - return( false ); + return false; } mState = CONNECTED; - return( true ); + return true; } -bool Socket::bind() -{ +bool Socket::bind() { if ( !socket() ) - return( false ); + return false; - if ( ::bind( mSd, mLocalAddr->getAddr(), getAddrSize() ) == -1 ) - { - Error( "bind(), errno = %d, error = %s", errno, strerror(errno) ); + if ( ::bind(mSd, mLocalAddr->getAddr(), getAddrSize()) == -1 ) { + Error("bind(), errno = %d, error = %s", errno, strerror(errno)); close(); - return( false ); + return false; } - return( true ); + return true; } -bool Socket::listen() -{ - if ( ::listen( mSd, SOMAXCONN ) == -1 ) - { - Error( "listen(), errno = %d, error = %s", errno, strerror(errno) ); +bool Socket::listen() { + if ( ::listen(mSd, SOMAXCONN) == -1 ) { + Error("listen(), errno = %d, error = %s", errno, strerror(errno)); close(); - return( false ); + return false; } mState = LISTENING; - - return( true ); + return true; } -bool Socket::accept() -{ +bool Socket::accept() { struct sockaddr *rem_addr = mLocalAddr->getTempAddr(); socklen_t rem_addr_size = getAddrSize(); int newSd = -1; - if ( (newSd = ::accept( mSd, rem_addr, &rem_addr_size )) == -1 ) - { - Error( "accept(), errno = %d, error = %s", errno, strerror(errno) ); + if ( (newSd = ::accept(mSd, rem_addr, &rem_addr_size)) == -1 ) { + Error("accept(), errno = %d, error = %s", errno, strerror(errno)); close(); - return( false ); + return false; } - ::close( mSd ); + ::close(mSd); mSd = newSd; mState = CONNECTED; - return( true ); + return true; } -bool Socket::accept( int &newSd ) -{ +bool Socket::accept(int &newSd) { struct sockaddr *rem_addr = mLocalAddr->getTempAddr(); socklen_t rem_addr_size = getAddrSize(); newSd = -1; - if ( (newSd = ::accept( mSd, rem_addr, &rem_addr_size )) == -1 ) - { - Error( "accept(), errno = %d, error = %s", errno, strerror(errno) ); + if ( (newSd = ::accept(mSd, rem_addr, &rem_addr_size)) == -1 ) { + Error("accept(), errno = %d, error = %s", errno, strerror(errno)); close(); - return( false ); + return false; } - return( true ); + return true; } -bool Socket::close() -{ - if ( mSd > -1 ) ::close( mSd ); +bool Socket::close() { + if ( mSd > -1 ) ::close(mSd); mSd = -1; mState = CLOSED; - return( true ); + return true; } -int Socket::bytesToRead() const -{ +int Socket::bytesToRead() const { int bytes_to_read = 0; - if ( ioctl( mSd, FIONREAD, &bytes_to_read ) < 0 ) - { - Error( "ioctl(), errno = %d, error = %s", errno, strerror(errno) ); - return( -1 ); + if ( ioctl(mSd, FIONREAD, &bytes_to_read) < 0 ) { + Error("ioctl(), errno = %d, error = %s", errno, strerror(errno)); + return -1; } - return( bytes_to_read ); + return bytes_to_read; } -bool Socket::getBlocking( bool &blocking ) -{ +bool Socket::getBlocking(bool &blocking) { int flags; - if ( (flags = fcntl( mSd, F_GETFL )) < 0 ) - { - Error( "fcntl(), errno = %d, error = %s", errno, strerror(errno) ); - return( false ); + if ( (flags = fcntl(mSd, F_GETFL)) < 0 ) { + Error("fcntl(), errno = %d, error = %s", errno, strerror(errno)); + return false; } - blocking = (flags & O_NONBLOCK); - return( true ); + blocking = flags & O_NONBLOCK; + return true; } -bool Socket::setBlocking( bool blocking ) -{ -#if 0 - // ioctl is apparently not recommended - int ioctl_arg = !blocking; - if ( ioctl( mSd, FIONBIO, &ioctl_arg ) < 0 ) - { - Error( "ioctl(), errno = %d, error = %s", errno, strerror(errno) ); - return( false ); - } - return( true ); -#endif - +bool Socket::setBlocking(bool blocking) { int flags; /* Now set it for non-blocking I/O */ - if ( (flags = fcntl( mSd, F_GETFL )) < 0 ) - { - Error( "fcntl(), errno = %d, error = %s", errno, strerror(errno) ); - return( false ); + if ( (flags = fcntl(mSd, F_GETFL)) < 0 ) { + Error("fcntl(), errno = %d, error = %s", errno, strerror(errno)); + return false; } - if ( blocking ) - { + if ( blocking ) { flags &= ~O_NONBLOCK; - } - else - { + } else { flags |= O_NONBLOCK; } - if ( fcntl( mSd, F_SETFL, flags ) < 0 ) - { - Error( "fcntl(), errno = %d, error = %s", errno, strerror(errno) ); - return( false ); + if ( fcntl(mSd, F_SETFL, flags) < 0 ) { + Error("fcntl(), errno = %d, error = %s", errno, strerror(errno)); + return false; } - return( true ); + return true; } -bool Socket::getSendBufferSize( int &buffersize ) const -{ +bool Socket::getSendBufferSize(int &buffersize) const { socklen_t optlen = sizeof(buffersize); - if ( getsockopt( mSd, SOL_SOCKET, SO_SNDBUF, &buffersize, &optlen ) < 0 ) - { - Error( "getsockopt(), errno = %d, error = %s", errno, strerror(errno) ); - return( -1 ); + if ( getsockopt(mSd, SOL_SOCKET, SO_SNDBUF, &buffersize, &optlen) < 0 ) { + Error("getsockopt(), errno = %d, error = %s", errno, strerror(errno)); + return -1; } - return( buffersize ); + return buffersize; } -bool Socket::getRecvBufferSize( int &buffersize ) const -{ +bool Socket::getRecvBufferSize(int &buffersize) const { socklen_t optlen = sizeof(buffersize); - if ( getsockopt( mSd, SOL_SOCKET, SO_RCVBUF, &buffersize, &optlen ) < 0 ) - { - Error( "getsockopt(), errno = %d, error = %s", errno, strerror(errno) ); - return( -1 ); + if ( getsockopt(mSd, SOL_SOCKET, SO_RCVBUF, &buffersize, &optlen) < 0 ) { + Error("getsockopt(), errno = %d, error = %s", errno, strerror(errno)); + return -1; } - return( buffersize ); + return buffersize; } -bool Socket::setSendBufferSize( int buffersize ) -{ - if ( setsockopt( mSd, SOL_SOCKET, SO_SNDBUF, (char *)&buffersize, sizeof(buffersize)) < 0 ) - { - Error( "setsockopt(), errno = %d, error = %s", errno, strerror(errno) ); - return( false ); +bool Socket::setSendBufferSize(int buffersize) { + if ( setsockopt(mSd, SOL_SOCKET, SO_SNDBUF, (char *)&buffersize, sizeof(buffersize)) < 0 ) { + Error("setsockopt(), errno = %d, error = %s", errno, strerror(errno)); + return false; } - return( true ); + return true; } -bool Socket::setRecvBufferSize( int buffersize ) -{ - if ( setsockopt( mSd, SOL_SOCKET, SO_RCVBUF, (char *)&buffersize, sizeof(buffersize)) < 0 ) - { - Error( "setsockopt(), errno = %d, error = %s", errno, strerror(errno) ); - return( false ); +bool Socket::setRecvBufferSize(int buffersize) { + if ( setsockopt( mSd, SOL_SOCKET, SO_RCVBUF, (char *)&buffersize, sizeof(buffersize)) < 0 ) { + Error("setsockopt(), errno = %d, error = %s", errno, strerror(errno)); + return false; } - return( true ); + return true; } -bool Socket::getRouting( bool &route ) const -{ +bool Socket::getRouting(bool &route) const { int dontRoute; socklen_t optlen = sizeof(dontRoute); - if ( getsockopt( mSd, SOL_SOCKET, SO_DONTROUTE, &dontRoute, &optlen ) < 0 ) - { - Error( "getsockopt(), errno = %d, error = %s", errno, strerror(errno) ); - return( false ); + if ( getsockopt(mSd, SOL_SOCKET, SO_DONTROUTE, &dontRoute, &optlen) < 0 ) { + Error("getsockopt(), errno = %d, error = %s", errno, strerror(errno)); + return false; } route = !dontRoute; - return( true ); + return true; } -bool Socket::setRouting( bool route ) -{ +bool Socket::setRouting(bool route) { int dontRoute = !route; - if ( setsockopt( mSd, SOL_SOCKET, SO_DONTROUTE, (char *)&dontRoute, sizeof(dontRoute)) < 0 ) - { - Error( "setsockopt(), errno = %d, error = %s", errno, strerror(errno) ); - return( false ); + if ( setsockopt(mSd, SOL_SOCKET, SO_DONTROUTE, (char *)&dontRoute, sizeof(dontRoute)) < 0 ) { + Error("setsockopt(), errno = %d, error = %s", errno, strerror(errno)); + return false; } - return( true ); + return true; } -bool Socket::getNoDelay( bool &nodelay ) const -{ +bool Socket::getNoDelay(bool &nodelay) const { int int_nodelay; socklen_t optlen = sizeof(int_nodelay); - if ( getsockopt( mSd, IPPROTO_TCP, TCP_NODELAY, &int_nodelay, &optlen ) < 0 ) - { - Error( "getsockopt(), errno = %d, error = %s", errno, strerror(errno) ); - return( false ); + if ( getsockopt(mSd, IPPROTO_TCP, TCP_NODELAY, &int_nodelay, &optlen) < 0 ) { + Error("getsockopt(), errno = %d, error = %s", errno, strerror(errno)); + return false; } nodelay = int_nodelay; - return( true ); + return true; } -bool Socket::setNoDelay( bool nodelay ) -{ +bool Socket::setNoDelay(bool nodelay) { int int_nodelay = nodelay; - if ( setsockopt( mSd, IPPROTO_TCP, TCP_NODELAY, (char *)&int_nodelay, sizeof(int_nodelay)) < 0 ) - { - Error( "setsockopt(), errno = %d, error = %s", errno, strerror(errno) ); - return( false ); + if ( setsockopt(mSd, IPPROTO_TCP, TCP_NODELAY, (char *)&int_nodelay, sizeof(int_nodelay)) < 0 ) { + Error("setsockopt(), errno = %d, error = %s", errno, strerror(errno)); + return false; } - return( true ); + return true; } -bool InetSocket::connect( const char *host, const char *serv ) -{ - struct addrinfo hints; - struct addrinfo *result, *rp; - int s; - char buf[255]; +bool InetSocket::connect(const char *host, const char *serv) { + struct addrinfo hints; + struct addrinfo *result, *rp; + int s; + char buf[255]; + mAddressFamily = AF_UNSPEC; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + hints.ai_socktype = getType(); + hints.ai_flags = 0; + hints.ai_protocol = 0; /* Any protocol */ + + s = getaddrinfo(host, serv, &hints, &result); + if ( s != 0 ) { + Error("connect(): getaddrinfo: %s", gai_strerror(s)); + return false; + } + + /* getaddrinfo() returns a list of address structures. + * Try each address until we successfully connect(2). + * If socket(2) (or connect(2)) fails, we (close the socket + * and) try the next address. */ + + for ( rp = result; rp != nullptr; rp = rp->ai_next ) { + if ( mSd != -1 ) { + if ( ::connect(mSd, rp->ai_addr, rp->ai_addrlen) != -1 ) + break; /* Success */ + continue; + } + memset(&buf, 0, sizeof(buf)); + if ( rp->ai_family == AF_INET ) { + inet_ntop(AF_INET, &((struct sockaddr_in *)rp->ai_addr)->sin_addr, buf, sizeof(buf)-1); + } else if (rp->ai_family == AF_INET6) { + inet_ntop(AF_INET6, &((struct sockaddr_in6 *)rp->ai_addr)->sin6_addr, buf, sizeof(buf)-1); + } else { + strncpy(buf, "n/a", sizeof(buf)-1); + } + Debug(1, "connect(): Trying '%s', family '%d', proto '%d'", buf, rp->ai_family, rp->ai_protocol); + mSd = ::socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if ( mSd == -1 ) + continue; + + int val = 1; + + (void)::setsockopt(mSd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); + (void)::setsockopt(mSd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)); + mAddressFamily = rp->ai_family; /* save AF_ for ctrl and data connections */ + + if ( ::connect(mSd, rp->ai_addr, rp->ai_addrlen) != -1 ) + break; /* Success */ + + ::close(mSd); + } // end for + + freeaddrinfo(result); /* No longer needed */ + + if ( rp == nullptr ) { /* No address succeeded */ + Error("connect(), Could not connect"); mAddressFamily = AF_UNSPEC; - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ - hints.ai_socktype = getType(); - hints.ai_flags = 0; - hints.ai_protocol = 0; /* Any protocol */ + return false; + } - s = getaddrinfo(host, serv, &hints, &result); - if (s != 0) { - Error( "connect(): getaddrinfo: %s", gai_strerror(s) ); - return( false ); - } + mState = CONNECTED; - /* getaddrinfo() returns a list of address structures. - * Try each address until we successfully connect(2). - * If socket(2) (or connect(2)) fails, we (close the socket - * and) try the next address. */ - - for (rp = result; rp != nullptr; rp = rp->ai_next) { - if (mSd != -1) { - if (::connect(mSd, rp->ai_addr, rp->ai_addrlen) != -1) - break; /* Success */ - continue; - } - memset(&buf, 0, sizeof(buf)); - if (rp->ai_family == AF_INET) { - inet_ntop(AF_INET, &((struct sockaddr_in *)rp->ai_addr)->sin_addr, buf, sizeof(buf)-1); - } - else if (rp->ai_family == AF_INET6) { - inet_ntop(AF_INET6, &((struct sockaddr_in6 *)rp->ai_addr)->sin6_addr, buf, sizeof(buf)-1); - } - else { - strncpy(buf, "n/a", sizeof(buf)-1); - } - Debug( 1, "connect(): Trying '%s', family '%d', proto '%d'", buf, rp->ai_family, rp->ai_protocol); - mSd = ::socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); - if (mSd == -1) - continue; - - int val = 1; - - (void)::setsockopt( mSd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val) ); - (void)::setsockopt( mSd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val) ); - mAddressFamily = rp->ai_family; /* save AF_ for ctrl and data connections */ - - if (::connect(mSd, rp->ai_addr, rp->ai_addrlen) != -1) - break; /* Success */ - - ::close(mSd); - } - - freeaddrinfo(result); /* No longer needed */ - - if (rp == nullptr) { /* No address succeeded */ - Error( "connect(), Could not connect" ); - mAddressFamily = AF_UNSPEC; - return( false ); - } - - mState = CONNECTED; - - return( true ); + return true; } -bool InetSocket::connect( const char *host, int port ) -{ - char serv[8]; - snprintf(serv, sizeof(serv), "%d", port); +bool InetSocket::connect(const char *host, int port) { + char serv[8]; + snprintf(serv, sizeof(serv), "%d", port); - return connect( host, serv ); + return connect(host, serv); } -bool InetSocket::bind( const char * host, const char * serv ) -{ - struct addrinfo hints; - struct addrinfo *result, *rp; - int s; - char buf[255]; +bool InetSocket::bind(const char * host, const char * serv) { + struct addrinfo hints; - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ - hints.ai_socktype = getType(); - hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */ - hints.ai_protocol = 0; /* Any protocol */ - hints.ai_canonname = nullptr; - hints.ai_addr = nullptr; - hints.ai_next = nullptr; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + hints.ai_socktype = getType(); + hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */ + hints.ai_protocol = 0; /* Any protocol */ + hints.ai_canonname = nullptr; + hints.ai_addr = nullptr; + hints.ai_next = nullptr; - s = getaddrinfo(host, serv, &hints, &result); - if (s != 0) { - Error( "bind(): getaddrinfo: %s", gai_strerror(s) ); - return( false ); + struct addrinfo *result, *rp; + int s = getaddrinfo(host, serv, &hints, &result); + if ( s != 0 ) { + Error("bind(): getaddrinfo: %s", gai_strerror(s)); + return false; + } + + char buf[255]; + /* getaddrinfo() returns a list of address structures. + * Try each address until we successfully bind(2). + * If socket(2) (or bind(2)) fails, we (close the socket + * and) try the next address. */ + for ( rp = result; rp != nullptr; rp = rp->ai_next ) { + memset(&buf, 0, sizeof(buf)); + if ( rp->ai_family == AF_INET ) { + inet_ntop(AF_INET, &((struct sockaddr_in *)rp->ai_addr)->sin_addr, buf, sizeof(buf)-1); + } else if ( rp->ai_family == AF_INET6 ) { + inet_ntop(AF_INET6, &((struct sockaddr_in6 *)rp->ai_addr)->sin6_addr, buf, sizeof(buf)-1); + } else { + strncpy(buf, "n/a", sizeof(buf)-1); } - - /* getaddrinfo() returns a list of address structures. - * Try each address until we successfully bind(2). - * If socket(2) (or bind(2)) fails, we (close the socket - * and) try the next address. */ - for (rp = result; rp != nullptr; rp = rp->ai_next) { - memset(&buf, 0, sizeof(buf)); - if (rp->ai_family == AF_INET) { - inet_ntop(AF_INET, &((struct sockaddr_in *)rp->ai_addr)->sin_addr, buf, sizeof(buf)-1); - } - else if (rp->ai_family == AF_INET6) { - inet_ntop(AF_INET6, &((struct sockaddr_in6 *)rp->ai_addr)->sin6_addr, buf, sizeof(buf)-1); - } - else { - strncpy(buf, "n/a", sizeof(buf)-1); - } - Debug( 1, "bind(): Trying '%s', family '%d', proto '%d'", buf, rp->ai_family, rp->ai_protocol); - mSd = ::socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); - if (mSd == -1) - continue; + Debug(1, "bind(): Trying '%s', family '%d', proto '%d'", buf, rp->ai_family, rp->ai_protocol); + mSd = ::socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if ( mSd == -1 ) + continue; mState = DISCONNECTED; - if (::bind(mSd, rp->ai_addr, rp->ai_addrlen) == 0) - break; /* Success */ + if ( ::bind(mSd, rp->ai_addr, rp->ai_addrlen) == 0 ) + break; /* Success */ - ::close(mSd); - mSd = -1; - } + ::close(mSd); + mSd = -1; + } // end foreach result - if (rp == nullptr) { /* No address succeeded */ - Error( "bind(), Could not bind" ); - return( false ); - } + if ( rp == nullptr ) { /* No address succeeded */ + Error("bind(), Could not bind"); + return false; + } - freeaddrinfo(result); /* No longer needed */ - - return( true ); + freeaddrinfo(result); /* No longer needed */ + return true; } -bool InetSocket::bind( const char * serv ) -{ - return bind( nullptr, serv); +bool InetSocket::bind(const char * serv) { + return bind(nullptr, serv); } -bool InetSocket::bind( const char * host, int port ) -{ - char serv[8]; - snprintf(serv, sizeof(serv), "%d", port); +bool InetSocket::bind(const char * host, int port) { + char serv[8]; + snprintf(serv, sizeof(serv), "%d", port); - return bind( host, serv ); + return bind(host, serv); } -bool InetSocket::bind( int port ) -{ - char serv[8]; - snprintf(serv, sizeof(serv), "%d", port); +bool InetSocket::bind(int port) { + char serv[8]; + snprintf(serv, sizeof(serv), "%d", port); - return bind( nullptr, serv ); + return bind(nullptr, serv); } -bool TcpInetServer::listen() -{ - return( Socket::listen() ); +bool TcpInetServer::listen() { + return Socket::listen(); } -bool TcpInetServer::accept() -{ - return( Socket::accept() ); +bool TcpInetServer::accept() { + return Socket::accept(); } -bool TcpInetServer::accept( TcpInetSocket *&newSocket ) -{ +bool TcpInetServer::accept(TcpInetSocket *&newSocket) { int newSd = -1; newSocket = nullptr; - if ( !Socket::accept( newSd ) ) - return( false ); + if ( !Socket::accept(newSd) ) + return false; - newSocket = new TcpInetSocket( *this, newSd ); + newSocket = new TcpInetSocket(*this, newSd); - return( true ); + return true; } -bool TcpUnixServer::accept( TcpUnixSocket *&newSocket ) -{ +bool TcpUnixServer::accept(TcpUnixSocket *&newSocket) { int newSd = -1; newSocket = nullptr; - if ( !Socket::accept( newSd ) ) - return( false ); + if ( !Socket::accept(newSd) ) + return false; - newSocket = new TcpUnixSocket( *this, newSd ); + newSocket = new TcpUnixSocket(*this, newSd); - return( true ); + return true; } -Select::Select() : mHasTimeout( false ), mMaxFd( -1 ) -{ +Select::Select() : mHasTimeout(false), mMaxFd(-1) { } -Select::Select( struct timeval timeout ) : mMaxFd( -1 ) -{ - setTimeout( timeout ); +Select::Select(struct timeval timeout) : mMaxFd(-1) { + setTimeout(timeout); } -Select::Select( int timeout ) : mMaxFd( -1 ) -{ - setTimeout( timeout ); +Select::Select(int timeout) : mMaxFd(-1) { + setTimeout(timeout); } -Select::Select( double timeout ) : mMaxFd( -1 ) -{ - setTimeout( timeout ); +Select::Select(double timeout) : mMaxFd(-1) { + setTimeout(timeout); } -void Select::setTimeout( int timeout ) -{ +void Select::setTimeout(int timeout) { mTimeout.tv_sec = timeout; mTimeout.tv_usec = 0; mHasTimeout = true; } -void Select::setTimeout( double timeout ) -{ +void Select::setTimeout(double timeout) { mTimeout.tv_sec = int(timeout); mTimeout.tv_usec = suseconds_t((timeout-mTimeout.tv_sec)*1000000.0); mHasTimeout = true; } -void Select::setTimeout( struct timeval timeout ) -{ +void Select::setTimeout(struct timeval timeout) { mTimeout = timeout; mHasTimeout = true; } -void Select::clearTimeout() -{ +void Select::clearTimeout() { mHasTimeout = false; } -void Select::calcMaxFd() -{ +void Select::calcMaxFd() { mMaxFd = -1; - for ( CommsSet::iterator iter = mReaders.begin(); iter != mReaders.end(); ++iter ) + for ( CommsSet::iterator iter = mReaders.begin(); iter != mReaders.end(); ++iter ) { if ( (*iter)->getMaxDesc() > mMaxFd ) mMaxFd = (*iter)->getMaxDesc(); - for ( CommsSet::iterator iter = mWriters.begin(); iter != mWriters.end(); ++iter ) + } + for ( CommsSet::iterator iter = mWriters.begin(); iter != mWriters.end(); ++iter ) { if ( (*iter)->getMaxDesc() > mMaxFd ) mMaxFd = (*iter)->getMaxDesc(); + } } -bool Select::addReader( CommsBase *comms ) -{ - if ( !comms->isOpen() ) - { - Error( "Unable to add closed reader" ); - return( false ); +bool Select::addReader(CommsBase *comms) { + if ( !comms->isOpen() ) { + Error("Unable to add closed reader"); + return false; } - std::pair result = mReaders.insert( comms ); - if ( result.second ) + std::pair result = mReaders.insert(comms); + if ( result.second ) { if ( comms->getMaxDesc() > mMaxFd ) mMaxFd = comms->getMaxDesc(); - return( result.second ); + } + return result.second; } -bool Select::deleteReader( CommsBase *comms ) -{ - if ( !comms->isOpen() ) - { - Error( "Unable to add closed reader" ); - return( false ); +bool Select::deleteReader(CommsBase *comms) { + if ( !comms->isOpen() ) { + Error("Unable to add closed reader"); + return false; } - if ( mReaders.erase( comms ) ) - { + if ( mReaders.erase(comms) ) { calcMaxFd(); - return( true ); + return true; } - return( false ); + return false; } -void Select::clearReaders() -{ +void Select::clearReaders() { mReaders.clear(); mMaxFd = -1; } -bool Select::addWriter( CommsBase *comms ) -{ - std::pair result = mWriters.insert( comms ); - if ( result.second ) +bool Select::addWriter(CommsBase *comms) { + std::pair result = mWriters.insert(comms); + if ( result.second ) { if ( comms->getMaxDesc() > mMaxFd ) mMaxFd = comms->getMaxDesc(); - return( result.second ); -} - -bool Select::deleteWriter( CommsBase *comms ) -{ - if ( mWriters.erase( comms ) ) - { - calcMaxFd(); - return( true ); } - return( false ); + return result.second; } -void Select::clearWriters() -{ +bool Select::deleteWriter(CommsBase *comms) { + if ( mWriters.erase(comms) ) { + calcMaxFd(); + return true; + } + return false; +} + +void Select::clearWriters() { mWriters.clear(); mMaxFd = -1; } -int Select::wait() -{ +int Select::wait() { struct timeval tempTimeout = mTimeout; struct timeval *selectTimeout = mHasTimeout?&tempTimeout:nullptr; @@ -838,40 +721,33 @@ int Select::wait() mReadable.clear(); FD_ZERO(&rfds); for ( CommsSet::iterator iter = mReaders.begin(); iter != mReaders.end(); ++iter ) - FD_SET((*iter)->getReadDesc(),&rfds); + FD_SET((*iter)->getReadDesc(), &rfds); mWriteable.clear(); FD_ZERO(&wfds); for ( CommsSet::iterator iter = mWriters.begin(); iter != mWriters.end(); ++iter ) - FD_SET((*iter)->getWriteDesc(),&wfds); + FD_SET((*iter)->getWriteDesc(), &wfds); - int nFound = select( mMaxFd+1, &rfds, &wfds, nullptr, selectTimeout ); - if( nFound == 0 ) - { - Debug( 1, "Select timed out" ); - } - else if ( nFound < 0) - { - Error( "Select error: %s", strerror(errno) ); - } - else - { + int nFound = select(mMaxFd+1, &rfds, &wfds, nullptr, selectTimeout); + if ( nFound == 0 ) { + Debug(1, "Select timed out"); + } else if ( nFound < 0 ) { + Error("Select error: %s", strerror(errno)); + } else { for ( CommsSet::iterator iter = mReaders.begin(); iter != mReaders.end(); ++iter ) - if ( FD_ISSET((*iter)->getReadDesc(),&rfds) ) - mReadable.push_back( *iter ); + if ( FD_ISSET((*iter)->getReadDesc(), &rfds) ) + mReadable.push_back(*iter); for ( CommsSet::iterator iter = mWriters.begin(); iter != mWriters.end(); ++iter ) - if ( FD_ISSET((*iter)->getWriteDesc(),&rfds) ) - mWriteable.push_back( *iter ); + if ( FD_ISSET((*iter)->getWriteDesc(), &rfds) ) + mWriteable.push_back(*iter); } - return( nFound ); + return nFound; } -const Select::CommsList &Select::getReadable() const -{ - return( mReadable ); +const Select::CommsList &Select::getReadable() const { + return mReadable; } -const Select::CommsList &Select::getWriteable() const -{ - return( mWriteable ); +const Select::CommsList &Select::getWriteable() const { + return mWriteable; } From 6da673dd698546097448b0f5af6968e825507029 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 21 Nov 2020 09:25:36 -0500 Subject: [PATCH 0674/2339] remove unused includes --- src/zm_eventstream.cpp | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/zm_eventstream.cpp b/src/zm_eventstream.cpp index 2c8ec7c08..a60723d86 100644 --- a/src/zm_eventstream.cpp +++ b/src/zm_eventstream.cpp @@ -1,5 +1,5 @@ // -// ZoneMinder Event Class Implementation, $Date$, $Revision$ +// ZoneMinder Event Stream Class Implementation // Copyright (C) 2001-2008 Philip Coombes // // This program is free software; you can redistribute it and/or @@ -16,24 +16,13 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // - -#include -#include +// #include -#include -#include -#include -#include -#include -#include -#include -#include #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_eventstream.h" #include "zm_storage.h" From b44f14691e8cfe2776a8f91e8cd345948c32430d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 21 Nov 2020 15:08:09 -0500 Subject: [PATCH 0675/2339] Don't exit after 30 minutes. Google code style. --- scripts/zmcontrol.pl.in | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/scripts/zmcontrol.pl.in b/scripts/zmcontrol.pl.in index 32c1132d6..474148df3 100644 --- a/scripts/zmcontrol.pl.in +++ b/scripts/zmcontrol.pl.in @@ -162,24 +162,24 @@ if ( $options{command} ) { listen(SERVER, SOMAXCONN) or Fatal("Can't listen: $!"); my $rin = ''; - vec( $rin, fileno(SERVER), 1 ) = 1; + vec($rin, fileno(SERVER), 1) = 1; my $win = $rin; my $ein = $win; my $timeout = MAX_COMMAND_WAIT; - while( 1 ) { + while ( 1 ) { my $nfound = select(my $rout = $rin, undef, undef, $timeout); if ( $nfound > 0 ) { - if ( vec( $rout, fileno(SERVER), 1 ) ) { + if ( vec($rout, fileno(SERVER), 1) ) { my $paddr = accept(CLIENT, SERVER); my $message = ; + close(CLIENT); next if !$message; my $params = jsonDecode($message); - Debug( Dumper( $params ) ); + Debug(Dumper($params)); my $command = $params->{command}; - close(CLIENT); if ( $command eq 'quit' ) { last; } elsif ( $command ) { @@ -192,7 +192,7 @@ if ( $options{command} ) { } } elsif ( $nfound < 0 ) { if ( $! == EINTR ) { - # Likely just SIGHUP + # Likely just SIGHUP Debug("Can't select: $!"); } elsif ( $! == EPIPE ) { Error("Can't select: $!"); @@ -200,17 +200,14 @@ if ( $options{command} ) { Fatal("Can't select: $!"); } } else { - #print( "Select timed out\n" ); - last; + Debug('Select timed out'); } } # end while forever Info("Control server $id/$protocol exiting"); unlink($sock_file); $control->close(); - exit(0); } # end if !server up - exit(0); 1; From 30363c1d4be207f95c7c6c70362c5140f4534b75 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 21 Nov 2020 15:08:29 -0500 Subject: [PATCH 0676/2339] Add Monitor Status loading --- scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm b/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm index 80b4fb75a..bbcb5af71 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm @@ -32,6 +32,7 @@ require ZoneMinder::Base; require ZoneMinder::Object; require ZoneMinder::Storage; require ZoneMinder::Server; +require ZoneMinder::Monitor_Status; #our @ISA = qw(Exporter ZoneMinder::Base); use parent qw(ZoneMinder::Object); @@ -245,6 +246,14 @@ sub control { } } # end sub control +sub Status { + my $self = shift; + $$self{Status} = shift if @_; + if ( ! $$self{Status} ) { + $$self{Status} = ZoneMinder::Monitor_Status->find_one(MonitorId=>$$self{Id}); + } + return $$self{Status}; +} 1; __END__ From 98c2c6cccfef7d0105b97941ddbff7528b07cf39 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 21 Nov 2020 15:09:43 -0500 Subject: [PATCH 0677/2339] Add Status,CaptureFPS,AnalysisFPS, CaptureBandWidth to MonitorStatus fields --- scripts/ZoneMinder/lib/ZoneMinder/Monitor_Status.pm | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Monitor_Status.pm b/scripts/ZoneMinder/lib/ZoneMinder/Monitor_Status.pm index 059c38121..9a9077653 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Monitor_Status.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Monitor_Status.pm @@ -39,6 +39,10 @@ $table = 'Monitor_Status'; $serial = $primary_key = 'MonitorId'; %fields = map { $_ => $_ } qw( MonitorId + Status + CaptureFPS + AnalysisFPS + CaptureBandwidth TotalEvents TotalEventDiskSpace HourEvents @@ -54,6 +58,10 @@ $serial = $primary_key = 'MonitorId'; ); %defaults = ( + Status => 'Unknown', + CaptureFPS => undef, + AnalysisFPS => undef, + CaptureBandwidth => undef, TotalEvents => undef, TotalEventDiskSpace => undef, HourEvents => undef, From 51ebaecc44ba1d00e1499621f2cb438609fe6e5d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 21 Nov 2020 15:10:23 -0500 Subject: [PATCH 0678/2339] Fix MN and the various Event Total substitutions --- scripts/zmfilter.pl.in | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/scripts/zmfilter.pl.in b/scripts/zmfilter.pl.in index b2dd7a2b4..38873e348 100644 --- a/scripts/zmfilter.pl.in +++ b/scripts/zmfilter.pl.in @@ -656,9 +656,11 @@ sub substituteTags { # First we'd better check what we need to get # We have a filter and an event, do we need any more # monitor information? - my $need_monitor = $text =~ /%(?:MET|MEH|MED|MEW|MEN|MEA)%/; + my $need_monitor = $text =~ /%(?:MN|MET|MEH|MED|MEW|MEN|MEA)%/; + my $need_status = $text =~ /%(?:MET|MEH|MED|MEW|MEN|MEA)%/; my $Monitor = $Event->Monitor() if $need_monitor; + my $Status = $Monitor->Status() if $need_status; # Do we need the image information too? my $need_images = $text =~ /%(?:EPI1|EPIM|EI1|EIM|EI1A|EIMA|EIMOD)%/; @@ -688,13 +690,13 @@ sub substituteTags { my $url = $Config{ZM_URL}; $text =~ s/%ZP%/$url/g; - $text =~ s/%MN%/$Event->{MonitorName}/g; - $text =~ s/%MET%/$Monitor->{TotalEvents}/g; - $text =~ s/%MEH%/$Monitor->{HourEvents}/g; - $text =~ s/%MED%/$Monitor->{DayEvents}/g; - $text =~ s/%MEW%/$Monitor->{WeekEvents}/g; - $text =~ s/%MEM%/$Monitor->{MonthEvents}/g; - $text =~ s/%MEA%/$Monitor->{ArchivedEvents}/g; + $text =~ s/%MN%/$Monitor->{Name}/g; + $text =~ s/%MET%/$Status->{TotalEvents}/g; + $text =~ s/%MEH%/$Status->{HourEvents}/g; + $text =~ s/%MED%/$Status->{DayEvents}/g; + $text =~ s/%MEW%/$Status->{WeekEvents}/g; + $text =~ s/%MEM%/$Status->{MonthEvents}/g; + $text =~ s/%MEA%/$Status->{ArchivedEvents}/g; $text =~ s/%MP%/$url?view=watch&mid=$Event->{MonitorId}/g; $text =~ s/%MPS%/$url?view=watch&mid=$Event->{MonitorId}&mode=stream/g; $text =~ s/%MPI%/$url?view=watch&mid=$Event->{MonitorId}&mode=still/g; From 1b472edc2b7507720516121eabe58a4223a284bf Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 21 Nov 2020 16:58:22 -0500 Subject: [PATCH 0679/2339] fix cast --- src/zm_buffer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/zm_buffer.cpp b/src/zm_buffer.cpp index be20c008e..76d11d969 100644 --- a/src/zm_buffer.cpp +++ b/src/zm_buffer.cpp @@ -38,8 +38,8 @@ unsigned int Buffer::expand(unsigned int count) { int headSpace = mHead - mStorage; int tailSpace = spare - headSpace; int width = mTail - mHead; - if ( spare > static_castcount ) { - if ( tailSpace < static_castcount ) { + if ( spare > static_cast(count) ) { + if ( tailSpace < static_cast(count) ) { memmove(mStorage, mHead, mSize); mHead = mStorage; mTail = mHead + width; From 4d8f45d284a522f54a862824c81d6597582f2f60 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 21 Nov 2020 16:59:21 -0500 Subject: [PATCH 0680/2339] There is no need to copy query. We do not modify it. --- src/zms.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/zms.cpp b/src/zms.cpp index 38917a388..8ecaf4e36 100644 --- a/src/zms.cpp +++ b/src/zms.cpp @@ -102,9 +102,7 @@ int main(int argc, const char *argv[], char **envp) { Debug(1, "Query: %s", query); - char temp_query[1024]; - strncpy(temp_query, query, sizeof(temp_query)-1); - char *q_ptr = temp_query; + char *q_ptr = (char *)query; char *parms[16]; // Shouldn't be more than this int parm_no = 0; while ( (parm_no < 16) && (parms[parm_no] = strtok(q_ptr, "&")) ) { From 660636c0e2763571704486bcf9694978fd1e5d62 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 22 Nov 2020 16:54:42 -0500 Subject: [PATCH 0681/2339] loop if we get egain when flocking. Warn when format not specified. --- src/zm_fifo.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/zm_fifo.cpp b/src/zm_fifo.cpp index 577281890..bf1ac5484 100644 --- a/src/zm_fifo.cpp +++ b/src/zm_fifo.cpp @@ -206,7 +206,6 @@ void FifoStream::setStreamStart(const char * path) { void FifoStream::setStreamStart(int monitor_id, const char * format) { char diag_path[PATH_MAX]; - const char * filename; Monitor * monitor = Monitor::Load(monitor_id, false, Monitor::QUERY); if ( !strcmp(format, "reference") ) { @@ -218,6 +217,9 @@ void FifoStream::setStreamStart(int monitor_id, const char * format) { staticConfig.PATH_SOCKS.c_str(), monitor->Id()); stream_type = MJPEG; } else { + if ( strcmp(format, "raw") ) { + Warning("Unknown or unspecified format. Defaulting to raw"); + } snprintf(diag_path, sizeof(diag_path), "%s/dbgpipe-%d.log", staticConfig.PATH_SOCKS.c_str(), monitor->Id()); stream_type = RAW; @@ -245,13 +247,13 @@ void FifoStream::runStream() { return; } int res = flock(fd_lock, LOCK_EX | LOCK_NB); - while ( (res == EAGAIN) and (! zm_terminate) ) { + while ( (res < 0 and errno == EAGAIN) and (! zm_terminate) ) { Warning("Flocking problem on %s: - %s", lock_file, strerror(errno)); sleep(1); res = flock(fd_lock, LOCK_EX | LOCK_NB); } if ( res < 0 ) { - Error("Flocking problem on %s: - %s", lock_file, strerror(errno)); + Error("Flocking problem on %d != %d %s: - %s", EAGAIN, res, lock_file, strerror(errno)); close(fd_lock); return; } From e0a30ab5e0077fb2c4bf94fdbdb8ac1f1421ab1d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 22 Nov 2020 17:28:53 -0500 Subject: [PATCH 0682/2339] Only log an error if we haven't been given sigpipe. --- src/zm_fifo.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/zm_fifo.cpp b/src/zm_fifo.cpp index bf1ac5484..d743611b8 100644 --- a/src/zm_fifo.cpp +++ b/src/zm_fifo.cpp @@ -117,7 +117,8 @@ bool FifoStream::sendRAWFrames() { return false; } if ( fwrite(buffer, bytes_read, 1, stdout) != 1 ) { - Error("Problem during writing: %s", strerror(errno)); + if ( !zm_terminate ) + Error("Problem during writing: %s", strerror(errno)); close(fd); return false; } From 4deb3a8d845cd407538ed0ef4f46169493810e94 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 23 Nov 2020 19:31:21 -0500 Subject: [PATCH 0683/2339] escape the word Groups --- db/zm_update-1.31.5.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/zm_update-1.31.5.sql b/db/zm_update-1.31.5.sql index 859487e88..d315c8e84 100644 --- a/db/zm_update-1.31.5.sql +++ b/db/zm_update-1.31.5.sql @@ -10,7 +10,7 @@ SET @s = (SELECT IF( AND column_name = 'ParentId' ) > 0, "SELECT 'Column GroupId exists in Groups'", -"ALTER TABLE Groups ADD `ParentId` int(10) unsigned AFTER `Name`" +"ALTER TABLE `Groups` ADD `ParentId` int(10) unsigned AFTER `Name`" )); PREPARE stmt FROM @s; From be27630a8508f6e0517fb6e3b70832cdc694c5f2 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 23 Nov 2020 19:33:53 -0500 Subject: [PATCH 0684/2339] escape the word Groups --- db/zm_update-1.31.7.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/zm_update-1.31.7.sql b/db/zm_update-1.31.7.sql index 1221d9adb..0afd76ce5 100644 --- a/db/zm_update-1.31.7.sql +++ b/db/zm_update-1.31.7.sql @@ -3,7 +3,7 @@ SET @s = (SELECT IF( AND table_name = 'Groups' AND column_name = 'MonitorIds' ) > 0, - "ALTER TABLE Groups MODIFY `MonitorIds` text NOT NULL", + "ALTER TABLE `Groups` MODIFY `MonitorIds` text NOT NULL", "SELECT 'Groups no longer has MonitorIds'" )); From d6345d32fdec3f5e8ccb36a79bebc1cc50d37089 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 25 Nov 2020 09:53:06 -0500 Subject: [PATCH 0685/2339] Reduce error level of warnings about monitors having Function==NONE --- src/zm_stream.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/zm_stream.cpp b/src/zm_stream.cpp index 613e6c97e..98c08922d 100644 --- a/src/zm_stream.cpp +++ b/src/zm_stream.cpp @@ -52,8 +52,9 @@ bool StreamBase::loadMonitor(int p_monitor_id) { Error("Unable to load monitor id %d for streaming", monitor_id); return false; } + if ( monitor->GetFunction() == Monitor::NONE ) { - Error("Monitor %d has function NONE. Will not be able to connect to it.", monitor_id); + Info("Monitor %d has function NONE. Will not be able to connect to it.", monitor_id); return false; } @@ -71,7 +72,7 @@ bool StreamBase::checkInitialised() { return false; } if ( monitor->GetFunction() == Monitor::NONE ) { - Error("Monitor %d has function NONE. Will not be able to connect to it.", monitor_id); + Info("Monitor %d has function NONE. Will not be able to connect to it.", monitor_id); return false; } if ( !monitor->ShmValid() ) { From ff4b0e6309b428ee8f5a08be595a240217b0d81b Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Wed, 25 Nov 2020 13:03:16 -0600 Subject: [PATCH 0686/2339] add option to disable thumb animation --- scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in | 13 +++++++++++++ web/skins/classic/views/js/console.js | 2 +- web/skins/classic/views/js/console.js.php | 1 + web/skins/classic/views/js/events.js | 2 +- web/skins/classic/views/js/events.js.php | 1 + web/skins/classic/views/js/frames.js | 2 +- web/skins/classic/views/js/frames.js.php | 1 + 7 files changed, 19 insertions(+), 3 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in index 98ed7fa69..bc194ebc9 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in @@ -2748,6 +2748,19 @@ our @options = ( requires => [ { name => 'ZM_WEB_LIST_THUMBS', value => 'yes' } ], category => 'web', }, + { + name => 'ZM_WEB_ANIMATE_THUMBS', + default => 'yes', + description => 'Enlarge and show the live stream when a thumbnail is hovered over', + help => q` + Enabling this option causes the static thumbnail, shown on certain + views, to enlarge and show the live stream, when the thumbnail is + hovered over by the mouse. + `, + type => $types{boolean}, + requires => [ { name => 'ZM_WEB_LIST_THUMBS', value => 'yes' } ], + category => 'web', + }, { name => 'ZM_WEB_USE_OBJECT_TAGS', default => 'yes', diff --git a/web/skins/classic/views/js/console.js b/web/skins/classic/views/js/console.js index 52b7aedc2..5ef7029f3 100644 --- a/web/skins/classic/views/js/console.js +++ b/web/skins/classic/views/js/console.js @@ -204,7 +204,7 @@ function initPage() { } ); // Setup the thumbnail video animation - initThumbAnimation(); + if ( WEB_ANIMATE_THUMBS ) initThumbAnimation(); $j('.functionLnk').click(manageFunctionModal); } // end function initPage diff --git a/web/skins/classic/views/js/console.js.php b/web/skins/classic/views/js/console.js.php index 9f5355dc6..c5a7f5e92 100644 --- a/web/skins/classic/views/js/console.js.php +++ b/web/skins/classic/views/js/console.js.php @@ -1,4 +1,5 @@ var consoleRefreshTimeout = ; +var WEB_ANIMATE_THUMBS = ; "; var yesString = ""; var noString = ""; var WEB_LIST_THUMBS = ; +var WEB_ANIMATE_THUMBS = ; diff --git a/web/skins/classic/views/js/frames.js b/web/skins/classic/views/js/frames.js index c569d8447..4594ed392 100644 --- a/web/skins/classic/views/js/frames.js +++ b/web/skins/classic/views/js/frames.js @@ -82,7 +82,7 @@ function initPage() { backBtn.prop('disabled', !document.referrer.length); // Setup the thumbnail animation - initThumbAnimation(); + if ( WEB_ANIMATE_THUMBS ) initThumbAnimation(); // Some toolbar events break the thumbnail animation, so re-init eventlistener table.on('all.bs.table', initThumbAnimation); diff --git a/web/skins/classic/views/js/frames.js.php b/web/skins/classic/views/js/frames.js.php index e8aa37a4d..b27e1e5ec 100644 --- a/web/skins/classic/views/js/frames.js.php +++ b/web/skins/classic/views/js/frames.js.php @@ -1,2 +1,3 @@ var eid = ; var WEB_LIST_THUMBS = ; +var WEB_ANIMATE_THUMBS = ; From 28614ce7039f665ae2db6504589be5db385b5536 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Wed, 25 Nov 2020 13:16:11 -0600 Subject: [PATCH 0687/2339] change where we check for web_animate_thumbs --- web/skins/classic/views/js/console.js | 12 +++++++----- web/skins/classic/views/js/events.js | 12 +++++++----- web/skins/classic/views/js/frames.js | 12 +++++++----- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/web/skins/classic/views/js/console.js b/web/skins/classic/views/js/console.js index 5ef7029f3..1098635b8 100644 --- a/web/skins/classic/views/js/console.js +++ b/web/skins/classic/views/js/console.js @@ -11,10 +11,12 @@ function thumbnail_onmouseout(event) { } function initThumbAnimation() { - $j('.colThumbnail img').each(function() { - this.addEventListener('mouseover', thumbnail_onmouseover, false); - this.addEventListener('mouseout', thumbnail_onmouseout, false); - }); + if ( WEB_ANIMATE_THUMBS ) { + $j('.colThumbnail img').each(function() { + this.addEventListener('mouseover', thumbnail_onmouseover, false); + this.addEventListener('mouseout', thumbnail_onmouseout, false); + }); + } } function setButtonStates( element ) { @@ -204,7 +206,7 @@ function initPage() { } ); // Setup the thumbnail video animation - if ( WEB_ANIMATE_THUMBS ) initThumbAnimation(); + initThumbAnimation(); $j('.functionLnk').click(manageFunctionModal); } // end function initPage diff --git a/web/skins/classic/views/js/events.js b/web/skins/classic/views/js/events.js index 8300b7f73..6be2747d5 100644 --- a/web/skins/classic/views/js/events.js +++ b/web/skins/classic/views/js/events.js @@ -87,10 +87,12 @@ function thumbnail_onmouseout(event) { } function initThumbAnimation() { - $j('.colThumbnail img').each(function() { - this.addEventListener('mouseover', thumbnail_onmouseover, false); - this.addEventListener('mouseout', thumbnail_onmouseout, false); - }); + if ( WEB_ANIMATE_THUMBS ) { + $j('.colThumbnail img').each(function() { + this.addEventListener('mouseover', thumbnail_onmouseover, false); + this.addEventListener('mouseout', thumbnail_onmouseout, false); + }); + } } // Returns the event id's of the selected rows @@ -195,7 +197,7 @@ function initPage() { backBtn.prop('disabled', !document.referrer.length); // Setup the thumbnail video animation - if ( WEB_ANIMATE_THUMBS ) initThumbAnimation(); + initThumbAnimation(); // Some toolbar events break the thumbnail animation, so re-init eventlistener table.on('all.bs.table', initThumbAnimation); diff --git a/web/skins/classic/views/js/frames.js b/web/skins/classic/views/js/frames.js index 4594ed392..cb09d1952 100644 --- a/web/skins/classic/views/js/frames.js +++ b/web/skins/classic/views/js/frames.js @@ -39,10 +39,12 @@ function thumbnail_onmouseout(event) { } function initThumbAnimation() { - $j('.colThumbnail img').each(function() { - this.addEventListener('mouseover', thumbnail_onmouseover, false); - this.addEventListener('mouseout', thumbnail_onmouseout, false); - }); + if ( WEB_ANIMATE_THUMBS ) { + $j('.colThumbnail img').each(function() { + this.addEventListener('mouseover', thumbnail_onmouseover, false); + this.addEventListener('mouseout', thumbnail_onmouseout, false); + }); + } } function processClicks(event, field, value, row, $element) { @@ -82,7 +84,7 @@ function initPage() { backBtn.prop('disabled', !document.referrer.length); // Setup the thumbnail animation - if ( WEB_ANIMATE_THUMBS ) initThumbAnimation(); + initThumbAnimation(); // Some toolbar events break the thumbnail animation, so re-init eventlistener table.on('all.bs.table', initThumbAnimation); From 08dabf1a4f530ad32bf8ce6cb248ab73c8bd4f0f Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Wed, 25 Nov 2020 13:29:14 -0600 Subject: [PATCH 0688/2339] don't add "zoom" class when thumb animation is off --- web/skins/classic/views/console.php | 3 ++- web/skins/classic/views/js/events.js | 3 ++- web/skins/classic/views/js/frames.js | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index 11c1e12ad..3a736529c 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -296,6 +296,7 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { $imgHTML=''; if ( ZM_WEB_LIST_THUMBS && ($monitor['Status'] == 'Connected') && $running ) { $options = array(); + $thmbClass = ZM_WEB_ANIMATE_THUMBS ? 'colThumbnail zoom-right' : 'colThumbnail'; $ratio_factor = $Monitor->ViewHeight() / $Monitor->ViewWidth(); $options['width'] = ZM_WEB_LIST_THUMB_WIDTH; $options['height'] = ZM_WEB_LIST_THUMB_HEIGHT ? ZM_WEB_LIST_THUMB_HEIGHT : ZM_WEB_LIST_THUMB_WIDTH*$ratio_factor; @@ -308,7 +309,7 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { $thmbWidth = ( $options['width'] ) ? 'width:'.$options['width'].'px;' : ''; $thmbHeight = ( $options['height'] ) ? 'height:'.$options['height'].'px;' : ''; - $imgHTML = '
' : '>'; $imgHTML .= ' Date: Thu, 26 Nov 2020 17:00:05 -0600 Subject: [PATCH 0689/2339] deploy bstable to watch view --- web/skins/classic/views/js/watch.js | 348 +++++++++++----------------- web/skins/classic/views/watch.php | 43 +++- 2 files changed, 171 insertions(+), 220 deletions(-) diff --git a/web/skins/classic/views/js/watch.js b/web/skins/classic/views/js/watch.js index feea5e698..337d36081 100644 --- a/web/skins/classic/views/js/watch.js +++ b/web/skins/classic/views/js/watch.js @@ -1,7 +1,89 @@ +var streamStatus; +var auth_hash; +var alarmState = STATE_IDLE; +var lastAlarmState = STATE_IDLE; var backBtn = $j('#backBtn'); var settingsBtn = $j('#settingsBtn'); var enableAlmBtn = $j('#enableAlmBtn'); var forceAlmBtn = $j('#forceAlmBtn'); +var table = $j('#eventList'); + +if ( monitorType != 'WebSite' ) { + var streamCmdParms = 'view=request&request=stream&connkey='+connKey; + if ( auth_hash ) { + streamCmdParms += '&auth='+auth_hash; + } + var streamCmdReq = new Request.JSON( { + url: monitorUrl, + method: 'get', + timeout: AJAX_TIMEOUT, + link: 'chain', + onError: getStreamCmdError, + onSuccess: getStreamCmdResponse, + onFailure: getStreamCmdFailure + } ); + var streamCmdTimer = null; +} + +/* +This is the format of the json object sent by bootstrap-table + +var params = +{ +"type":"get", +"data": + { + "search":"some search text", + "sort":"StartDateTime", + "order":"asc", + "offset":0, + "limit":25 + "filter": + { + "Name":"some advanced search text" + "StartDateTime":"some more advanced search text" + } + }, +"cache":true, +"contentType":"application/json", +"dataType":"json" +}; +*/ + +// Called by bootstrap-table to retrieve zm event data +function ajaxRequest(params) { + // Maintain legacy behavior of sorting by Id column only + delete params.data.order; + delete params.data.limit; + params.data.sort = 'Id desc'; + params.data.count = maxDisplayEvents; + params.data.id = monitorId; + if ( auth_hash ) params.data.auth = auth_hash; + + $j.getJSON(thisUrl + '?view=request&request=status&entity=events', params.data) + .done(function(data) { + var rows = processRows(data.events); + // rearrange the result into what bootstrap-table expects + params.success({total: data.total, totalNotFiltered: data.totalNotFiltered, rows: rows}); + }) + .fail(logAjaxFail); +} + +function processRows(rows) { + $j.each(rows, function(ndx, row) { + var eid = row.Id; + var filterQuery = '&filter[Query][terms][0][attr]=MonitorId&filter[Query][terms][0][op]=%3d&filter[Query][terms][0][val]='+monitorId; + + row.Id = '' + eid + ''; + row.Name = '' + row.Name + ''; + row.Frames = '' + row.Frames + ''; + row.AlarmFrames = '' + row.AlarmFrames + ''; + row.MaxScore = '' + row.MaxScore + ''; + row.Delete = ''; + }); + + return rows; +} function showEvents() { $('ptzControls').addClass('hidden'); @@ -56,9 +138,6 @@ function changeScale() { } } -var alarmState = STATE_IDLE; -var lastAlarmState = STATE_IDLE; - function setAlarmState( currentAlarmState ) { alarmState = currentAlarmState; @@ -103,39 +182,22 @@ function setAlarmState( currentAlarmState ) { $('MediaPlayer').Stop(); } } - eventCmdQuery(); + table.bootstrapTable('refresh'); } lastAlarmState = alarmState; } // end function setAlarmState( currentAlarmState ) -if ( monitorType != 'WebSite' ) { - var streamCmdParms = 'view=request&request=stream&connkey='+connKey; - if ( auth_hash ) { - streamCmdParms += '&auth='+auth_hash; - } - var streamCmdReq = new Request.JSON( { - url: monitorUrl, - method: 'get', - timeout: AJAX_TIMEOUT, - link: 'chain', - onError: getStreamCmdError, - onSuccess: getStreamCmdResponse, - onFailure: getStreamCmdFailure - } ); - var streamCmdTimer = null; -} - -var streamStatus; - function getStreamCmdError(text, error) { console.log(error); // Error are normally due to failed auth. reload the page. window.location.reload(); } + function getStreamCmdFailure(xhr) { console.log(xhr); } + function getStreamCmdResponse(respObj, respText) { watchdogOk('stream'); if ( streamCmdTimer ) { @@ -233,7 +295,7 @@ function getStreamCmdResponse(respObj, respText) { } streamCmdParms = streamCmdParms.replace(/auth=\w+/i, 'auth='+streamStatus.auth); statusCmdParms = statusCmdParms.replace(/auth=\w+/i, 'auth='+streamStatus.auth); - eventCmdParms = eventCmdParms.replace(/auth=\w+/i, 'auth='+streamStatus.auth); + table.bootstrapTable('refresh'); controlParms = controlParms.replace(/auth=\w+/i, 'auth='+streamStatus.auth); } // end if have a new auth hash } // end if respObj.status @@ -503,187 +565,6 @@ function cmdForce() { } } -function getActResponse( respObj, respText ) { - if ( respObj.result == 'Ok' ) { - if ( respObj.refreshParent && window.opener ) { - console.log('refreshing parent'); - window.opener.location.reload(); - } - } - eventCmdQuery(); -} - -function deleteEvent(event, eventId) { - var actParms = 'view=request&request=event&action=delete&id='+eventId; - if ( auth_hash ) { - actParms += '&auth='+auth_hash; - } - var actReq = new Request.JSON( { - url: thisUrl, - method: 'post', - timeout: 3000, - onSuccess: getActResponse - } ); - actReq.send(actParms); - event.stop(); -} - -if ( monitorType != 'WebSite' ) { - var eventCmdParms = "view=request&request=status&entity=events&id="+monitorId+"&count="+maxDisplayEvents+"&sort=Id%20desc"; - if ( auth_hash ) { - eventCmdParms += '&auth='+auth_hash; - } - var eventCmdReq = new Request.JSON( { - url: monitorUrl, - method: 'get', - timeout: AJAX_TIMEOUT, - link: 'cancel', - onSuccess: getEventCmdResponse, - onTimeout: eventCmdQuery - } ); - var eventCmdTimer = null; - var eventCmdFirst = true; -} - -function highlightRow( row ) { - $(row).toggleClass('highlight'); -} - -function getEventCmdResponse( respObj, respText ) { - watchdogOk('event'); - if ( eventCmdTimer ) { - eventCmdTimer = clearTimeout(eventCmdTimer); - } - - if ( respObj.result == 'Ok' ) { - var dbEvents = respObj.events.reverse(); - var eventList = $('eventList'); - var eventListBody = $(eventList).getElement('tbody'); - var eventListRows = $(eventListBody).getElements('tr'); - - eventListRows.each( function(row) { - row.removeClass('updated'); - } ); - - for ( var i = 0; i < dbEvents.length; i++ ) { - var zm_event = dbEvents[i]; - var row = $('event'+zm_event.Id); - var newEvent = (row == null ? true : false); - if ( newEvent ) { - row = new Element('tr', {'id': 'event'+zm_event.Id}); - new Element('td', {'class': 'colId'}).inject(row); - new Element('td', {'class': 'colName'}).inject(row); - new Element('td', {'class': 'colTime'}).inject(row); - new Element('td', {'class': 'colSecs'}).inject(row); - new Element('td', {'class': 'colFrames'}).inject(row); - new Element('td', {'class': 'colScore'}).inject(row); - new Element('td', {'class': 'colDelete'}).inject(row); - - var link = new Element('a', { - 'href': '#', - 'events': { - 'click': openEvent.pass( [ - zm_event.Id, - '&filter[Query][terms][0][attr]=MonitorId&filter[Query][terms][0][op]=%3d&filter[Query][terms][0][val]='+monitorId+'&page=1' - ] ) - } - }); - link.set('text', zm_event.Id); - link.inject(row.getElement('td.colId')); - - link = new Element('a', { - 'href': '#', - 'events': { - 'click': openEvent.pass( [ - zm_event.Id, - '&filter[Query][terms][0][attr]=MonitorId&filter[Query][terms][0][op]=%3d&filter[Query][terms][0][val]='+monitorId+'&page=1' - ] ) - } - }); - link.set('text', zm_event.Name); - link.inject(row.getElement('td.colName')); - - row.getElement('td.colTime').set('text', zm_event.StartDateTime); - row.getElement('td.colSecs').set('text', zm_event.Length); - - link = new Element('a', {'href': '#', 'events': {'click': openFrames.pass( [zm_event.Id] )}}); - link.set('text', zm_event.Frames+'/'+zm_event.AlarmFrames); - link.inject(row.getElement('td.colFrames')); - - link = new Element('a', {'href': '#', 'events': {'click': openFrame.pass( [zm_event.Id, '0'] )}}); - link.set('text', zm_event.AvgScore+'/'+zm_event.MaxScore); - link.inject(row.getElement('td.colScore')); - - link = new Element('button', { - 'type': 'button', - 'title': deleteString, - 'data-event-id': zm_event.Id, - 'events': { - 'click': function(e) { - var event_id = e.target.getAttribute('data-event-id'); - if ( !event_id ) { - console.log('No event id in deleteEvent'); - console.log(e); - } else { - deleteEvent(e, event_id); - } - }, - 'mouseover': highlightRow.pass(row), - 'mouseout': highlightRow.pass(row) - } - }); - link.set('text', 'X'); - link.inject(row.getElement('td.colDelete')); - - if ( i == 0 ) { - row.inject($(eventListBody)); - } else { - row.inject($(eventListBody), 'top'); - if ( !eventCmdFirst ) { - row.addClass('recent'); - } - } - } else { - row.getElement('td.colName a').set('text', zm_event.Name); - row.getElement('td.colSecs').set('text', zm_event.Length); - row.getElement('td.colFrames a').set('text', zm_event.Frames+'/'+zm_event.AlarmFrames); - row.getElement('td.colScore a').set('text', zm_event.AvgScore+'/'+zm_event.MaxScore); - row.removeClass('recent'); - } - row.addClass('updated'); - } // end foreach event - - var rows = $(eventListBody).getElements('tr'); - for ( var i = 0; i < rows.length; i++ ) { - if ( !rows[i].hasClass('updated') ) { - rows[i].destroy(); - rows.splice( i, 1 ); - i--; - } - } - while ( rows.length > maxDisplayEvents ) { - rows[rows.length-1].destroy(); - rows.length--; - } - } else { - checkStreamForErrors('getEventCmdResponse', respObj); - } // end if objresult == ok - - var eventCmdTimeout = eventsRefreshTimeout; - if ( alarmState == STATE_ALARM || alarmState == STATE_ALERT ) { - eventCmdTimeout = eventCmdTimeout/5; - } - eventCmdTimer = eventCmdQuery.delay(eventCmdTimeout); - eventCmdFirst = false; -} - -function eventCmdQuery() { - if ( eventCmdTimer ) { // avoid firing another if we are firing one - eventCmdTimer = clearTimeout(eventCmdTimer); - } - eventCmdReq.send(eventCmdParms); -} - if ( monitorType != 'WebSite' ) { var controlParms = 'view=request&request=control&id='+monitorId; if ( auth_hash ) { @@ -802,14 +683,12 @@ function appletRefresh() { var watchdogInactive = { 'stream': false, - 'status': false, - 'event': false + 'status': false }; var watchdogFunctions = { 'stream': streamCmdQuery, 'status': statusCmdQuery, - 'event': eventCmdQuery }; //Make sure the various refreshes are still taking effect @@ -872,6 +751,44 @@ function getSettingsModal() { .fail(logAjaxFail); } +function processClicks(event, field, value, row, $element) { + if ( field == 'Delete' ) { + $j.getJSON(thisUrl + '?request=modal&modal=delconfirm') + .done(function(data) { + insertModalHtml('deleteConfirm', data.html); + manageDelConfirmModalBtns(); + $j('#deleteConfirm').data('eid', row.Id.replace(/(<([^>]+)>)/gi, '')); + $j('#deleteConfirm').modal('show'); + }) + .fail(logAjaxFail); + } +} + +// Manage the DELETE CONFIRMATION modal button +function manageDelConfirmModalBtns() { + document.getElementById("delConfirmBtn").addEventListener("click", function onDelConfirmClick(evt) { + if ( ! canEditEvents ) { + enoperm(); + return; + } + + var eid = $j('#deleteConfirm').data('eid'); + + evt.preventDefault(); + $j.getJSON(thisUrl + '?request=events&task=delete&eids[]='+eid) + .done( function(data) { + table.bootstrapTable('refresh'); + $j('#deleteConfirm').modal('hide'); + }) + .fail(logAjaxFail); + }); + + // Manage the CANCEL modal button + document.getElementById("delCancelBtn").addEventListener("click", function onDelCancelClick(evt) { + $j('#deleteConfirm').modal('hide'); + }); +} + function initPage() { if ( canViewControl ) { // Load the PTZ Preset modal into the DOM @@ -889,9 +806,6 @@ function initPage() { watchdogCheck.pass('stream').periodical(statusRefreshTimeout*2); } - eventCmdTimer = eventCmdQuery.delay( (Math.random()+0.1)*statusRefreshTimeout ); - watchdogCheck.pass('event').periodical(eventsRefreshTimeout*2); - if ( canStreamNative || (streamMode == 'single') ) { var streamImg = $('imageFeed').getElement('img'); if ( !streamImg ) { @@ -924,6 +838,7 @@ function initPage() { } else if ( monitorRefresh > 0 ) { setInterval(reloadWebSite, monitorRefresh*1000); } + // Manage the BACK button document.getElementById("backBtn").addEventListener("click", function onBackClick(evt) { evt.preventDefault(); @@ -948,6 +863,17 @@ function initPage() { // Only enable the settings button for local cameras settingsBtn.prop('disabled', !canViewControl); if ( monitorType != 'Local' ) settingsBtn.hide(); + + // Init the bootstrap-table + if ( monitorType != 'WebSite' ) table.bootstrapTable({icons: icons}); + + // Update table rows each time after new data is loaded + table.on('post-body.bs.table', function(data) { + $j('#eventList tr:contains("New Event")').addClass('recent'); + }); + + // Take appropriate action when the user clicks on a cell + table.on('click-cell.bs.table', processClicks); } // initPage // Kick everything off diff --git a/web/skins/classic/views/watch.php b/web/skins/classic/views/watch.php index a8b9f24bd..579f8b11e 100644 --- a/web/skins/classic/views/watch.php +++ b/web/skins/classic/views/watch.php @@ -159,21 +159,46 @@ if ( $showPtzControls ) { } if ( canView('Events') && ($monitor->Type() != 'WebSite') ) { ?> -
- + +
+
+ - - - - - - - + + + + + + + + + + + +
 
Date: Thu, 26 Nov 2020 19:28:25 -0600 Subject: [PATCH 0690/2339] eslint --- web/skins/classic/views/js/watch.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/web/skins/classic/views/js/watch.js b/web/skins/classic/views/js/watch.js index 337d36081..bff6246ea 100644 --- a/web/skins/classic/views/js/watch.js +++ b/web/skins/classic/views/js/watch.js @@ -754,13 +754,13 @@ function getSettingsModal() { function processClicks(event, field, value, row, $element) { if ( field == 'Delete' ) { $j.getJSON(thisUrl + '?request=modal&modal=delconfirm') - .done(function(data) { - insertModalHtml('deleteConfirm', data.html); - manageDelConfirmModalBtns(); - $j('#deleteConfirm').data('eid', row.Id.replace(/(<([^>]+)>)/gi, '')); - $j('#deleteConfirm').modal('show'); - }) - .fail(logAjaxFail); + .done(function(data) { + insertModalHtml('deleteConfirm', data.html); + manageDelConfirmModalBtns(); + $j('#deleteConfirm').data('eid', row.Id.replace(/(<([^>]+)>)/gi, '')); + $j('#deleteConfirm').modal('show'); + }) + .fail(logAjaxFail); } } From a6245d9e90be40d2d8d38f9c5351f1aaa1be5fa8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Nov 2020 13:27:51 -0500 Subject: [PATCH 0691/2339] Minor code style update --- src/zm_storage.cpp | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/zm_storage.cpp b/src/zm_storage.cpp index 4bba82bab..9eae26b85 100644 --- a/src/zm_storage.cpp +++ b/src/zm_storage.cpp @@ -26,25 +26,25 @@ #include #include -Storage::Storage() { +Storage::Storage() : id(0) { Warning("Instantiating default Storage Object. Should not happen."); - id = 0; strcpy(name, "Default"); if ( staticConfig.DIR_EVENTS[0] != '/' ) { // not using an absolute path. Make it one by appending ZM_PATH_WEB - snprintf( path, sizeof (path), "%s/%s", staticConfig.PATH_WEB.c_str( ), staticConfig.DIR_EVENTS.c_str() ); + snprintf(path, sizeof(path), "%s/%s", + staticConfig.PATH_WEB.c_str(), staticConfig.DIR_EVENTS.c_str()); } else { - strncpy(path, staticConfig.DIR_EVENTS.c_str(), sizeof(path)-1 ); + strncpy(path, staticConfig.DIR_EVENTS.c_str(), sizeof(path)-1); } scheme = MEDIUM; scheme_str = "Medium"; } -Storage::Storage( MYSQL_ROW &dbrow ) { +Storage::Storage(MYSQL_ROW &dbrow) { unsigned int index = 0; - id = atoi( dbrow[index++] ); - strncpy( name, dbrow[index++], sizeof(name)-1 ); - strncpy( path, dbrow[index++], sizeof(path)-1 ); + id = atoi(dbrow[index++]); + strncpy(name, dbrow[index++], sizeof(name)-1); + strncpy(path, dbrow[index++], sizeof(path)-1); type_str = std::string(dbrow[index++]); scheme_str = std::string(dbrow[index++]); if ( scheme_str == "Deep" ) { @@ -57,16 +57,15 @@ Storage::Storage( MYSQL_ROW &dbrow ) { } /* If a zero or invalid p_id is passed, then the old default path will be assumed. */ -Storage::Storage( unsigned int p_id ) { - id = 0; +Storage::Storage(unsigned int p_id) : id(p_id) { - if ( p_id ) { + if ( id ) { char sql[ZM_SQL_SML_BUFSIZ]; - snprintf(sql, sizeof(sql), "SELECT `Id`, `Name`, `Path`, `Type`, `Scheme` FROM `Storage` WHERE `Id`=%d", p_id); - Debug(2,"Loading Storage for %d using %s", p_id, sql ); + snprintf(sql, sizeof(sql), "SELECT `Id`, `Name`, `Path`, `Type`, `Scheme` FROM `Storage` WHERE `Id`=%u", id); + Debug(2, "Loading Storage for %u using %s", id, sql); zmDbRow dbrow; if ( !dbrow.fetch(sql) ) { - Error("Unable to load storage area for id %d: %s", p_id, mysql_error(&dbconn)); + Error("Unable to load storage area for id %d: %s", id, mysql_error(&dbconn)); } else { unsigned int index = 0; id = atoi(dbrow[index++]); @@ -81,17 +80,18 @@ Storage::Storage( unsigned int p_id ) { } else { scheme = SHALLOW; } - Debug(1, "Loaded Storage area %d '%s'", id, this->Name()); + Debug(1, "Loaded Storage area %d '%s'", id, name); } } if ( !id ) { if ( staticConfig.DIR_EVENTS[0] != '/' ) { // not using an absolute path. Make it one by appending ZM_PATH_WEB - snprintf(path, sizeof (path), "%s/%s", staticConfig.PATH_WEB.c_str(), staticConfig.DIR_EVENTS.c_str()); + snprintf(path, sizeof(path), "%s/%s", + staticConfig.PATH_WEB.c_str(), staticConfig.DIR_EVENTS.c_str()); } else { strncpy(path, staticConfig.DIR_EVENTS.c_str(), sizeof(path)-1); } - Debug(1,"No id passed to Storage constructor. Using default path %s instead", path); + Debug(1, "No id passed to Storage constructor. Using default path %s instead", path); strcpy(name, "Default"); scheme = MEDIUM; scheme_str = "Medium"; From 95cbc053fcd60fdd202bbd09405d6019d6a73f35 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Nov 2020 13:28:38 -0500 Subject: [PATCH 0692/2339] Try other storage areas if we fail to create event dir on the assigned area. --- src/zm_event.cpp | 200 +++++++++++++++++++++++++++++------------------ src/zm_event.h | 1 + 2 files changed, 127 insertions(+), 74 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index efd7d8bc6..7f0ae2031 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -78,8 +78,6 @@ Event::Event( start_time = now; } - Storage * storage = monitor->getStorage(); - scheme = storage->Scheme(); unsigned int state_id = 0; zmDbRow dbrow; @@ -87,8 +85,58 @@ Event::Event( state_id = atoi(dbrow[0]); } + Storage * storage = monitor->getStorage(); + if ( !SetPath(storage) ) { + // Try another + Warning("Failed creating event dir at %s", storage->Path()); + + std::string sql = stringtf("SELECT `Id` FROM `Storage` WHERE `Id` != %u", storage->Id()); + if ( monitor->ServerId() ) + sql += stringtf(" AND ServerId=%u", monitor->ServerId()); + + Debug(1, "%s", sql.c_str()); + storage = nullptr; + + MYSQL_RES *result = zmDbFetch(sql.c_str()); + if ( result ) { + for ( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++ ) { + storage = new Storage(atoi(dbrow[0])); + if ( SetPath(storage) ) + break; + delete storage; + storage = nullptr; + } // end foreach row of Storage + mysql_free_result(result); + result = nullptr; + } + if ( !storage ) { + Info("No valid local storage area found. Trying all other areas."); + // Try remote + std::string sql = "SELECT `Id` FROM `Storage` WHERE ServerId IS NULL"; + if ( monitor->ServerId() ) + sql += stringtf(" OR ServerId != %u", monitor->ServerId()); + + MYSQL_RES *result = zmDbFetch(sql.c_str()); + if ( result ) { + for ( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++ ) { + storage = new Storage(atoi(dbrow[0])); + if ( SetPath(storage) ) + break; + delete storage; + storage = nullptr; + } // end foreach row of Storage + mysql_free_result(result); + result = nullptr; + } + } + if ( !storage ) { + storage = new Storage(); + Warning("Failed to find a storage area to save events."); + } + } + Debug(1, "Using storage area at %s", path.c_str()); + char sql[ZM_SQL_MED_BUFSIZ]; - struct tm *stime = localtime(&start_time.tv_sec); snprintf(sql, sizeof(sql), "INSERT INTO Events " "( MonitorId, StorageId, Name, StartDateTime, Width, Height, Cause, Notes, StateId, Orientation, Videoed, DefaultVideo, SaveJPEGs, Scheme )" " VALUES ( %u, %u, 'New Event', from_unixtime( %ld ), %u, %u, '%s', '%s', %u, %d, %d, '%s', %d, '%s' )", @@ -116,7 +164,7 @@ Event::Event( db_mutex.unlock(); if ( untimedEvent ) { - Warning("Event %d has zero time, setting to current", id); + Warning("Event %" PRIu64 " has zero time, setting to current", id); } end_time.tv_sec = 0; frames = 0; @@ -124,77 +172,7 @@ Event::Event( tot_score = 0; max_score = 0; alarm_frame_written = false; - - std::string id_file; - - path = stringtf("%s/%d", storage->Path(), monitor->Id()); - // Try to make the Monitor Dir. Normally this would exist, but in odd cases might not. - if ( mkdir(path.c_str(), 0755) ) { - if ( errno != EEXIST ) - Error("Can't mkdir %s: %s", path.c_str(), strerror(errno)); - } - - if ( storage->Scheme() == Storage::DEEP ) { - - int dt_parts[6]; - dt_parts[0] = stime->tm_year-100; - dt_parts[1] = stime->tm_mon+1; - dt_parts[2] = stime->tm_mday; - dt_parts[3] = stime->tm_hour; - dt_parts[4] = stime->tm_min; - dt_parts[5] = stime->tm_sec; - - std::string date_path; - std::string time_path; - - for ( unsigned int i = 0; i < sizeof(dt_parts)/sizeof(*dt_parts); i++ ) { - path += stringtf("/%02d", dt_parts[i]); - - if ( mkdir(path.c_str(), 0755) ) { - // FIXME This should not be fatal. Should probably move to a different storage area. - if ( errno != EEXIST ) - Error("Can't mkdir %s: %s", path.c_str(), strerror(errno)); - } - if ( i == 2 ) - date_path = path; - } - time_path = stringtf("%02d/%02d/%02d", stime->tm_hour, stime->tm_min, stime->tm_sec); - - // Create event id symlink - id_file = stringtf("%s/.%" PRIu64, date_path.c_str(), id); - if ( symlink(time_path.c_str(), id_file.c_str()) < 0 ) - Error("Can't symlink %s -> %s: %s", id_file.c_str(), time_path.c_str(), strerror(errno)); - } else if ( storage->Scheme() == Storage::MEDIUM ) { - path += stringtf("/%04d-%02d-%02d", - stime->tm_year+1900, stime->tm_mon+1, stime->tm_mday - ); - if ( mkdir(path.c_str(), 0755) ) { - if ( errno != EEXIST ) - Error("Can't mkdir %s: %s", path.c_str(), strerror(errno)); - } - path += stringtf("/%" PRIu64, id); - if ( mkdir(path.c_str(), 0755) ) { - if ( errno != EEXIST ) - Error("Can't mkdir %s: %s", path.c_str(), strerror(errno)); - } - } else { - path += stringtf("/%" PRIu64, id); - if ( mkdir(path.c_str(), 0755) ) { - if ( errno != EEXIST ) - Error("Can't mkdir %s: %s", path.c_str(), strerror(errno)); - } - - // Create empty id tag file - id_file = stringtf("%s/.%" PRIu64, path.c_str(), id); - if ( FILE *id_fp = fopen(id_file.c_str(), "w") ) { - fclose(id_fp); - } else { - Error("Can't fopen %s: %s", id_file.c_str(), strerror(errno)); - } - } // deep storage or not - last_db_frame = 0; - video_name = ""; snapshot_file = path + "/snapshot.jpg"; @@ -739,3 +717,77 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a end_time = timestamp; } // end void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *alarm_image) + +bool Event::SetPath(Storage *storage) { + scheme = storage->Scheme(); + + path = stringtf("%s/%d", storage->Path(), monitor->Id()); + // Try to make the Monitor Dir. Normally this would exist, but in odd cases might not. + if ( mkdir(path.c_str(), 0755) and ( errno != EEXIST ) ) { + Error("Can't mkdir %s: %s", path.c_str(), strerror(errno)); + return false; + } + + struct tm *stime = localtime(&start_time.tv_sec); + if ( scheme == Storage::DEEP ) { + + int dt_parts[6]; + dt_parts[0] = stime->tm_year-100; + dt_parts[1] = stime->tm_mon+1; + dt_parts[2] = stime->tm_mday; + dt_parts[3] = stime->tm_hour; + dt_parts[4] = stime->tm_min; + dt_parts[5] = stime->tm_sec; + + std::string date_path; + std::string time_path; + + for ( unsigned int i = 0; i < sizeof(dt_parts)/sizeof(*dt_parts); i++ ) { + path += stringtf("/%02d", dt_parts[i]); + + if ( mkdir(path.c_str(), 0755) and ( errno != EEXIST ) ) { + Error("Can't mkdir %s: %s", path.c_str(), strerror(errno)); + return false; + } + if ( i == 2 ) + date_path = path; + } + time_path = stringtf("%02d/%02d/%02d", stime->tm_hour, stime->tm_min, stime->tm_sec); + + // Create event id symlink + std::string id_file = stringtf("%s/.%" PRIu64, date_path.c_str(), id); + if ( symlink(time_path.c_str(), id_file.c_str()) < 0 ) { + Error("Can't symlink %s -> %s: %s", id_file.c_str(), time_path.c_str(), strerror(errno)); + return false; + } + } else if ( scheme == Storage::MEDIUM ) { + path += stringtf("/%04d-%02d-%02d", + stime->tm_year+1900, stime->tm_mon+1, stime->tm_mday + ); + if ( mkdir(path.c_str(), 0755) and ( errno != EEXIST ) ) { + Error("Can't mkdir %s: %s", path.c_str(), strerror(errno)); + return false; + } + path += stringtf("/%" PRIu64, id); + if ( mkdir(path.c_str(), 0755) and ( errno != EEXIST ) ) { + Error("Can't mkdir %s: %s", path.c_str(), strerror(errno)); + return false; + } + } else { + path += stringtf("/%" PRIu64, id); + if ( mkdir(path.c_str(), 0755) and ( errno != EEXIST ) ) { + Error("Can't mkdir %s: %s", path.c_str(), strerror(errno)); + return false; + } + + // Create empty id tag file + std::string id_file = stringtf("%s/.%" PRIu64, path.c_str(), id); + if ( FILE *id_fp = fopen(id_file.c_str(), "w") ) { + fclose(id_fp); + } else { + Error("Can't fopen %s: %s", id_file.c_str(), strerror(errno)); + return false; + } + } // deep storage or not + return true; +} // end bool Event::SetPath diff --git a/src/zm_event.h b/src/zm_event.h index ab837658e..e8e1e567e 100644 --- a/src/zm_event.h +++ b/src/zm_event.h @@ -133,6 +133,7 @@ class Event { void AddFramesInternal( int n_frames, int start_frame, Image **images, struct timeval **timestamps ); void WriteDbFrames(); void UpdateFramesDelta(double offset); + bool SetPath(Storage *storage); public: static const char *getSubPath( struct tm *time ) { From 3a943d6f09a94e9b94754a8293217cc636bfefb1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Nov 2020 13:29:05 -0500 Subject: [PATCH 0693/2339] Add ServerId method, code style --- src/zm_monitor.h | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 9a023d53a..e43f1dda0 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -430,29 +430,22 @@ public: return shared_data && shared_data->valid; } - inline unsigned int Id() const { - return id; - } - inline const char *Name() const { - return name; - } + inline unsigned int Id() const { return id; } + inline const char *Name() const { return name; } + inline unsigned int ServerId() { return server_id; } inline Storage *getStorage() { if ( ! storage ) { storage = new Storage( storage_id ); } return storage; } - inline Function GetFunction() const { - return( function ); - } + inline Function GetFunction() const { return function; } inline bool Enabled() const { if ( function <= MONITOR ) return false; return enabled; } - inline const char *EventPrefix() const { - return event_prefix; - } + inline const char *EventPrefix() const { return event_prefix; } inline bool Ready() const { if ( function <= MONITOR ) return false; @@ -463,9 +456,7 @@ public: return false; return( enabled && shared_data->active ); } - inline bool Exif() const { - return embed_exif; - } + inline bool Exif() const { return embed_exif; } Orientation getOrientation() const; unsigned int Width() const { return width; } From 80c4e2fa57b88000597074d914ec497981021c82 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Nov 2020 13:29:57 -0500 Subject: [PATCH 0694/2339] Fix table not being 100%. Use appropriate bootstrap style labels for radios --- web/ajax/modals/storage.php | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/web/ajax/modals/storage.php b/web/ajax/modals/storage.php index 70cc956dc..c439c384c 100644 --- a/web/ajax/modals/storage.php +++ b/web/ajax/modals/storage.php @@ -31,12 +31,11 @@ 'Shallow' => translate('Shallow'), ); - $servers = ZM\Server::find( null, array('order'=>'lower(Name)') ); + global $Servers; $ServersById = array(); - foreach ( $servers as $S ) { + foreach ( $Servers as $S ) { $ServersById[$S->Id()] = $S; } - ?>