From 3577a3e0a32a33ebe4f72e73403836abbc3459c3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 7 Jul 2017 20:02:02 -0400 Subject: [PATCH 01/23] 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 02/23] 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 03/23] 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 04/23] 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 05/23] 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 06/23] 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 07/23] 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 08/23] 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 c2fab6e959daa33ccb421772e67e2d392eb43b8f Mon Sep 17 00:00:00 2001 From: APHW2 MFGENG Date: Mon, 6 Nov 2017 07:31:08 -0800 Subject: [PATCH 09/23] add the options for nvsocket as an include --- .../classic/views/_monitor_source_nvsocket.html | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 web/skins/classic/views/_monitor_source_nvsocket.html diff --git a/web/skins/classic/views/_monitor_source_nvsocket.html b/web/skins/classic/views/_monitor_source_nvsocket.html new file mode 100644 index 000000000..2a1567dfe --- /dev/null +++ b/web/skins/classic/views/_monitor_source_nvsocket.html @@ -0,0 +1,14 @@ + + + + + + + + + () + () + +Orientation() );?> + + From 2ffa79172ad3e65b70f17a596783caddbc3fc279 Mon Sep 17 00:00:00 2001 From: APHW2 MFGENG Date: Mon, 6 Nov 2017 08:36:53 -0800 Subject: [PATCH 10/23] Only load Name,Value when loading config because that's all we use --- scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in index d2b444ef4..f69e95b18 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in @@ -115,7 +115,7 @@ BEGIN { , $Config{ZM_DB_USER} , $Config{ZM_DB_PASS} ) or croak( "Can't connect to db" ); - my $sql = 'select * from Config'; + my $sql = 'SELECT Name,Value FROM Config'; my $sth = $dbh->prepare_cached( $sql ) or croak( "Can't prepare '$sql': ".$dbh->errstr() ); my $res = $sth->execute() or croak( "Can't execute: ".$sth->errstr() ); while( my $config = $sth->fetchrow_hashref() ) { From e17bcb9178d079182eb73436fda390c453241a40 Mon Sep 17 00:00:00 2001 From: APHW2 MFGENG Date: Tue, 7 Nov 2017 18:21:51 -0800 Subject: [PATCH 11/23] updates for mast ffmpeg --- src/zm_ffmpeg.cpp | 2 + src/zm_ffmpeg_camera.cpp | 2 + src/zm_mpeg.cpp | 133 +++++++++++++------- src/zm_mpeg.h | 1 + src/zm_remote_camera.cpp | 1 + src/zm_remote_camera.h | 3 +- src/zm_remote_camera_nvsocket.cpp | 200 ++++++++---------------------- src/zm_remote_camera_nvsocket.h | 2 +- src/zm_sdp.cpp | 92 ++++++++------ src/zm_sdp.h | 18 +-- src/zm_videostore.cpp | 10 +- 11 files changed, 216 insertions(+), 248 deletions(-) diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index 4ba88d900..c9fe65e91 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -133,6 +133,7 @@ int av_dict_parse_string(AVDictionary **pm, const char *str, #endif // HAVE_LIBAVCODEC || HAVE_LIBAVUTIL || HAVE_LIBSWSCALE #if HAVE_LIBAVUTIL +#if LIBAVUTIL_VERSION_CHECK(56, 0, 0, 17, 100) int64_t av_rescale_delta(AVRational in_tb, int64_t in_ts, AVRational fs_tb, int duration, int64_t *last, AVRational out_tb){ int64_t a, b, this_thing; @@ -156,6 +157,7 @@ simple_round: return av_rescale_q(this_thing, fs_tb, out_tb); } #endif +#endif int hacked_up_context2_for_older_ffmpeg(AVFormatContext **avctx, AVOutputFormat *oformat, const char *format, const char *filename) { AVFormatContext *s = avformat_alloc_context(); diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index ee5437633..e6c3432fe 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -458,7 +458,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 ) { diff --git a/src/zm_mpeg.cpp b/src/zm_mpeg.cpp index e949052dc..2a7a24f87 100644 --- a/src/zm_mpeg.cpp +++ b/src/zm_mpeg.cpp @@ -211,39 +211,52 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei Debug( 1, "Allocated stream" ); - AVCodecContext *c = ost->codec; +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + codec_context = avcodec_alloc_context3(NULL); + avcodec_parameters_to_context(codec_context, ost->codecpar); +#else + codec_context = ost->codec; +#endif - c->codec_id = codec->id; - c->codec_type = codec->type; + codec_context->codec_id = codec->id; + codec_context->codec_type = codec->type; - c->pix_fmt = strcmp( "mjpeg", ofc->oformat->name ) == 0 ? AV_PIX_FMT_YUVJ422P : AV_PIX_FMT_YUV420P; + codec_context->pix_fmt = strcmp( "mjpeg", ofc->oformat->name ) == 0 ? AV_PIX_FMT_YUVJ422P : AV_PIX_FMT_YUV420P; if ( bitrate <= 100 ) { // Quality based bitrate control (VBR). Scale is 1..31 where 1 is best. // This gets rid of artifacts in the beginning of the movie; and well, even quality. - c->flags |= CODEC_FLAG_QSCALE; - c->global_quality = FF_QP2LAMBDA * (31 - (31 * (bitrate / 100.0))); +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + codec_context->flags |= AV_CODEC_FLAG_QSCALE; +#else + codec_context->flags |= CODEC_FLAG_QSCALE; +#endif + codec_context->global_quality = FF_QP2LAMBDA * (31 - (31 * (bitrate / 100.0))); } else { - c->bit_rate = bitrate; + codec_context->bit_rate = bitrate; } /* resolution must be a multiple of two */ - c->width = width; - c->height = height; + codec_context->width = width; + codec_context->height = height; /* time base: this is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented. for fixed-fps content, timebase should be 1/framerate and timestamp increments should be identically 1. */ - c->time_base.den = frame_rate; - c->time_base.num = 1; + codec_context->time_base.den = frame_rate; + codec_context->time_base.num = 1; - Debug( 1, "Will encode in %d fps.", c->time_base.den ); + Debug( 1, "Will encode in %d fps.", codec_context->time_base.den ); /* emit one intra frame every second */ - c->gop_size = frame_rate; + codec_context->gop_size = frame_rate; // some formats want stream headers to be separate if ( of->flags & AVFMT_GLOBALHEADER ) - c->flags |= CODEC_FLAG_GLOBAL_HEADER; +#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) + codec_context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; +#else + codec_context->flags |= CODEC_FLAG_GLOBAL_HEADER; +#endif } else { Fatal( "of->video_codec == AV_CODEC_ID_NONE" ); } @@ -278,13 +291,11 @@ void VideoStream::OpenStream( ) { /* now that all the parameters are set, we can open the video codecs and allocate the necessary encode buffers */ if ( ost ) { - AVCodecContext *c = ost->codec; - /* open the codec */ #if !LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 8, 0) - if ( (avRet = avcodec_open( c, codec )) < 0 ) + if ( (avRet = avcodec_open( codec_context, codec )) < 0 ) #else - if ( (avRet = avcodec_open2( c, codec, 0 )) < 0 ) + if ( (avRet = avcodec_open2( codec_context, codec, 0 )) < 0 ) #endif { Fatal( "Could not open codec. Error code %d \"%s\"", avRet, av_err2str( avRet ) ); @@ -293,19 +304,15 @@ void VideoStream::OpenStream( ) { Debug( 1, "Opened codec" ); /* allocate the encoded raw picture */ -#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) - opicture = av_frame_alloc( ); -#else - opicture = avcodec_alloc_frame( ); -#endif + opicture = zm_av_frame_alloc( ); if ( !opicture ) { Panic( "Could not allocate opicture" ); } #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) - int size = av_image_get_buffer_size( c->pix_fmt, c->width, c->height, 1 ); + int size = av_image_get_buffer_size( codec_context->pix_fmt, codec_context->width, codec_context->height, 1 ); #else - int size = avpicture_get_size( c->pix_fmt, c->width, c->height ); + int size = avpicture_get_size( codec_context->pix_fmt, codec_context->width, codec_context->height ); #endif uint8_t *opicture_buf = (uint8_t *)av_malloc( size ); @@ -315,17 +322,17 @@ void VideoStream::OpenStream( ) { } #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) av_image_fill_arrays(opicture->data, opicture->linesize, - opicture_buf, c->pix_fmt, c->width, c->height, 1); + opicture_buf, codec_context->pix_fmt, codec_context->width, codec_context->height, 1); #else - avpicture_fill( (AVPicture *)opicture, opicture_buf, c->pix_fmt, - c->width, c->height ); + avpicture_fill( (AVPicture *)opicture, opicture_buf, codec_context->pix_fmt, + codec_context->width, codec_context->height ); #endif /* if the output format is not identical to the input format, then a temporary picture is needed too. It is then converted to the required output format */ tmp_opicture = NULL; - if ( c->pix_fmt != pf ) { + if ( codec_context->pix_fmt != pf ) { #if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) tmp_opicture = av_frame_alloc( ); #else @@ -335,9 +342,9 @@ void VideoStream::OpenStream( ) { Panic( "Could not allocate tmp_opicture" ); } #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) - int size = av_image_get_buffer_size( pf, c->width, c->height,1 ); + int size = av_image_get_buffer_size( pf, codec_context->width, codec_context->height,1 ); #else - int size = avpicture_get_size( pf, c->width, c->height ); + int size = avpicture_get_size( pf, codec_context->width, codec_context->height ); #endif uint8_t *tmp_opicture_buf = (uint8_t *)av_malloc( size ); if ( !tmp_opicture_buf ) { @@ -347,10 +354,10 @@ void VideoStream::OpenStream( ) { #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) av_image_fill_arrays(tmp_opicture->data, tmp_opicture->linesize, tmp_opicture_buf, pf, - c->width, c->height, 1); + codec_context->width, codec_context->height, 1); #else avpicture_fill( (AVPicture *)tmp_opicture, - tmp_opicture_buf, pf, c->width, c->height ); + tmp_opicture_buf, pf, codec_context->width, codec_context->height ); #endif } } @@ -375,7 +382,12 @@ void VideoStream::OpenStream( ) { } video_outbuf = NULL; +#if LIBAVFORMAT_VERSION_CHECK(57, 0, 0, 0, 0) + if (codec_context->codec_type == AVMEDIA_TYPE_VIDEO && + codec_context->codec_id == AV_CODEC_ID_RAWVIDEO) { +#else if ( !(of->flags & AVFMT_RAWPICTURE) ) { +#endif /* allocate output buffer */ /* XXX: API change will be done */ // TODO: Make buffer dynamic. @@ -446,6 +458,8 @@ VideoStream::VideoStream( const char *in_filename, const char *in_format, int bi if ( pthread_mutex_init( buffer_copy_lock, NULL ) != 0 ) { Fatal("pthread_mutex_init failed"); } + + codec_context = NULL; } VideoStream::~VideoStream( ) { @@ -481,7 +495,7 @@ VideoStream::~VideoStream( ) { /* close each codec */ if ( ost ) { - avcodec_close( ost->codec ); + avcodec_close( codec_context ); av_free( opicture->data[0] ); av_frame_free( &opicture ); if ( tmp_opicture ) { @@ -564,17 +578,15 @@ double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size, static struct SwsContext *img_convert_ctx = 0; #endif // HAVE_LIBSWSCALE - AVCodecContext *c = ost->codec; - - if ( c->pix_fmt != pf ) { + if ( codec_context->pix_fmt != pf ) { memcpy( tmp_opicture->data[0], buffer, buffer_size ); #ifdef HAVE_LIBSWSCALE if ( !img_convert_ctx ) { - img_convert_ctx = sws_getCachedContext( NULL, c->width, c->height, pf, c->width, c->height, c->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL ); + img_convert_ctx = sws_getCachedContext( NULL, codec_context->width, codec_context->height, pf, codec_context->width, codec_context->height, codec_context->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL ); if ( !img_convert_ctx ) Panic( "Unable to initialise image scaling context" ); } - sws_scale( img_convert_ctx, tmp_opicture->data, tmp_opicture->linesize, 0, c->height, opicture->data, opicture->linesize ); + sws_scale( img_convert_ctx, tmp_opicture->data, tmp_opicture->linesize, 0, codec_context->height, opicture->data, opicture->linesize ); #else // HAVE_LIBSWSCALE Fatal( "swscale is required for MPEG mode" ); #endif // HAVE_LIBSWSCALE @@ -586,7 +598,13 @@ double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size, AVPacket *pkt = packet_buffers[packet_index]; av_init_packet( pkt ); int got_packet = 0; +#if LIBAVFORMAT_VERSION_CHECK(57, 0, 0, 0, 0) + if (codec_context->codec_type == AVMEDIA_TYPE_VIDEO && + codec_context->codec_id == AV_CODEC_ID_RAWVIDEO) { +#else if ( of->flags & AVFMT_RAWPICTURE ) { +#endif + #if LIBAVCODEC_VERSION_CHECK(52, 30, 2, 30, 2) pkt->flags |= AV_PKT_FLAG_KEY; #else @@ -597,19 +615,34 @@ double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size, pkt->size = sizeof (AVPicture); got_packet = 1; } else { - opicture_ptr->pts = c->frame_number; - opicture_ptr->quality = c->global_quality; + opicture_ptr->pts = codec_context->frame_number; + opicture_ptr->quality = codec_context->global_quality; + +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + // Put encoder into flushing mode + avcodec_send_frame(codec_context, opicture_ptr); + int ret = avcodec_receive_packet(codec_context, pkt); + if ( ret < 0 ) { + if ( AVERROR_EOF != ret ) { + Error("ERror encoding video (%d) (%s)", ret, + av_err2str(ret)); + } + } else { + got_packet = 1; + } +#else #if LIBAVFORMAT_VERSION_CHECK(54, 1, 0, 2, 100) - int ret = avcodec_encode_video2( c, pkt, opicture_ptr, &got_packet ); + int ret = avcodec_encode_video2( codec_context, pkt, opicture_ptr, &got_packet ); if ( ret != 0 ) { Fatal( "avcodec_encode_video2 failed with errorcode %d \"%s\"", ret, av_err2str( ret ) ); } #else - int out_size = avcodec_encode_video( c, video_outbuf, video_outbuf_size, opicture_ptr ); + int out_size = avcodec_encode_video( codec_context, video_outbuf, video_outbuf_size, opicture_ptr ); got_packet = out_size > 0 ? 1 : 0; pkt->data = got_packet ? video_outbuf : NULL; pkt->size = got_packet ? out_size : 0; +#endif #endif if ( got_packet ) { // if ( c->coded_frame->key_frame ) @@ -622,12 +655,12 @@ double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size, // } if ( pkt->pts != (int64_t)AV_NOPTS_VALUE ) { - pkt->pts = av_rescale_q( pkt->pts, c->time_base, ost->time_base ); + pkt->pts = av_rescale_q( pkt->pts, codec_context->time_base, ost->time_base ); } if ( pkt->dts != (int64_t)AV_NOPTS_VALUE ) { - pkt->dts = av_rescale_q( pkt->dts, c->time_base, ost->time_base ); + pkt->dts = av_rescale_q( pkt->dts, codec_context->time_base, ost->time_base ); } - pkt->duration = av_rescale_q( pkt->duration, c->time_base, ost->time_base ); + pkt->duration = av_rescale_q( pkt->duration, codec_context->time_base, ost->time_base ); pkt->stream_index = ost->index; } } @@ -658,8 +691,12 @@ void *VideoStream::StreamingThreadCallback(void *ctx){ VideoStream* videoStream = reinterpret_cast(ctx); const uint64_t nanosecond_multiplier = 1000000000; - - uint64_t target_interval_ns = nanosecond_multiplier * ( ((double)videoStream->ost->codec->time_base.num) / (videoStream->ost->codec->time_base.den) ); + +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + uint64_t target_interval_ns = nanosecond_multiplier * ( ((double)videoStream->codec_context->time_base.num) / (videoStream->codec_context->time_base.den) ); +#else + uint64_t target_interval_ns = nanosecond_multiplier * ( ((double)videoStream->codec_context->time_base.num) / (videoStream->codec_context->time_base.den) ); +#endif uint64_t frame_count = 0; timespec start_time; clock_gettime(CLOCK_MONOTONIC, &start_time); diff --git a/src/zm_mpeg.h b/src/zm_mpeg.h index 931f9d687..f943b4fd7 100644 --- a/src/zm_mpeg.h +++ b/src/zm_mpeg.h @@ -46,6 +46,7 @@ protected: AVOutputFormat *of; AVFormatContext *ofc; AVStream *ost; + AVCodecContext *codec_context; AVCodec *codec; AVFrame *opicture; AVFrame *tmp_opicture; 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..32e22c47a 100644 --- a/src/zm_remote_camera.h +++ b/src/zm_remote_camera.h @@ -87,7 +87,8 @@ public: virtual void Terminate() = 0; virtual int Connect() = 0; virtual int Disconnect() = 0; - virtual int PreCapture() = 0; + virtual int PreCapture() { return 0; }; + virtual int PrimeCapture() { return 0; }; virtual int Capture( Image &image ) = 0; virtual int PostCapture() = 0; virtual int CaptureAndRecord( Image &image, timeval recording, char* event_directory )=0; diff --git a/src/zm_remote_camera_nvsocket.cpp b/src/zm_remote_camera_nvsocket.cpp index 78f65bd92..98eff70cd 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; @@ -289,20 +187,28 @@ struct image_def image_def; } int RemoteCameraNVSocket::Capture( Image &image ) { - if ( SendRequest("GetNextImage") < 0 ) { + 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 ); + 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..67df93032 100644 --- a/src/zm_remote_camera_nvsocket.h +++ b/src/zm_remote_camera_nvsocket.h @@ -67,7 +67,7 @@ bool p_record_audio ); int SendRequest( std::string ); int ReadData( Buffer &buffer, unsigned int bytes_expected=0 ); int GetResponse(); - int PreCapture(); + int PrimeCapture(); int Capture( Image &image ); int PostCapture(); int CaptureAndRecord( Image &image, timeval recording, char* event_directory ) {return(0);}; diff --git a/src/zm_sdp.cpp b/src/zm_sdp.cpp index ffcea791b..b9f4eb837 100644 --- a/src/zm_sdp.cpp +++ b/src/zm_sdp.cpp @@ -379,21 +379,31 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const stream->id = i; #endif + AVCodecContext *codec_context = NULL; +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + codec_context = avcodec_alloc_context3(NULL); + avcodec_parameters_to_context(codec_context, stream->codecpar); +#else + codec_context = stream->codec; +#endif + + + Debug( 1, "Looking for codec for %s payload type %d / %s", mediaDesc->getType().c_str(), mediaDesc->getPayloadType(), mediaDesc->getPayloadDesc().c_str() ); #if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) if ( mediaDesc->getType() == "video" ) - stream->codec->codec_type = AVMEDIA_TYPE_VIDEO; + codec_context->codec_type = AVMEDIA_TYPE_VIDEO; else if ( mediaDesc->getType() == "audio" ) - stream->codec->codec_type = AVMEDIA_TYPE_AUDIO; + codec_context->codec_type = AVMEDIA_TYPE_AUDIO; else if ( mediaDesc->getType() == "application" ) - stream->codec->codec_type = AVMEDIA_TYPE_DATA; + codec_context->codec_type = AVMEDIA_TYPE_DATA; #else if ( mediaDesc->getType() == "video" ) - stream->codec->codec_type = CODEC_TYPE_VIDEO; + codec_context->codec_type = CODEC_TYPE_VIDEO; else if ( mediaDesc->getType() == "audio" ) - stream->codec->codec_type = CODEC_TYPE_AUDIO; + codec_context->codec_type = CODEC_TYPE_AUDIO; else if ( mediaDesc->getType() == "application" ) - stream->codec->codec_type = CODEC_TYPE_DATA; + codec_context->codec_type = CODEC_TYPE_DATA; #endif #if LIBAVCODEC_VERSION_CHECK(55, 50, 3, 60, 103) @@ -410,31 +420,27 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const #if LIBAVCODEC_VERSION_CHECK(55, 50, 3, 60, 103) codec_name = std::string( smStaticPayloads[i].payloadName ); #else - strncpy( stream->codec->codec_name, smStaticPayloads[i].payloadName, sizeof(stream->codec->codec_name) );; + strncpy( codec_context->codec_name, smStaticPayloads[i].payloadName, sizeof(codec_context->codec_name) );; #endif - stream->codec->codec_type = smStaticPayloads[i].codecType; - stream->codec->codec_id = smStaticPayloads[i].codecId; - stream->codec->sample_rate = smStaticPayloads[i].clockRate; + codec_context->codec_type = smStaticPayloads[i].codecType; + codec_context->codec_id = smStaticPayloads[i].codecId; + codec_context->sample_rate = smStaticPayloads[i].clockRate; break; } } - } - else - { + } else { // Look in dynamic table - for ( unsigned int i = 0; i < (sizeof(smDynamicPayloads)/sizeof(*smDynamicPayloads)); i++ ) - { - if ( smDynamicPayloads[i].payloadName == mediaDesc->getPayloadDesc() ) - { + for ( unsigned int i = 0; i < (sizeof(smDynamicPayloads)/sizeof(*smDynamicPayloads)); i++ ) { + if ( smDynamicPayloads[i].payloadName == mediaDesc->getPayloadDesc() ) { Debug( 1, "Got dynamic payload type %d, %s", mediaDesc->getPayloadType(), smDynamicPayloads[i].payloadName ); #if LIBAVCODEC_VERSION_CHECK(55, 50, 3, 60, 103) codec_name = std::string( smStaticPayloads[i].payloadName ); #else - strncpy( stream->codec->codec_name, smDynamicPayloads[i].payloadName, sizeof(stream->codec->codec_name) );; + strncpy( codec_context->codec_name, smDynamicPayloads[i].payloadName, sizeof(codec_context->codec_name) );; #endif - stream->codec->codec_type = smDynamicPayloads[i].codecType; - stream->codec->codec_id = smDynamicPayloads[i].codecId; - stream->codec->sample_rate = mediaDesc->getClock(); + codec_context->codec_type = smDynamicPayloads[i].codecType; + codec_context->codec_id = smDynamicPayloads[i].codecId; + codec_context->sample_rate = mediaDesc->getClock(); break; } } @@ -450,14 +456,13 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const //return( 0 ); } if ( mediaDesc->getWidth() ) - stream->codec->width = mediaDesc->getWidth(); + codec_context->width = mediaDesc->getWidth(); if ( mediaDesc->getHeight() ) - stream->codec->height = mediaDesc->getHeight(); - if ( stream->codec->codec_id == AV_CODEC_ID_H264 && mediaDesc->getSprops().size()) - { + codec_context->height = mediaDesc->getHeight(); + if ( codec_context->codec_id == AV_CODEC_ID_H264 && mediaDesc->getSprops().size()) { uint8_t start_sequence[]= { 0, 0, 1 }; - stream->codec->extradata_size= 0; - stream->codec->extradata= NULL; + codec_context->extradata_size= 0; + codec_context->extradata= NULL; char pvalue[1024], *value = pvalue; strcpy(pvalue, mediaDesc->getSprops().c_str()); @@ -482,22 +487,33 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const if (packet_size) { uint8_t *dest = (uint8_t *)av_malloc(packet_size + sizeof(start_sequence) + - stream->codec->extradata_size + - FF_INPUT_BUFFER_PADDING_SIZE); + codec_context->extradata_size + +#if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0) + AV_INPUT_BUFFER_PADDING_SIZE +#else + FF_INPUT_BUFFER_PADDING_SIZE +#endif +); if(dest) { - if(stream->codec->extradata_size) { + if(codec_context->extradata_size) { // av_realloc? - memcpy(dest, stream->codec->extradata, stream->codec->extradata_size); - av_free(stream->codec->extradata); + memcpy(dest, codec_context->extradata, codec_context->extradata_size); + av_free(codec_context->extradata); } - memcpy(dest+stream->codec->extradata_size, start_sequence, sizeof(start_sequence)); - memcpy(dest+stream->codec->extradata_size+sizeof(start_sequence), decoded_packet, packet_size); - memset(dest+stream->codec->extradata_size+sizeof(start_sequence)+ - packet_size, 0, FF_INPUT_BUFFER_PADDING_SIZE); + memcpy(dest+codec_context->extradata_size, start_sequence, sizeof(start_sequence)); + memcpy(dest+codec_context->extradata_size+sizeof(start_sequence), decoded_packet, packet_size); + memset(dest+codec_context->extradata_size+sizeof(start_sequence)+ + packet_size, 0, +#if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0) + AV_INPUT_BUFFER_PADDING_SIZE +#else + FF_INPUT_BUFFER_PADDING_SIZE +#endif +); - stream->codec->extradata= dest; - stream->codec->extradata_size+= sizeof(start_sequence)+packet_size; + codec_context->extradata= dest; + codec_context->extradata_size+= sizeof(start_sequence)+packet_size; // } else { // av_log(codec, AV_LOG_ERROR, "Unable to allocate memory for extradata!"); // return AVERROR(ENOMEM); diff --git a/src/zm_sdp.h b/src/zm_sdp.h index 48a05b706..68e574d0f 100644 --- a/src/zm_sdp.h +++ b/src/zm_sdp.h @@ -31,13 +31,11 @@ #include #include -class SessionDescriptor -{ +class SessionDescriptor { protected: enum { PAYLOAD_TYPE_DYNAMIC=96 }; - struct StaticPayloadDesc - { + struct StaticPayloadDesc { int payloadType; const char payloadName[6]; #if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) @@ -50,8 +48,7 @@ protected: int autoChannels; }; - struct DynamicPayloadDesc - { + struct DynamicPayloadDesc { const char payloadName[32]; #if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) AVMediaType codecType; @@ -65,8 +62,7 @@ protected: }; public: - class ConnInfo - { + class ConnInfo { protected: std::string mNetworkType; std::string mAddressType; @@ -78,8 +74,7 @@ public: ConnInfo( const std::string &connInfo ); }; - class BandInfo - { + class BandInfo { protected: std::string mType; int mValue; @@ -88,8 +83,7 @@ public: BandInfo( const std::string &bandInfo ); }; - class MediaDescriptor - { + class MediaDescriptor { protected: std::string mType; int mPort; diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index c8704eae0..e6c4769b1 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -167,7 +167,11 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, 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; +#endif } Monitor::Orientation orientation = monitor->getOrientation(); @@ -274,7 +278,11 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, 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 From 476ed4c9e08141f8414b9eeb5717dd35a8a7463d Mon Sep 17 00:00:00 2001 From: APHW2 MFGENG Date: Thu, 9 Nov 2017 06:16:41 -0800 Subject: [PATCH 12/23] 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 13/23] 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 14/23] 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 3dafb5c2258a750b620e339e5cedbad09669c4cc Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 11 Nov 2017 09:25:13 -0500 Subject: [PATCH 15/23] 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 50d3b168fad86de339046ca1fa81e1664329954f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 12 Nov 2017 11:50:07 -0500 Subject: [PATCH 16/23] 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 0e799233d2d1f923fd6ec71bcaef2f6505fae957 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 13 Nov 2017 10:57:37 -0500 Subject: [PATCH 17/23] 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 18/23] 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 19/23] 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 20/23] 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 21/23] 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 22/23] 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 23/23] 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()) { ?> +