From 4df354dc24a633120d2c19a233e7252e6d476129 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 22 Jun 2017 10:48:15 -0400 Subject: [PATCH 001/114] fix order of send_frame and break and fix if ( usleep ) which should be if ( delta_us ) --- src/zm_event.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 110faf2d2..4335f27f0 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -913,9 +913,8 @@ void EventStream::processCommand( const CmdMsg *msg ) { zoom = 500; break; } - break; - send_frame = true; + break; } case CMD_ZOOMOUT : { @@ -1342,7 +1341,7 @@ void EventStream::runStream() { curr_frame_id += replay_rate>0?1:-1; if ( send_frame && type != STREAM_MPEG ) { Debug( 3, "dUs: %d", delta_us ); - if ( usleep ) + if ( delta_us ) usleep( delta_us ); } } else { From 6fc1581b9e99ed4da3c73a679999a728d9130c87 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 28 Jun 2017 20:33:53 -0400 Subject: [PATCH 002/114] use a monitor object instead of just a db array. --- web/skins/classic/views/monitor.php | 889 ++++++++++++++-------------- 1 file changed, 458 insertions(+), 431 deletions(-) diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index 4bc808122..dcc76e662 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -51,17 +51,94 @@ if ( ! $Server ) { } if ( ! empty($_REQUEST['mid']) ) { - $monitor = dbFetchMonitor( $_REQUEST['mid'] ); + $monitor = new Monitor( $_REQUEST['mid'] ); if ( ZM_OPT_X10 ) $x10Monitor = dbFetchOne( 'SELECT * FROM TriggersX10 WHERE MonitorId = ?', NULL, array($_REQUEST['mid']) ); } else { $nextId = getTableAutoInc( 'Monitors' ); - $monitor = getMonitorObject($_REQUEST['dupId']); - $clonedName = $monitor['Name']; - $monitor['Name'] = translate('Monitor').'-'.$nextId; - $monitor['Id']='0'; -} + if ( ! empty( $_REQUEST['dupId'] ) ) { + $monitor = new Monitor( $_REQUEST['dupId'] ); + if ( ZM_OPT_X10 ) + $x10Monitor = dbFetchOne( 'SELECT * FROM TriggersX10 WHERE MonitorId = ?', NULL, array($_REQUEST['dupId']) ); + $clonedName = $monitor->Name(); + $monitor->Name( translate('Monitor').'-'.$nextId ); + $monitor->Id( $nextId ); + } else { + $monitor = new Monitor(); + $monitor->set( array( + 'Id' => 0, + 'Name' => translate('Monitor').'-'.$nextId, + 'Function' => 'Monitor', + 'Enabled' => true, + 'LinkedMonitors' => '', + 'Type' => '', + 'Device' => "/dev/video0", + 'Channel' => '0', + 'Format' => 0x000000ff, + 'Protocol' => '', + 'Method' => '', + 'Host' => '', + 'Path' => '', + 'Options' => '', + 'Port' => '80', + 'User' => '', + 'Pass' => '', + 'Colours' => 3, + 'Palette' => 0, + 'Width' => '320', + 'Height' => '240', + 'Orientation' => '0', + 'Deinterlacing' => 0, + 'RTSPDescribe' => 0, + 'SaveJPEGs' => '3', + 'VideoWriter' => '0', + 'EncoderParameters' => "# Lines beginning with # are a comment \n# For changing quality, use the crf option\n# 1 is best, 51 is worst quality\n#crf=23\n", + 'RecordAudio' => '0', + 'LabelFormat' => '%N - %d/%m/%y %H:%M:%S', + 'LabelX' => 0, + 'LabelY' => 0, + 'LabelSize' => 1, + 'ImageBufferCount' => 50, + 'WarmupCount' => 25, + 'PreEventCount' => 25, + 'PostEventCount' => 25, + 'StreamReplayBuffer' => 1000, + 'AlarmFrameCount' => 1, + 'Controllable' => 0, + 'ControlId' => '', + 'ControlType' => 0, + 'ControlDevice' => '', + 'ControlAddress' => '', + 'AutoStopTimeout' => '', + 'TrackMotion' => 0, + 'TrackDelay' => '', + 'ReturnLocation' => -1, + 'ReturnDelay' => '', + 'SectionLength' => 600, + 'FrameSkip' => 0, + 'MotionFrameSkip' => 0, + 'EventPrefix' => 'Event-', + 'AnalysisFPS' => '', + 'AnalysisUpdateDelay' => 0, + 'MaxFPS' => '', + 'AlarmMaxFPS' => '', + 'FPSReportInterval' => 1000, + 'RefBlendPerc' => 6, + 'AlarmRefBlendPerc' => 6, + 'DefaultView' => 'Events', + 'DefaultRate' => '100', + 'DefaultScale' => '100', + 'SignalCheckColour' => '#0000c0', + 'WebColour' => 'red', + 'Exif' => '0', + 'Triggers' => '', + 'V4LMultiBuffer' => '', + 'V4LCapturesPerFrame' => 1, + 'ServerId' => $Server['Id'], + ) ); + } # end if $_REQUEST['dupID'] +} # end if $_REQUEST['mid'] if ( ZM_OPT_X10 && empty($x10Monitor) ) { $x10Monitor = array( @@ -71,114 +148,37 @@ if ( ZM_OPT_X10 && empty($x10Monitor) ) { ); } -function getMonitorObject( $mid = null ) { - if ( $mid !== null ) { - $monitor = dbFetchMonitor($mid); - } else { - $monitor = array( - 'Id' => 0, - 'Name' => 'willbereplaced', - 'Function' => 'Monitor', - 'Enabled' => true, - 'LinkedMonitors' => '', - 'Type' => '', - 'Device' => '/dev/video0', - 'Channel' => '0', - 'Format' => 0x000000ff, - 'Protocol' => '', - 'Method' => '', - 'Host' => '', - 'Path' => '', - 'Options' => '', - 'Port' => "80", - 'User' => '', - 'Pass' => '', - 'Colours' => 3, - 'Palette' => 0, - 'Width' => '320', - 'Height' => '240', - 'Orientation' => '0', - 'Deinterlacing' => 0, - 'RTSPDescribe' => 0, - 'SaveJPEGs' => '3', - 'VideoWriter' => '0', - 'EncoderParameters' => "# Lines beginning with # are a comment \n# For changing quality, use the crf option\n# 1 is best, 51 is worst quality\n#crf=23\n", - 'RecordAudio' => '0', - 'LabelFormat' => '%N - %d/%m/%y %H:%M:%S', - 'LabelX' => 0, - 'LabelY' => 0, - 'LabelSize' => 1, - 'ImageBufferCount' => 50, - 'WarmupCount' => 25, - 'PreEventCount' => 25, - 'PostEventCount' => 25, - 'StreamReplayBuffer' => 1000, - 'AlarmFrameCount' => 1, - 'Controllable' => 0, - 'ControlId' => '', - 'ControlType' => 0, - 'ControlDevice' => '', - 'ControlAddress' => '', - 'AutoStopTimeout' => '', - 'TrackMotion' => 0, - 'TrackDelay' => '', - 'ReturnLocation' => -1, - 'ReturnDelay' => '', - 'SectionLength' => 600, - 'FrameSkip' => 0, - 'MotionFrameSkip' => 0, - 'EventPrefix' => 'Event-', - 'AnalysisFPS' => '', - 'AnalysisUpdateDelay' => 0, - 'MaxFPS' => '', - 'AlarmMaxFPS' => '', - 'FPSReportInterval' => 1000, - 'RefBlendPerc' => 6, - 'AlarmRefBlendPerc' => 6, - 'DefaultView' => 'Events', - 'DefaultRate' => '100', - 'DefaultScale' => '100', - 'SignalCheckColour' => '#0000c0', - 'WebColour' => 'red', - 'Exif' => '0', - 'Triggers' => '', - 'V4LMultiBuffer' => '', - 'V4LCapturesPerFrame' => 1, - 'ServerId' => $Server['Id'], - ); - } - return ($monitor); -} - function fourcc( $a, $b, $c, $d ) { return( ord($a) | (ord($b) << 8) | (ord($c) << 16) | (ord($d) << 24) ); } if ( isset( $_REQUEST['newMonitor'] ) ) { - $newMonitor = $_REQUEST['newMonitor']; + # Update the monitor object with whatever has been set so far. + $monitor->set( $_REQUEST['newMonitor'] ); + if ( ZM_OPT_X10 ) $newX10Monitor = $_REQUEST['newX10Monitor']; } else { - $newMonitor = $monitor; - $newMonitor['Triggers'] = explode( ',', isset($monitor['Triggers'])?$monitor['Triggers']:'' ); + # FIXME: Triggers in the db is a comma separated string. Needs to be an array. + #$monitor->Triggers()= explode( ',', isset($monitor->Triggers())?$monitor->Triggers:"" ); if ( ZM_OPT_X10 ) $newX10Monitor = $x10Monitor; } -$newMonitor['Name'] = trim($newMonitor['Name']); - -if ( $newMonitor['AnalysisFPS'] == '0.00' ) - $newMonitor['AnalysisFPS'] = ''; -if ( $newMonitor['MaxFPS'] == '0.00' ) - $newMonitor['MaxFPS'] = ''; -if ( $newMonitor['AlarmMaxFPS'] == '0.00' ) - $newMonitor['AlarmMaxFPS'] = ''; +# What if it has less zeros? This is not robust code. +if ( $monitor->AnalysisFPS() == '0.00' ) + $monitor->AnalysisFPS( '' ); +if ( $monitor->MaxFPS() == '0.00' ) + $monitor->MaxFPS( '' ); +if ( $monitor->AlarmMaxFPS() == '0.00' ) + $monitor->AlarmMaxFPS( '' ); if ( !empty($_REQUEST['preset']) ) { $preset = dbFetchOne( 'SELECT Type, Device, Channel, Format, Protocol, Method, Host, Port, Path, Width, Height, Palette, MaxFPS, Controllable, ControlId, ControlDevice, ControlAddress, DefaultRate, DefaultScale FROM MonitorPresets WHERE Id = ?', NULL, array($_REQUEST['preset']) ); foreach ( $preset as $name=>$value ) { + # Does isset handle NULL's? I don't think this code is correct. if ( isset($value) ) { - $newMonitor[$name] = $value; + $monitor->$name = $value; } } } @@ -186,16 +186,17 @@ if ( !empty($_REQUEST['probe']) ) { $probe = unserialize(base64_decode($_REQUEST['probe'])); foreach ( $probe as $name=>$value ) { if ( isset($value) ) { - $newMonitor[$name] = $value; + # Does isset handle NULL's? I don't think this code is correct. + $monitor->$name = $value; } } - if ( ZM_HAS_V4L && $newMonitor['Type'] == 'Local' ) { - $newMonitor['Palette'] = fourCC( substr($newMonitor['Palette'],0,1), substr($newMonitor['Palette'],1,1), substr($newMonitor['Palette'],2,1), substr($newMonitor['Palette'],3,1) ); - if ( $newMonitor['Format'] == 'PAL' ) - $newMonitor['Format'] = 0x000000ff; - elseif ( $newMonitor['Format'] == 'NTSC' ) - $newMonitor['Format'] = 0x0000b000; - } + if ( ZM_HAS_V4L && $monitor->Type() == 'Local' ) { + $monitor->Palette( fourCC( substr($monitor->Palette,0,1), substr($monitor->Palette,1,1), substr($monitor->Palette,2,1), substr($monitor->Palette,3,1) ) ); + if ( $monitor->Format() == 'PAL' ) + $monitor->Format( 0x000000ff ); + elseif ( $monitor->Format() == 'NTSC' ) + $monitor->Format( 0x0000b000 ); + } } $sourceTypes = array( @@ -246,7 +247,7 @@ $httpMethods = array( if ( !ZM_PCRE ) unset($httpMethods['regexp']); -// Currently unsupported + // Currently unsupported unset($httpMethods['jpegTags']); if ( ZM_HAS_V4L1 ) { @@ -267,9 +268,9 @@ if ( ZM_HAS_V4L1 ) { $v4l1DeviceChannels[$i] = $i; $v4l1LocalPalettes = array( - translate('Grey') => 1, - 'BGR32' => 5, - 'BGR24' => 4, + translate('Grey') => 1, + 'BGR32' => 5, + 'BGR24' => 4, '*YUYV' => 8, '*RGB565' => 3, '*RGB555' => 6, @@ -466,7 +467,7 @@ $videowriteropts = array( 'H264 Camera Passthrough' => 2 ); -xhtmlHeaders(__FILE__, translate('Monitor')." - ".validHtmlStr($monitor['Name']) ); +xhtmlHeaders(__FILE__, translate('Monitor')." - ".validHtmlStr($monitor->Name()) ); ?>
@@ -474,270 +475,279 @@ xhtmlHeaders(__FILE__, translate('Monitor')." - ".validHtmlStr($monitor['Name']) -
- Configuration cloned from Monitor: -
- -
- - - - - -
- -

- ()

+
+ Configuration cloned from Monitor:
-
-
    $value ) { - if ( $tab == $name ) { + } ?> -
  • +
    + -
  • + + + +
    + +

    - Name()) ?>Id()) ) { ?> (Id()?>)

    +
+
+
    +$value ) { + if ( $tab == $name ) { +?> +
  • + +
  • + +
+
+
+ + + + + + + + + + + + + + + + + +Triggers() ) { + foreach( explode( ',', $monitor->Triggers() ) as $newTrigger ) { +?> + Type()!= 'Local') ) { +?> + + + + + + +Type()!= 'Remote' ) { +?> + + + +Type()!= 'Local' && $monitor->Type()!= 'Remote' && $monitor->Type()!= 'Ffmpeg' && $monitor->Type()!= 'Libvlc') ) { +?> + +Type()!= 'Ffmpeg' && $monitor->Type()!= 'Libvlc' )) { +?> + +Type()!= 'Remote' && $monitor->Type()!= 'File' && $monitor->Type()!= 'Ffmpeg' && $monitor->Type()!= 'Libvlc' && $monitor->Type()!= 'cURL') ) { +?> + + + + + + + + + + + + + + +Type()!= 'Remote' && $monitor->Protocol()!= 'rtsp') ) { +?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Type()!= 'Local') ) { +?> + + - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
+ - - + - - + + - - - - + + + + - - + + + + Type() != 'Local' && $monitor->Type() != 'File' ) { ?> - + - + - - + + - - - + + + + + + + - - + + @@ -753,148 +763,150 @@ switch ( $tab ) { if ( $optCount && ($optCount%$breakCount == 0) ) echo '
'; ?> - checked="checked"/>  + Triggers() ) && in_array( $optTrigger, $monitor->Triggers() ) ) { ?> checked="checked"/>  - - - - + + + + Type() == 'Local' ) { ?> - - + + Method() == 'v4l1' ) { ?> - - - + + + - - - + + + - - + + Type() == 'Remote' ) { ?> - + Protocol()) || $monitor->Protocol() == 'http' ) { ?> - + - + - - - + + + Type() == 'File' ) { ?> - + Type() == 'cURL' ) { ?> - - - + + + Type() == 'Ffmpeg' || $monitor->Type() == 'Libvlc' ) { ?> - - - + + + - - - - - + + + + + Type() == 'Local' ) { ?> - + + + - - - > + } + ?> + Type() == 'Remote' ) { + ?> + Protocol()!= 'rtsp' ) { echo ' style="display:none;"'; } ?>> - - - - + + + + - - - - + + + + - - - - - - + + + + + + - + - - - - + + + + translate('None'), @@ -902,9 +914,9 @@ switch ( $tab ) { '1' => translate('Preset')." 1", ); ?> - + - + - - - - - - - + + + + + + - - + + + Type() == 'Local' ) { ?> - + + + + - - + + + + + + + + From d13d7e905073999c144e979dbee2d9c3e23fe994 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 14 Jul 2017 09:57:25 -0400 Subject: [PATCH 003/114] recode the bit that outputs the link under source so that it defaults to Monitor # under all situations --- web/skins/classic/views/console.php | 39 ++++++++++++++--------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index ad2382ff4..ad6891161 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -252,27 +252,26 @@ foreach( $displayMonitors as $monitor ) { $Server = new Server( $monitor['ServerId'] ); echo $Server->Name(); ?> - - - - - - - - - - - - - -'. makePopupLink( '?view=monitor&mid='.$monitor['Id'], 'zmMonitor'.$monitor['Id'], 'monitor', ''.$source.'', canEdit( 'Monitors' ) ).''; + for ( $i = 0; $i < count($eventCounts); $i++ ) { ?> From 1822510909816bcee548c68cddac8b9e5c7f1fe3 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Fri, 14 Jul 2017 10:15:12 -0500 Subject: [PATCH 004/114] rpm packaging - consolidate zoneminder apache config file --- distros/redhat/CMakeLists.txt | 10 +-- .../{systemd => apache}/zoneminder.conf.in | 0 distros/redhat/sysvinit/zoneminder.conf.in | 71 ------------------- 3 files changed, 5 insertions(+), 76 deletions(-) rename distros/redhat/{systemd => apache}/zoneminder.conf.in (100%) delete mode 100644 distros/redhat/sysvinit/zoneminder.conf.in diff --git a/distros/redhat/CMakeLists.txt b/distros/redhat/CMakeLists.txt index 63159b1c7..7684fb975 100644 --- a/distros/redhat/CMakeLists.txt +++ b/distros/redhat/CMakeLists.txt @@ -9,15 +9,15 @@ else(ZM_TARGET_DISTRO MATCHES "^el") message([WARNING] "Unknown Build Option Detected" ...) endif(ZM_TARGET_DISTRO MATCHES "^el") -if((ZM_TARGET_DISTRO STREQUAL "el6") AND (ZM_WEB_USER STREQUAL "nginx")) - message([FATAL_ERROR] "Nginx is Not a Supported Build Option on EL6 Target Distro" ...) -endif((ZM_TARGET_DISTRO STREQUAL "el6") AND (ZM_WEB_USER STREQUAL "nginx")) +if((NOT ZM_TARGET_DISTRO MATCHES "^fc") AND (ZM_WEB_USER STREQUAL "nginx")) + message([FATAL_ERROR] "Experimental Nginx support is currently only supported on Fedora" ...) +endif((NOT ZM_TARGET_DISTRO MATCHES "^fc") AND (ZM_WEB_USER STREQUAL "nginx")) # Configure the zoneminder service files if(ZM_TARGET_DISTRO STREQUAL "el6") configure_file(sysvinit/zoneminder.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.sysvinit @ONLY) configure_file(sysvinit/zoneminder.logrotate.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.logrotate @ONLY) - configure_file(sysvinit/zoneminder.conf.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.conf @ONLY) + configure_file(apache/zoneminder.conf.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.conf @ONLY) else(ZM_TARGET_DISTRO STREQUAL "el6") configure_file(systemd/zoneminder.logrotate.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.logrotate @ONLY) if(ZM_WEB_USER STREQUAL "nginx") @@ -28,7 +28,7 @@ else(ZM_TARGET_DISTRO STREQUAL "el6") configure_file(nginx/README.Fedora ${CMAKE_CURRENT_SOURCE_DIR}/readme/README.Fedora COPYONLY) else(ZM_WEB_USER STREQUAL "nginx") configure_file(systemd/zoneminder.service.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.service @ONLY) - configure_file(systemd/zoneminder.conf.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.conf @ONLY) + configure_file(apache/zoneminder.conf.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.conf @ONLY) configure_file(systemd/zoneminder.tmpfiles.in ${CMAKE_CURRENT_SOURCE_DIR}/zoneminder.tmpfiles @ONLY) endif(ZM_WEB_USER STREQUAL "nginx") endif(ZM_TARGET_DISTRO STREQUAL "el6") diff --git a/distros/redhat/systemd/zoneminder.conf.in b/distros/redhat/apache/zoneminder.conf.in similarity index 100% rename from distros/redhat/systemd/zoneminder.conf.in rename to distros/redhat/apache/zoneminder.conf.in diff --git a/distros/redhat/sysvinit/zoneminder.conf.in b/distros/redhat/sysvinit/zoneminder.conf.in deleted file mode 100644 index 0e546f9df..000000000 --- a/distros/redhat/sysvinit/zoneminder.conf.in +++ /dev/null @@ -1,71 +0,0 @@ -# -# ZoneMinder Apache configuration file -# With SSLRequire and HTTPS auto redirect -# Modify this configuration to suit your requirements -# - -# Auto Redirect HTTP requests to HTTPS -RewriteEngine On -RewriteCond %{HTTPS} !=on -RewriteRule ^/?(zm)(.*) https://%{SERVER_NAME}/$1$2 [R,L] - -Alias /zm "@ZM_WEBDIR@" - - # explicitly set index.php as the only directoryindex - DirectoryIndex disabled - DirectoryIndex index.php - SSLRequireSSL - Options -Indexes +MultiViews +FollowSymLinks - AllowOverride None - - # Apache 2.4 - Require all granted - - - # Apache 2.2 - Order deny,allow - Allow from all - - - -ScriptAlias /cgi-bin-zm "@ZM_CGIDIR@" - - SSLRequireSSL - AllowOverride None - Options +ExecCGI +FollowSymLinks - - # Apache 2.4 - Require all granted - - - # Apache 2.2 - Order deny,allow - Allow from all - - - -# For better visibility, the following directives have been migrated from the -# default .htaccess files included with the CakePHP project. -# Parameters not set here are inherited from the parent directive above. - - RewriteEngine on - RewriteRule ^$ app/webroot/ [L] - RewriteRule (.*) app/webroot/$1 [L] - RewriteBase /zm/api - - - - RewriteEngine on - RewriteRule ^$ webroot/ [L] - RewriteRule (.*) webroot/$1 [L] - RewriteBase /zm/api - - - - RewriteEngine On - RewriteCond %{REQUEST_FILENAME} !-d - RewriteCond %{REQUEST_FILENAME} !-f - RewriteRule ^ index.php [L] - RewriteBase /zm/api - - From 2002e863a9c6f0e2cca31403fbd0b76e94bf9871 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Fri, 14 Jul 2017 10:26:41 -0500 Subject: [PATCH 005/114] Update zoneminder.service.in --- distros/redhat/systemd/zoneminder.service.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distros/redhat/systemd/zoneminder.service.in b/distros/redhat/systemd/zoneminder.service.in index 2234af036..68918ab9e 100644 --- a/distros/redhat/systemd/zoneminder.service.in +++ b/distros/redhat/systemd/zoneminder.service.in @@ -1,4 +1,4 @@ -# ZoneMinder systemd unit file for CentOS 7 +# ZoneMinder systemd unit file for RedHat distros and clones [Unit] Description=ZoneMinder CCTV recording and security system From 89bcfc4e28cb74b94a4e29ad25ac18e90cab9ac0 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Fri, 14 Jul 2017 10:39:50 -0500 Subject: [PATCH 006/114] fix incorrect gpl license text mailing address --- scripts/ZoneMinder/lib/ZoneMinder/Control/MaginonIPC.pm | 2 +- scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm | 2 +- scripts/ZoneMinder/lib/ZoneMinder/Object.pm | 2 +- web/skins/classic/views/image-ffmpeg.php | 2 +- web/views/view_video.php | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/MaginonIPC.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/MaginonIPC.pm index 35159fc4e..38ae81aa3 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/MaginonIPC.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/MaginonIPC.pm @@ -15,7 +15,7 @@ # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # # ========================================================================== # diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm b/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm index d5b7d7f53..ebdb073b2 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Monitor.pm @@ -15,7 +15,7 @@ # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # # ========================================================================== # diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Object.pm b/scripts/ZoneMinder/lib/ZoneMinder/Object.pm index b87e111a6..63193bccf 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Object.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Object.pm @@ -15,7 +15,7 @@ # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # # ========================================================================== # diff --git a/web/skins/classic/views/image-ffmpeg.php b/web/skins/classic/views/image-ffmpeg.php index 082c75099..37e2cd691 100644 --- a/web/skins/classic/views/image-ffmpeg.php +++ b/web/skins/classic/views/image-ffmpeg.php @@ -15,7 +15,7 @@ // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // if ( !canView( 'Events' ) ) diff --git a/web/views/view_video.php b/web/views/view_video.php index 8cf590e9d..a4bfa3892 100644 --- a/web/views/view_video.php +++ b/web/views/view_video.php @@ -15,7 +15,7 @@ // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // // Calling sequence: ... /zm/index.php?view=video&event_id=123 From 13a72b7a99ba3a0b1dad7fedccdb2109ea24ea9a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 14 Jul 2017 11:58:15 -0400 Subject: [PATCH 007/114] fix path to logs for api --- web/api/app/Config/bootstrap.php.in | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/web/api/app/Config/bootstrap.php.in b/web/api/app/Config/bootstrap.php.in index ac3bcb62c..bfef76b54 100644 --- a/web/api/app/Config/bootstrap.php.in +++ b/web/api/app/Config/bootstrap.php.in @@ -101,15 +101,17 @@ CakeLog::config('debug', array( 'engine' => 'File', 'types' => array('notice', 'info', 'debug'), 'file' => 'cake_debug', + 'path' => '@ZM_LOGDIR@/' )); CakeLog::config('error', array( 'engine' => 'File', 'types' => array('warning', 'error', 'critical', 'alert', 'emergency'), 'file' => 'cake_error', + 'path' => '@ZM_LOGDIR@/' )); CakeLog::config('custom_path', array( 'engine' => 'File', - 'path' => '@ZM_LOGDIR@' + 'path' => '@ZM_LOGDIR@/' )); Configure::write('ZM_CONFIG', '@ZM_CONFIG@'); From e203064bf7ab238d13b8c8ce1b39de1e4a5906aa Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 14 Jul 2017 12:03:00 -0400 Subject: [PATCH 008/114] updates bootstrap.php.in to match config.php's conf.d loading --- web/api/app/Config/bootstrap.php.in | 69 ++++++++++++++++++----------- 1 file changed, 42 insertions(+), 27 deletions(-) diff --git a/web/api/app/Config/bootstrap.php.in b/web/api/app/Config/bootstrap.php.in index ac3bcb62c..c92e24488 100644 --- a/web/api/app/Config/bootstrap.php.in +++ b/web/api/app/Config/bootstrap.php.in @@ -113,37 +113,52 @@ CakeLog::config('custom_path', array( )); Configure::write('ZM_CONFIG', '@ZM_CONFIG@'); +Configure::write('ZM_CONFIG_SUBDIR', '@ZM_CONFIG_SUBDIR@'); Configure::write('ZM_VERSION', '@VERSION@'); Configure::write('ZM_API_VERSION', '@API_VERSION@'); -loadConfigFile(); +# Process name, value pairs from the main config file first +$configvals = process_configfile(Configure::read('ZM_CONFIG')); -function loadConfigFile() { - $configFile = Configure::read('ZM_CONFIG'); - $localConfigFile = basename($configFile); - if ( file_exists( $localConfigFile ) && filesize( $localConfigFile ) > 0 ) - { - if ( php_sapi_name() == 'cli' && empty($_SERVER['REMOTE_ADDR']) ) - print( "Warning, overriding installed $localConfigFile file with local copy\n" ); - else - error_log( "Warning, overriding installed $localConfigFile file with local copy" ); - $configFile = $localConfigFile; - } - - $cfg = fopen( $configFile, "r") or die("Could not open config file."); - while ( !feof($cfg) ) - { - $str = fgets( $cfg, 256 ); - if ( preg_match( '/^\s*$/', $str )) - continue; - elseif ( preg_match( '/^\s*#/', $str )) - continue; - elseif ( preg_match( '/^\s*([^=\s]+)\s*=\s*(.*?)\s*$/', $str, $matches )) { - Configure::write( $matches[1], $matches[2] ); - define( $matches[1], $matches[2] ); - } - } - fclose( $cfg ); +# Search for user created config files. If one or more are found then +# update our config value array with those values +$configSubFolder = Configure::read('ZM_CONFIG_SUBDIR'); +if ( is_dir($configSubFolder) ) { + if ( is_readable($configSubFolder) ) { + foreach ( glob("$configSubFolder/*.conf") as $filename ) { + $configvals = array_replace($configvals, process_configfile($filename) ); + } + } else { + error_log( "WARNING: ZoneMinder configuration subfolder found but is not readable. Check folder permissions on $configSubFolder." ); + } } +# Now that our array our finalized, define each key => value +# pair in the array as a constant +foreach( $configvals as $key => $value) { + define( $key, $value ); + Configure::write( $matches[1], $matches[2] ); +} + +function process_configfile($configFile) { + if ( is_readable( $configFile ) ) { + $configvals = array(); + + $cfg = fopen( $configFile, "r") or die("Could not open config file."); + while ( !feof($cfg) ) { + $str = fgets( $cfg, 256 ); + if ( preg_match( '/^\s*$/', $str )) + continue; + elseif ( preg_match( '/^\s*#/', $str )) + continue; + elseif ( preg_match( '/^\s*([^=\s]+)\s*=\s*(.*?)\s*$/', $str, $matches )) + $configvals[$matches[1]] = $matches[2]; + } + fclose( $cfg ); + return( $configvals ); + } else { + error_log( "WARNING: ZoneMinder configuration file found but is not readable. Check file permissions on $configFile." ); + return( false ); + } +} From 240a990c7f2a7f1be02332ed52eaf4c1c280b8ee Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 14 Jul 2017 12:19:43 -0400 Subject: [PATCH 009/114] fix writing to config --- web/api/app/Config/bootstrap.php.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/api/app/Config/bootstrap.php.in b/web/api/app/Config/bootstrap.php.in index c92e24488..e744fa457 100644 --- a/web/api/app/Config/bootstrap.php.in +++ b/web/api/app/Config/bootstrap.php.in @@ -137,7 +137,7 @@ if ( is_dir($configSubFolder) ) { # pair in the array as a constant foreach( $configvals as $key => $value) { define( $key, $value ); - Configure::write( $matches[1], $matches[2] ); + Configure::write( $key, $value ); } function process_configfile($configFile) { From 1264f0601f3348208a977d366f022ab6c80b6210 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 14 Jul 2017 15:55:08 -0400 Subject: [PATCH 010/114] update to storageareas version, which changes the sql to use subqueries instead of JOINs --- scripts/zmvideo.pl.in | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/scripts/zmvideo.pl.in b/scripts/zmvideo.pl.in index ab9d0b347..788ecde87 100644 --- a/scripts/zmvideo.pl.in +++ b/scripts/zmvideo.pl.in @@ -27,12 +27,14 @@ zmvideo.pl - ZoneMinder Video Creation Script =head1 SYNOPSIS - zmvideo.pl [ -e ,--event= | --filter= ] [--format ] - [--rate=] - [--scale=] - [--fps=] - [--size=] - [--overwrite] + zmvideo.pl [ -e ,--event= | --filter_name= | --filter_id= ] + [--concat=filename] + [--format ] + [--rate=] + [--scale=] + [--fps=] + [--size=] + [--overwrite] =head1 DESCRIPTION @@ -189,23 +191,21 @@ if ( $event_id ) { Debug(@event_ids . " events found for $filter_name"); } $concat_name = $filter_name if $concat_name eq ''; -} else { - Warning("Nothing to do"); } -my $sql = " SELECT max(F.Delta)-min(F.Delta) as FullLength, - E.*, - unix_timestamp(E.StartTime) as Time, +my $sql = " SELECT (SELECT max(Delta) FROM Frames WHERE EventId=Events.Id)-(SELECT min(Delta) FROM Frames WHERE EventId=Events.Id) as FullLength, + Events.*, + unix_timestamp(Events.StartTime) as Time, M.Name as MonitorName, M.Width as MonitorWidth, M.Height as MonitorHeight, M.Palette - FROM Frames as F - INNER JOIN Events as E on F.EventId = E.Id - INNER JOIN Monitors as M on E.MonitorId = M.Id - WHERE EventId = ? - GROUP BY F.EventId"; + FROM Events + INNER JOIN Monitors as M on Events.MonitorId = M.Id + WHERE Events.Id = ? + "; my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() ); +Debug($sql); my @video_files; foreach my $event_id ( @event_ids ) { @@ -237,8 +237,9 @@ if ( $concat_name ) { } close $fd; my $command = $Config{ZM_PATH_FFMPEG} - . " -f concat -i $concat_list_file -c copy " - ." '$video_file' > ffmpeg.log 2>&1" + . " -f concat -safe 0 -i $concat_list_file -c copy " + .$Config{ZM_FFMPEG_OUTPUT_OPTIONS} + ." '$video_file' > $Config{ZM_PATH_LOGS}/ffmpeg_${concat_name}.log 2>&1" ; Debug( $command."\n" ); my $output = qx($command); @@ -247,10 +248,10 @@ if ( $concat_name ) { unlink $concat_list_file; if ( $status ) { - Error( "Unable to generate video, check /ffmpeg.log for details"); + Error( "Unable to generate video, check $Config{ZM_PATH_LOGS}/ffmpeg_${concat_name}.log for details"); exit(-1); } - print( STDOUT $video_file."\n" ); + print( STDOUT $video_file."\n" ); } exit( 0 ); From 4bca799d435807ed77023568d69859d2f6efa267 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Mon, 17 Jul 2017 08:11:36 -0500 Subject: [PATCH 011/114] reorganize zm config files (#1937) * reogranize config files * process 01-system-paths.conf.in * exclude .in files in install directive --- CMakeLists.txt | 5 +-- conf.d/01-system-paths.conf.in | 53 ++++++++++++++++++++++++++++++++ conf.d/02-multiserver.conf | 12 ++++++++ conf.d/zm-server-host.conf | 7 ----- distros/redhat/zoneminder.spec | 10 ++++-- zm.conf.in | 56 +++++++--------------------------- 6 files changed, 87 insertions(+), 56 deletions(-) create mode 100644 conf.d/01-system-paths.conf.in create mode 100644 conf.d/02-multiserver.conf delete mode 100644 conf.d/zm-server-host.conf diff --git a/CMakeLists.txt b/CMakeLists.txt index edf9cc615..e1c605d6f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -801,11 +801,12 @@ endif(ZM_PERL_SEARCH_PATH) # If this is an out-of-source build, copy the files we need to the binary directory if(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)) - file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/conf.d" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/conf.d") + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/conf.d" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/conf.d" PATTERN "*.in" EXCLUDE) endif(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)) # Generate files from the .in files configure_file(zm.conf.in "${CMAKE_CURRENT_BINARY_DIR}/zm.conf" @ONLY) +configure_file(conf.d/01-system-paths.conf.in "${CMAKE_CURRENT_BINARY_DIR}/conf.d/01-system-paths.conf" @ONLY) configure_file(zoneminder-config.cmake "${CMAKE_CURRENT_BINARY_DIR}/config.h" @ONLY) configure_file(zmconfgen.pl.in "${CMAKE_CURRENT_BINARY_DIR}/zmconfgen.pl" @ONLY) configure_file(zmlinkcontent.sh.in "${CMAKE_CURRENT_BINARY_DIR}/zmlinkcontent.sh" @ONLY) @@ -850,7 +851,7 @@ endif(zmconfgen_result EQUAL 0) # Install zm.conf and conf.d subfolder install(FILES "${CMAKE_CURRENT_BINARY_DIR}/zm.conf" DESTINATION "${ZM_CONFIG_DIR}") -install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/conf.d/" DESTINATION "${ZM_CONFIG_SUBDIR}") +install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/conf.d/" DESTINATION "${ZM_CONFIG_SUBDIR}" PATTERN "*.in" EXCLUDE) # Uninstall target configure_file( diff --git a/conf.d/01-system-paths.conf.in b/conf.d/01-system-paths.conf.in new file mode 100644 index 000000000..9f45abdbd --- /dev/null +++ b/conf.d/01-system-paths.conf.in @@ -0,0 +1,53 @@ +# ========================================================================== +# +# ZoneMinder System Paths Configuration +# +# ========================================================================== +# +# This config file contains the variables previously found under Options -> Paths +# +# *** DO NOT EDIT THIS FILE *** +# +# To make custom changes to the variables below, create a new configuration +# file, with an extention of .conf, containing your desired modifications. +# + +# Full path to the folder events are recorded to. +# The web account user must have full read/write permission to this folder. +ZM_DIR_EVENTS=@ZM_DIR_EVENTS@ + +# Full path to the folder images, not directly associated with events, +# are recorded to. +# The web account user must have full read/write permission to this folder. +ZM_DIR_IMAGES=@ZM_DIR_IMAGES@ + +# Foldername under the webroot where ZoneMinder looks for optional sound files +# to play when an alarm is detected. +ZM_DIR_SOUNDS=@ZM_DIR_SOUNDS@ + +# Full path to the folder where exported archives are stored +# The web account user must have full read/write permission to this folder. +ZM_DIR_EXPORTS=@ZM_TMPDIR@ + +# ZoneMinder url path to the zms streaming server +ZM_PATH_ZMS=@ZM_PATH_ZMS@ + +# Full Path to ZoneMinder's mapped memory files +# The web account user must have full read/write permission to this folder. +ZM_PATH_MAP=@ZM_PATH_MAP@ + +# Full Path to ZoneMinder's socket folder +# The web account user must have full read/write permission to this folder. +ZM_PATH_SOCKS=@ZM_SOCKDIR@ + +# Full path to ZoneMinder's log folder +# The web account user must have full read/write permission to this folder. +ZM_PATH_LOGS=@ZM_LOGDIR@ + +# Full path to ZoneMinder's swap folder +# The web account user must have full read/write permission to this folder. +ZM_PATH_SWAP=@ZM_TMPDIR@ + +# Full path to optional arp binary +# ZoneMinder will find the arp binary automatically on most systems +ZM_PATH_ARP=@ZM_PATH_ARP@ diff --git a/conf.d/02-multiserver.conf b/conf.d/02-multiserver.conf new file mode 100644 index 000000000..d2fdfcca7 --- /dev/null +++ b/conf.d/02-multiserver.conf @@ -0,0 +1,12 @@ +# ========================================================================== +# +# ZoneMinder Multiserver Configuration +# +# ========================================================================== +# Do NOT set ZM_SERVER_HOST if you are not using Multi-Server +# You have been warned +# +# The name specified here must have a corresponding entry +# in the Servers tab under Options +#ZM_SERVER_HOST= + diff --git a/conf.d/zm-server-host.conf b/conf.d/zm-server-host.conf deleted file mode 100644 index 7c61c200d..000000000 --- a/conf.d/zm-server-host.conf +++ /dev/null @@ -1,7 +0,0 @@ -# Do NOT set ZM_SERVER_HOST if you are not using Multi-Server -# You have been warned -# -# The name specified here must have a corresponding entry -# in the Servers tab under Options -ZM_SERVER_HOST= - diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index f60ae222a..baf87b2f6 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -286,12 +286,18 @@ rm -rf %{_docdir}/%{name}-%{version} %files %license COPYING %doc AUTHORS README.md distros/redhat/readme/README.%{readme_suffix} distros/redhat/readme/README.https distros/redhat/jscalendar-doc + +# We want these two folders to have "normal" read permission +# compared to the folder contents %dir %{_sysconfdir}/zm %dir %{_sysconfdir}/zm/conf.d + +# Config folder contents contain sensitive info +# and should not be readable by normal users %{_sysconfdir}/zm/conf.d/README -# Always overwrite zm.conf now that ZoneMinder supports conf.d folder -%attr(640,root,%{zmgid_final}) %{_sysconfdir}/zm/zm.conf +%config(noreplace) %attr(640,root,%{zmgid_final}) %{_sysconfdir}/zm/zm.conf %config(noreplace) %attr(640,root,%{zmgid_final}) %{_sysconfdir}/zm/conf.d/*.conf +%ghost %{_sysconfdir}/zm/conf.d/zmcustom.conf %config(noreplace) %attr(644,root,root) %{wwwconfdir}/zoneminder.conf %config(noreplace) %{_sysconfdir}/logrotate.d/zoneminder diff --git a/zm.conf.in b/zm.conf.in index c417aacd2..bde068104 100644 --- a/zm.conf.in +++ b/zm.conf.in @@ -1,16 +1,15 @@ # ========================================================================== # -# ZoneMinder Base Configuration File +# ZoneMinder Base Configuration # # ========================================================================== # # *** DO NOT EDIT THIS FILE *** -# Changes made directly to this configuration file are no longer supported. -# They will be overwritten during an upgrade. # -# Instead, create a custom configuration file, with an extention of ".conf" -# under the @ZM_CONFIG_SUBDIR@ subfolder containing your desired modifications. -# +# To make custom changes to the variables below, create a new configuration +# file, with an extention of .conf, under the @ZM_CONFIG_SUBDIR@ +# folder, containing your desired modifications. +# # Path to installed data directory, used mostly for finding DB upgrade scripts ZM_PATH_DATA=@PKGDATADIR@ @@ -50,43 +49,10 @@ ZM_DB_USER=@ZM_DB_USER@ # ZoneMinder database password ZM_DB_PASS=@ZM_DB_PASS@ -# Full path to the folder events are recorded to. -# The web account user must have full read/write permission to this folder. -ZM_DIR_EVENTS=@ZM_DIR_EVENTS@ - -# Full path to the folder images, not directly associated with events, -# are recorded to. -# The web account user must have full read/write permission to this folder. -ZM_DIR_IMAGES=@ZM_DIR_IMAGES@ - -# Foldername under the webroot where ZoneMinder looks for optional sound files -# to play when an alarm is detected. -ZM_DIR_SOUNDS=@ZM_DIR_SOUNDS@ - -# Full path to the folder where exported archives are stored -# The web account user must have full read/write permission to this folder. -ZM_DIR_EXPORTS=@ZM_TMPDIR@ - -# ZoneMinder url path to the zms streaming server -ZM_PATH_ZMS=@ZM_PATH_ZMS@ - -# Full Path to ZoneMinder's mapped memory files -# The web account user must have full read/write permission to this folder. -ZM_PATH_MAP=@ZM_PATH_MAP@ - -# Full Path to ZoneMinder's socket folder -# The web account user must have full read/write permission to this folder. -ZM_PATH_SOCKS=@ZM_SOCKDIR@ - -# Full path to ZoneMinder's log folder -# The web account user must have full read/write permission to this folder. -ZM_PATH_LOGS=@ZM_LOGDIR@ - -# Full path to ZoneMinder's swap folder -# The web account user must have full read/write permission to this folder. -ZM_PATH_SWAP=@ZM_TMPDIR@ - -# Full path to optional arp binary -# ZoneMinder will find the arp binary automatically on most systems -ZM_PATH_ARP=@ZM_PATH_ARP@ +# Do NOT set ZM_SERVER_HOST if you are not using Multi-Server +# You have been warned +# +# The name specified here must have a corresponding entry +# in the Servers tab under Options +ZM_SERVER_HOST= From d931945619cf96bdecbaa4b8219f8791a2583f2b Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Thu, 20 Jul 2017 17:53:06 -0500 Subject: [PATCH 012/114] Update zoneminder.spec we have to tell rpm what permission zmcustom.conf has to prevent the build from failing on el6 --- distros/redhat/zoneminder.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index baf87b2f6..d56c0cc21 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -297,7 +297,7 @@ rm -rf %{_docdir}/%{name}-%{version} %{_sysconfdir}/zm/conf.d/README %config(noreplace) %attr(640,root,%{zmgid_final}) %{_sysconfdir}/zm/zm.conf %config(noreplace) %attr(640,root,%{zmgid_final}) %{_sysconfdir}/zm/conf.d/*.conf -%ghost %{_sysconfdir}/zm/conf.d/zmcustom.conf +%ghost %attr(640,root,%{zmgid_final}) %{_sysconfdir}/zm/conf.d/zmcustom.conf %config(noreplace) %attr(644,root,root) %{wwwconfdir}/zoneminder.conf %config(noreplace) %{_sysconfdir}/logrotate.d/zoneminder From 91ccba137fd2c9cba638e1261c476e72c8e60286 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Fri, 21 Jul 2017 07:18:13 -0500 Subject: [PATCH 013/114] Don't create symlinks in ZoneMinder webroot (#1923) * don't create symlinks during rpm packaging * don't use symlinks when pacakging debs * change default values for zm_dir_events and zm_dir_images * remove zm_contentdir cmake var from debian packaging * change default for zm_config_subdir * update INSTALL documentation --- CMakeLists.txt | 10 +++++----- INSTALL | 8 ++++++++ distros/debian/rules | 1 - distros/redhat/CMakeLists.txt | 5 +---- distros/ubuntu1204/rules | 1 - distros/ubuntu1204/zoneminder.links | 3 --- distros/ubuntu1504_cmake_split_packages/rules | 1 - .../zoneminder-core.links | 3 --- .../zoneminder-ui-base.links | 1 - .../ubuntu1604/patches/default_cgi-path.patch | 16 ---------------- distros/ubuntu1604/rules | 1 - distros/ubuntu1604/zoneminder.links | 3 --- 12 files changed, 14 insertions(+), 39 deletions(-) delete mode 100644 distros/ubuntu1504_cmake_split_packages/zoneminder-core.links delete mode 100644 distros/ubuntu1504_cmake_split_packages/zoneminder-ui-base.links delete mode 100644 distros/ubuntu1604/patches/default_cgi-path.patch diff --git a/CMakeLists.txt b/CMakeLists.txt index e1c605d6f..0c104998a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,11 +137,11 @@ set(ZM_WEB_USER "" CACHE STRING set(ZM_WEB_GROUP "" CACHE STRING "The group apache or the local web server runs on, Leave empty to be the same as the web user") -set(ZM_DIR_EVENTS "events" CACHE PATH - "Location where events are recorded to, default: events") -set(ZM_DIR_IMAGES "events" CACHE PATH +set(ZM_DIR_EVENTS "${ZM_CONTENTDIR}/events" CACHE PATH + "Location where events are recorded to, default: ZM_CONTENTDIR/events") +set(ZM_DIR_IMAGES "${ZM_CONTENTDIR}/images" CACHE PATH "Location where images, not directly associated with events, - are recorded to, default: images") + are recorded to, default: ZM_CONTENTDIR/images") set(ZM_DIR_SOUNDS "sounds" CACHE PATH "Location to look for optional sound files, default: sounds") set(ZM_PATH_ZMS "/cgi-bin/nph-zms" CACHE PATH @@ -154,7 +154,7 @@ set(ZM_PATH_ARP "" CACHE PATH "Full path to compatible arp binary. Leave empty for automatic detection.") set(ZM_CONFIG_DIR "/${CMAKE_INSTALL_SYSCONFDIR}" CACHE PATH "Location of ZoneMinder configuration, default system config directory") -set(ZM_CONFIG_SUBDIR "${ZM_CONFIG_DIR}/conf.d" CACHE PATH +set(ZM_CONFIG_SUBDIR "${ZM_CONFIG_DIR}/zm/conf.d" CACHE PATH "Location of ZoneMinder configuration subfolder, default: ZM_CONFIG_DIR/conf.d") set(ZM_EXTRA_LIBS "" CACHE STRING "A list of optional libraries, separated by semicolons, e.g. ssl;theora") diff --git a/INSTALL b/INSTALL index bcb7f78df..3b50f5b62 100644 --- a/INSTALL +++ b/INSTALL @@ -47,7 +47,15 @@ Possible configuration options: ZM_DB_PASS Password of ZoneMinder database user, default: zmpass ZM_WEB_USER The user apache or the local web server runs on. Leave empty for automatic detection. If that fails, you can use this variable to force ZM_WEB_GROUP The group apache or the local web server runs on, Leave empty to be the same as the web user + ZM_DIR_EVENTS Location where events are recorded to, default: ZM_CONTENTDIR/events + ZM_DIR_IMAGES Location where images, not directly associated with events, are recorded to, default: ZM_CONTENTDIR/images + ZM_DIR_SOUNDS Location to look for optional sound files, default: sounds + ZM_PATH_ZMS Web url to zms streaming server, default: /cgi-bin/nph-zms Advanced: + ZM_PATH_MAP Location to save mapped memory files, default: /dev/shm + ZM_PATH_ARP Full path to compatible arp binary. Leave empty for automatic detection. + ZM_CONFIG_DIR Location of the main ZoneMinder config file, zm.conf. default: /etc/zm + ZM_CONFIG_SUBDIR Location of custom config files. default: ZM_CONFIG_DIR/conf.d ZM_EXTRA_LIBS A list of optional libraries, separated by semicolons, e.g. ssl;theora ZM_MYSQL_ENGINE MySQL engine to use with database, default: InnoDB ZM_NO_MMAP Set to ON to not use mmap shared memory. Shouldn't be enabled unless you experience problems with the shared memory. default: OFF diff --git a/distros/debian/rules b/distros/debian/rules index 929f054df..fe725c2d0 100755 --- a/distros/debian/rules +++ b/distros/debian/rules @@ -18,7 +18,6 @@ override_dh_auto_configure: -DZM_TMPDIR=/var/tmp/zm \ -DZM_LOGDIR=/var/log/zm \ -DZM_WEBDIR=/usr/share/zoneminder/www \ - -DZM_CONTENTDIR=/var/cache/zoneminder \ -DZM_CGIDIR=/usr/lib/zoneminder/cgi-bin \ -DZM_WEB_USER=www-data \ -DZM_WEB_GROUP=www-data \ diff --git a/distros/redhat/CMakeLists.txt b/distros/redhat/CMakeLists.txt index 7684fb975..73f88f968 100644 --- a/distros/redhat/CMakeLists.txt +++ b/distros/redhat/CMakeLists.txt @@ -55,10 +55,7 @@ install(DIRECTORY zoneminder DESTINATION /var/run DIRECTORY_PERMISSIONS OWNER_WR install(DIRECTORY zoneminder-upload DESTINATION /var/spool DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) install(DIRECTORY events images temp DESTINATION /var/lib/zoneminder DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) -# Create symlinks -install(CODE "execute_process(COMMAND ln -sf ../../../../var/lib/zoneminder/events \"\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/zoneminder/www/events\")") -install(CODE "execute_process(COMMAND ln -sf ../../../../var/lib/zoneminder/images \"\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/zoneminder/www/images\")") -install(CODE "execute_process(COMMAND ln -sf ../../../../var/lib/zoneminder/temp \"\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/zoneminder/www/temp\")") +# Symlink the cake php temp folder to the ZoneMinder temp folder install(CODE "execute_process(COMMAND ln -sf ../../../../../../var/lib/zoneminder/temp \"\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/zoneminder/www/api/app/tmp\")") # Link to Cambozola diff --git a/distros/ubuntu1204/rules b/distros/ubuntu1204/rules index dcf11864b..0103d1c27 100755 --- a/distros/ubuntu1204/rules +++ b/distros/ubuntu1204/rules @@ -25,7 +25,6 @@ override_dh_auto_configure: -DZM_SOCKDIR="/var/run/zm" \ -DZM_TMPDIR="/tmp/zm" \ -DZM_CGIDIR="/usr/lib/zoneminder/cgi-bin" \ - -DZM_CONTENTDIR="/var/cache/zoneminder" \ -DZM_DIR_EVENTS="/var/cache/zoneminder/events" \ -DZM_DIR_IMAGES="/var/cache/zoneminder/images" \ -DZM_PATH_ZMS="/zm/cgi-bin/nph-zms" \ diff --git a/distros/ubuntu1204/zoneminder.links b/distros/ubuntu1204/zoneminder.links index 4c44d3238..373548919 100644 --- a/distros/ubuntu1204/zoneminder.links +++ b/distros/ubuntu1204/zoneminder.links @@ -1,4 +1 @@ -/var/cache/zoneminder/events /usr/share/zoneminder/www/events -/var/cache/zoneminder/images /usr/share/zoneminder/www/images -/var/cache/zoneminder/temp /usr/share/zoneminder/www/temp /tmp/zm /usr/share/zoneminder/www/api/app/tmp diff --git a/distros/ubuntu1504_cmake_split_packages/rules b/distros/ubuntu1504_cmake_split_packages/rules index 7c8fc232d..0eca4b511 100755 --- a/distros/ubuntu1504_cmake_split_packages/rules +++ b/distros/ubuntu1504_cmake_split_packages/rules @@ -58,7 +58,6 @@ override_dh_auto_configure: -DZM_TMPDIR=/var/tmp/zm \ -DZM_LOGDIR=/var/log/zm \ -DZM_WEBDIR=/usr/share/zoneminder \ - -DZM_CONTENTDIR=/var/cache/zoneminder \ -DZM_CGIDIR=/usr/lib/cgi-bin \ -DZM_WEB_USER=www-data \ -DZM_WEB_GROUP=www-data \ diff --git a/distros/ubuntu1504_cmake_split_packages/zoneminder-core.links b/distros/ubuntu1504_cmake_split_packages/zoneminder-core.links deleted file mode 100644 index e7d90d176..000000000 --- a/distros/ubuntu1504_cmake_split_packages/zoneminder-core.links +++ /dev/null @@ -1,3 +0,0 @@ -var/cache/zoneminder/events usr/share/zoneminder/www/events -var/cache/zoneminder/images usr/share/zoneminder/www/images -var/cache/zoneminder/temp usr/share/zoneminder/www/temp diff --git a/distros/ubuntu1504_cmake_split_packages/zoneminder-ui-base.links b/distros/ubuntu1504_cmake_split_packages/zoneminder-ui-base.links deleted file mode 100644 index b00a147d6..000000000 --- a/distros/ubuntu1504_cmake_split_packages/zoneminder-ui-base.links +++ /dev/null @@ -1 +0,0 @@ -usr/lib/cgi-bin usr/share/zoneminder/cgi-bin diff --git a/distros/ubuntu1604/patches/default_cgi-path.patch b/distros/ubuntu1604/patches/default_cgi-path.patch deleted file mode 100644 index 8bfc2ba06..000000000 --- a/distros/ubuntu1604/patches/default_cgi-path.patch +++ /dev/null @@ -1,16 +0,0 @@ -Last-Update: 2015-08-16 -Forwarded: no -Author: Dmitry Smirnov -Description: correct path to CGI app according to default web server configuration. - ---- a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in -+++ b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in -@@ -428,7 +428,7 @@ our @options = - }, - { - name => "ZM_PATH_ZMS", -- default => "/cgi-bin/nph-zms", -+ default => "/zm/cgi-bin/nph-zms", - description => "Web path to zms streaming server", - help => qqq(" - The ZoneMinder streaming server is required to send streamed diff --git a/distros/ubuntu1604/rules b/distros/ubuntu1604/rules index b78361212..6bc3dffb5 100755 --- a/distros/ubuntu1604/rules +++ b/distros/ubuntu1604/rules @@ -25,7 +25,6 @@ override_dh_auto_configure: -DZM_SOCKDIR="/var/run/zm" \ -DZM_TMPDIR="/tmp/zm" \ -DZM_CGIDIR="/usr/lib/zoneminder/cgi-bin" \ - -DZM_CONTENTDIR="/var/cache/zoneminder" \ -DZM_DIR_EVENTS="/var/cache/zoneminder/events" \ -DZM_DIR_IMAGES="/var/cache/zoneminder/images" \ -DZM_PATH_ZMS="/zm/cgi-bin/nph-zms" diff --git a/distros/ubuntu1604/zoneminder.links b/distros/ubuntu1604/zoneminder.links index 14a8aee91..b7258c3c4 100644 --- a/distros/ubuntu1604/zoneminder.links +++ b/distros/ubuntu1604/zoneminder.links @@ -1,4 +1 @@ -/var/cache/zoneminder/events /usr/share/zoneminder/www/events -/var/cache/zoneminder/images /usr/share/zoneminder/www/images -/var/cache/zoneminder/temp /usr/share/zoneminder/www/temp /var/tmp /usr/share/zoneminder/www/api/app/tmp From ee7d714d591b88ddb482b69039d2a4606add1e48 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 21 Jul 2017 10:54:09 -0400 Subject: [PATCH 014/114] refuse and log attempt to delete an event without full info --- scripts/ZoneMinder/lib/ZoneMinder/Event.pm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm index 6f2d6addc..e9af77479 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm @@ -238,6 +238,11 @@ sub GenerateVideo { sub delete { my $event = $_[0]; + if ( ! ( $event->{Id} and $event->{MonitorId} and $event->{StartTime} ) ) { + my ( $caller, undef, $line ) = caller; + Warning( "Can't Delete event $event->{Id} from Monitor $event->{MonitorId} $event->{StartTime} from $caller:$line\n" ); + return; + } Info( "Deleting event $event->{Id} from Monitor $event->{MonitorId} $event->{StartTime}\n" ); $ZoneMinder::Database::dbh->ping(); # Do it individually to avoid locking up the table for new events From 457d909c889437b2f096a255d3bdf8537f3f33c7 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 21 Jul 2017 10:54:33 -0400 Subject: [PATCH 015/114] fix quotes --- web/skins/classic/views/console.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index 3f39029ed..ac0dc8528 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -51,7 +51,7 @@ $eventCounts = array( 'filter' => array( 'Query' => array( 'terms' => array( - array( 'attr' => "DateTime", 'op' => '>=', 'val' => '-1 day' ), + array( 'attr' => 'DateTime', 'op' => '>=', 'val' => '-1 day' ), ) ) ), @@ -62,7 +62,7 @@ $eventCounts = array( 'filter' => array( 'Query' => array( 'terms' => array( - array( 'attr' => "DateTime", 'op' => '>=', 'val' => '-7 day' ), + array( 'attr' => 'DateTime', 'op' => '>=', 'val' => '-7 day' ), ) ) ), @@ -73,7 +73,7 @@ $eventCounts = array( 'filter' => array( 'Query' => array( 'terms' => array( - array( 'attr' => "DateTime", 'op' => '>=', 'val' => '-1 month' ), + array( 'attr' => 'DateTime', 'op' => '>=', 'val' => '-1 month' ), ) ) ), @@ -84,7 +84,7 @@ $eventCounts = array( 'filter' => array( 'Query' => array( 'terms' => array( - array( 'attr' => "Archived", 'op' => '=', 'val' => '1' ), + array( 'attr' => 'Archived', 'op' => '=', 'val' => '1' ), ) ) ), @@ -107,7 +107,7 @@ for( $i = 0; $i < count($displayMonitors); $i += 1 ) { for ( $j = 0; $j < count($eventCounts); $j += 1 ) { $filter = addFilterTerm( $eventCounts[$j]['filter'], count($eventCounts[$j]['filter']['Query']['terms']), array( 'cnj' => 'and', 'attr' => 'MonitorId', 'op' => '=', 'val' => $monitor['Id'] ) ); parseFilter( $filter ); - $counts[] = "count(if(1".$filter['sql'].",1,NULL)) as EventCount$j"; + $counts[] = 'count(if(1'.$filter['sql'].",1,NULL)) as EventCount$j"; $monitor['eventCounts'][$j]['filter'] = $filter; } $sql = 'select '.join($counts,', ').' from Events as E where MonitorId = ?'; From efb02f3368633c997ee8609ccd04fe6fe44a73e1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 21 Jul 2017 10:54:48 -0400 Subject: [PATCH 016/114] fix indent --- web/api/app/Config/bootstrap.php.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/api/app/Config/bootstrap.php.in b/web/api/app/Config/bootstrap.php.in index a3213d150..bbc3630e4 100644 --- a/web/api/app/Config/bootstrap.php.in +++ b/web/api/app/Config/bootstrap.php.in @@ -138,8 +138,8 @@ if ( is_dir($configSubFolder) ) { # Now that our array our finalized, define each key => value # pair in the array as a constant foreach( $configvals as $key => $value) { - define( $key, $value ); - Configure::write( $matches[1], $matches[2] ); + define( $key, $value ); + Configure::write( $key, $value ); } function process_configfile($configFile) { From 1cfd657168b379ad09324675babbe07b56303342 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 26 Jul 2017 10:22:57 -0400 Subject: [PATCH 017/114] put back the preg_replace that strips usernames and passwords from monitor source --- web/skins/classic/views/console.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index ad6891161..c5a3c9784 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -255,16 +255,16 @@ echo $Server->Name(); Date: Wed, 26 Jul 2017 10:38:18 -0400 Subject: [PATCH 018/114] Don't keep setting the event_file unnecessarily. Add some code comments --- src/zm_monitor.cpp | 16 +++++++++------- src/zm_monitorstream.cpp | 5 +++-- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 1f1c2413e..88683a698 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1319,14 +1319,15 @@ bool Monitor::Analyse() { score += motion_score; } noteSetMap[MOTION_CAUSE] = zoneSet; - - } + } // end if motion_score shared_data->active = signal; - } + } // end if signal change + if ( (!signal_change && signal) && n_linked_monitors > 0 ) { bool first_link = true; Event::StringSet noteSet; for ( int i = 0; i < n_linked_monitors; i++ ) { + // TODO: Shouldn't we try to connect? if ( linked_monitors[i]->isConnected() ) { if ( linked_monitors[i]->hasAlarmed() ) { if ( !event ) { @@ -1352,11 +1353,12 @@ bool Monitor::Analyse() { if ( (!signal_change && signal) && (function == RECORD || function == MOCORD) ) { if ( event ) { //TODO: We shouldn't have to do this every time. Not sure why it clears itself if this isn't here?? - snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "%s", event->getEventFile()); + //snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "%s", event->getEventFile()); Debug( 3, "Detected new event at (%d.%d)", timestamp->tv_sec,timestamp->tv_usec ); if ( section_length ) { - int section_mod = timestamp->tv_sec%section_length; + // TODO: Wouldn't this be clearer if we just did something like if now - event->start > section_length ? + int section_mod = timestamp->tv_sec % section_length; Debug( 3, "Section length (%d) Last Section Mod(%d), new section mod(%d)", section_length, last_section_mod, section_mod ); if ( section_mod < last_section_mod ) { //if ( state == IDLE || state == TAPE || event_close_mode == CLOSE_TIME ) { @@ -1374,8 +1376,8 @@ bool Monitor::Analyse() { } else { last_section_mod = section_mod; } - } - } // end if section_length + } // end if section_length + } // end if event if ( ! event ) { diff --git a/src/zm_monitorstream.cpp b/src/zm_monitorstream.cpp index 699ad6644..aaa5e8289 100644 --- a/src/zm_monitorstream.cpp +++ b/src/zm_monitorstream.cpp @@ -732,8 +732,9 @@ void MonitorStream::runStream() { if ( rmdir( swap_path ) < 0 ) { Error( "Can't rmdir '%s': %s", swap_path, strerror(errno) ); } - } - } + } // end if checking for swap_path + } // end if buffered_playback + if ( swap_path ) free( swap_path ); closeComms(); } From 1f8871639a4f52868d15fcd84e7c0ebfa6f882b6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 27 Jul 2017 09:56:07 -0400 Subject: [PATCH 019/114] only complain about losing the dbh connection, if we can't reconnect --- scripts/zmaudit.pl.in | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/scripts/zmaudit.pl.in b/scripts/zmaudit.pl.in index 0a111f899..db8ca5933 100644 --- a/scripts/zmaudit.pl.in +++ b/scripts/zmaudit.pl.in @@ -144,15 +144,16 @@ MAIN: while( $loop ) { # After a long sleep, we may need to reconnect to the db while ( ! ( $dbh and $dbh->ping() ) ) { $dbh = zmDbConnect(); - - if ( $continuous ) { - Error('Unable to connect to database'); -# if we are running continuously, then just skip to the next -# interval, otherwise we are a one off run, so wait a second and -# retry until someone kills us. - sleep( $Config{ZM_AUDIT_CHECK_INTERVAL} ); - } else { - Fatal('Unable to connect to database'); + if ( ! $dbh ) { + if ( $continuous ) { + Error('Unable to connect to database'); + # if we are running continuously, then just skip to the next + # interval, otherwise we are a one off run, so wait a second and + # retry until someone kills us. + sleep( $Config{ZM_AUDIT_CHECK_INTERVAL} ); + } else { + Fatal('Unable to connect to database'); + } # end if } # end if } # end while can't connect to the db From 792d8640c293b701227df05232d7ebda82a41d8d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 28 Jul 2017 09:54:33 -0400 Subject: [PATCH 020/114] use the analyze file if exists as thumbnail --- web/includes/Event.php | 43 ++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/web/includes/Event.php b/web/includes/Event.php index 70668690b..ebc0c61f8 100644 --- a/web/includes/Event.php +++ b/web/includes/Event.php @@ -217,28 +217,31 @@ class Event { $captImage = 'snapshot.jpg'; Debug("Frame not specified, using snapshot"); } else { - $captImage = sprintf( '%0'.ZM_EVENT_IMAGE_DIGITS.'d-capture.jpg', $frame['FrameId'] ); + $captImage = sprintf( '%0'.ZM_EVENT_IMAGE_DIGITS.'d-analyze.jpg', $frame['FrameId'] ); if ( ! file_exists( $eventPath.'/'.$captImage ) ) { - # Generate the frame JPG - if ( $Event->DefaultVideo() ) { - $videoPath = $eventPath.'/'.$Event->DefaultVideo(); + $captImage = sprintf( '%0'.ZM_EVENT_IMAGE_DIGITS.'d-capture.jpg', $frame['FrameId'] ); + if ( ! file_exists( $eventPath.'/'.$captImage ) ) { + # Generate the frame JPG + if ( $Event->DefaultVideo() ) { + $videoPath = $eventPath.'/'.$Event->DefaultVideo(); - if ( ! file_exists( $videoPath ) ) { - Error("Event claims to have a video file, but it does not seem to exist at $videoPath" ); - return ''; - } - - #$command ='ffmpeg -v 0 -i '.$videoPath.' -vf "select=gte(n\\,'.$frame['FrameId'].'),setpts=PTS-STARTPTS" '.$eventPath.'/'.$captImage; - $command ='ffmpeg -ss '. $frame['Delta'] .' -i '.$videoPath.' -frames:v 1 '.$eventPath.'/'.$captImage; - Logger::Debug( "Running $command" ); - $output = array(); - $retval = 0; - exec( $command, $output, $retval ); - Logger::Debug("Retval: $retval, output: " . implode("\n", $output)); - } else { - Error("Can't create frame images from video becuase there is no video file for this event (".$Event->DefaultVideo() ); - } - } + if ( ! file_exists( $videoPath ) ) { + Error("Event claims to have a video file, but it does not seem to exist at $videoPath" ); + return ''; + } + + #$command ='ffmpeg -v 0 -i '.$videoPath.' -vf "select=gte(n\\,'.$frame['FrameId'].'),setpts=PTS-STARTPTS" '.$eventPath.'/'.$captImage; + $command ='ffmpeg -ss '. $frame['Delta'] .' -i '.$videoPath.' -frames:v 1 '.$eventPath.'/'.$captImage; + Logger::Debug( "Running $command" ); + $output = array(); + $retval = 0; + exec( $command, $output, $retval ); + Logger::Debug("Retval: $retval, output: " . implode("\n", $output)); + } else { + Error("Can't create frame images from video becuase there is no video file for this event (".$Event->DefaultVideo() ); + } + } // end if capture file exists + } // end if analyze file exists } $captPath = $eventPath.'/'.$captImage; From 259b7f765526aac9551e4f80c96c61ff3bdc7802 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 31 Jul 2017 15:49:27 -0400 Subject: [PATCH 021/114] fix memleak --- src/zm_ffmpeg_camera.cpp | 22 ++++++++++------------ src/zm_packetqueue.cpp | 2 +- src/zm_videostore.cpp | 15 +++++++++++++-- src/zm_zone.cpp | 2 +- web/skins/classic/views/events.php | 4 +++- 5 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index eaaf20456..dc29363cf 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -270,15 +270,15 @@ int FfmpegCamera::OpenFfmpeg() { } // Set transport method as specified by method field, rtpUni is default - if (Method() == "rtpMulti") { + if ( Method() == "rtpMulti" ) { ret = av_dict_set(&opts, "rtsp_transport", "udp_multicast", 0); - } else if (Method() == "rtpRtsp") { + } else if ( Method() == "rtpRtsp" ) { ret = av_dict_set(&opts, "rtsp_transport", "tcp", 0); - } else if (Method() == "rtpRtspHttp") { + } else if ( Method() == "rtpRtspHttp" ) { ret = av_dict_set(&opts, "rtsp_transport", "http", 0); } - if (ret < 0) { + if ( ret < 0 ) { Warning("Could not set rtsp_transport method '%s'\n", Method().c_str()); } @@ -297,7 +297,7 @@ int FfmpegCamera::OpenFfmpeg() { } AVDictionaryEntry *e; - if ((e = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX)) != NULL) { + if ( (e = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX)) != NULL ) { Warning( "Option %s not recognized by ffmpeg", e->key); } @@ -380,7 +380,7 @@ int FfmpegCamera::OpenFfmpeg() { mVideoCodecContext->flags2 |= CODEC_FLAG2_FAST | CODEC_FLAG_LOW_DELAY; // Try and get the codec from the codec context - if ((mVideoCodec = avcodec_find_decoder(mVideoCodecContext->codec_id)) == NULL) { + if ( (mVideoCodec = avcodec_find_decoder(mVideoCodecContext->codec_id)) == NULL ) { Fatal("Can't find codec for video stream from %s", mPath.c_str()); } else { Debug(1, "Video Found decoder"); @@ -388,10 +388,10 @@ int FfmpegCamera::OpenFfmpeg() { // Open the codec #if !LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 8, 0) Debug ( 1, "Calling avcodec_open" ); - if (avcodec_open(mVideoCodecContext, mVideoCodec) < 0) + if ( avcodec_open(mVideoCodecContext, mVideoCodec) < 0 ) #else Debug ( 1, "Calling avcodec_open2" ); - if (avcodec_open2(mVideoCodecContext, mVideoCodec, 0) < 0) + if ( avcodec_open2(mVideoCodecContext, mVideoCodec, 0) < 0 ) #endif Fatal( "Unable to open codec for video stream from %s", mPath.c_str() ); } @@ -837,11 +837,9 @@ else if ( packet.pts && video_last_pts > packet.pts ) { Debug( 3, "Some other stream index %d", packet.stream_index ); #endif } - //if ( videoStore ) { - // the packet contents are ref counted... when queuing, we allocate another packet and reference it with that one, so we should always need to unref here, which should not affect the queued version. - zm_av_packet_unref( &packet ); - //} + // the packet contents are ref counted... when queuing, we allocate another packet and reference it with that one, so we should always need to unref here, which should not affect the queued version. + zm_av_packet_unref( &packet ); } // end while ! frameComplete return (frameCount); } // end FfmpegCamera::CaptureAndRecord diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index d4520caba..497809342 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -30,7 +30,7 @@ zm_packetqueue::zm_packetqueue(){ } zm_packetqueue::~zm_packetqueue() { - + clearQueue(); } bool zm_packetqueue::queuePacket( ZMPacket* zm_packet ) { diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 9cfeb74a9..2fd710dd8 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -189,6 +189,8 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, audio_output_codec = NULL; audio_input_context = NULL; audio_output_stream = NULL; + input_frame = NULL; + output_frame = NULL; #ifdef HAVE_LIBAVRESAMPLE resample_context = NULL; #endif @@ -391,6 +393,15 @@ Debug(2, "writing flushed packet pts(%d) dts(%d) duration(%d)", pkt.pts, pkt.dts /* free the stream */ avformat_free_context(oc); + + if ( input_frame ) { + av_frame_free( &input_frame ); + input_frame = NULL; + } + if ( output_frame ) { + av_frame_free( &output_frame ); + output_frame = NULL; + } } bool VideoStore::setup_resampler() { @@ -495,13 +506,13 @@ bool VideoStore::setup_resampler() { } /** Create a new frame to store the audio samples. */ - if (!(input_frame = zm_av_frame_alloc())) { + if ( !(input_frame = zm_av_frame_alloc()) ) { Error("Could not allocate input frame"); return false; } /** Create a new frame to store the audio samples. */ - if (!(output_frame = zm_av_frame_alloc())) { + if ( !(output_frame = zm_av_frame_alloc()) ) { Error("Could not allocate output frame"); av_frame_free( &input_frame ); return false; diff --git a/src/zm_zone.cpp b/src/zm_zone.cpp index 7e4d151ff..1b4cb946f 100644 --- a/src/zm_zone.cpp +++ b/src/zm_zone.cpp @@ -68,7 +68,7 @@ void Zone::Setup( overload_frames = p_overload_frames; extend_alarm_frames = p_extend_alarm_frames; - Debug( 1, "Initialised zone %d/%s - %d - %dx%d - Rgb:%06x, CM:%d, MnAT:%d, MxAT:%d, MnAP:%d, MxAP:%d, FB:%dx%d, MnFP:%d, MxFP:%d, MnBS:%d, MxBS:%d, MnB:%d, MxB:%d, OF: %d, AF: %d", id, label, type, polygon.Width(), polygon.Height(), alarm_rgb, check_method, min_pixel_threshold, max_pixel_threshold, min_alarm_pixels, max_alarm_pixels, filter_box.X(), filter_box.Y(), min_filter_pixels, max_filter_pixels, min_blob_pixels, max_blob_pixels, min_blobs, max_blobs, overload_frames, extend_alarm_frames ); + //Debug( 1, "Initialised zone %d/%s - %d - %dx%d - Rgb:%06x, CM:%d, MnAT:%d, MxAT:%d, MnAP:%d, MxAP:%d, FB:%dx%d, MnFP:%d, MxFP:%d, MnBS:%d, MxBS:%d, MnB:%d, MxB:%d, OF: %d, AF: %d", id, label, type, polygon.Width(), polygon.Height(), alarm_rgb, check_method, min_pixel_threshold, max_pixel_threshold, min_alarm_pixels, max_alarm_pixels, filter_box.X(), filter_box.Y(), min_filter_pixels, max_filter_pixels, min_blob_pixels, max_blob_pixels, min_blobs, max_blobs, overload_frames, extend_alarm_frames ); alarmed = false; was_alarmed = false; diff --git a/web/skins/classic/views/events.php b/web/skins/classic/views/events.php index 7aad2b36e..7c3ffbd4b 100644 --- a/web/skins/classic/views/events.php +++ b/web/skins/classic/views/events.php @@ -193,7 +193,9 @@ foreach ( $events as $event ) { - + From 3b97fdadc45861f1c2069f2005786750ebd6777b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 31 Jul 2017 15:57:07 -0400 Subject: [PATCH 022/114] Fix memleak by freeing input and output frames --- src/zm_videostore.cpp | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 0d6056e3e..2fd710dd8 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -189,6 +189,8 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, audio_output_codec = NULL; audio_input_context = NULL; audio_output_stream = NULL; + input_frame = NULL; + output_frame = NULL; #ifdef HAVE_LIBAVRESAMPLE resample_context = NULL; #endif @@ -391,6 +393,15 @@ Debug(2, "writing flushed packet pts(%d) dts(%d) duration(%d)", pkt.pts, pkt.dts /* free the stream */ avformat_free_context(oc); + + if ( input_frame ) { + av_frame_free( &input_frame ); + input_frame = NULL; + } + if ( output_frame ) { + av_frame_free( &output_frame ); + output_frame = NULL; + } } bool VideoStore::setup_resampler() { @@ -495,13 +506,13 @@ bool VideoStore::setup_resampler() { } /** Create a new frame to store the audio samples. */ - if (!(input_frame = zm_av_frame_alloc())) { + if ( !(input_frame = zm_av_frame_alloc()) ) { Error("Could not allocate input frame"); return false; } /** Create a new frame to store the audio samples. */ - if (!(output_frame = zm_av_frame_alloc())) { + if ( !(output_frame = zm_av_frame_alloc()) ) { Error("Could not allocate output frame"); av_frame_free( &input_frame ); return false; @@ -618,7 +629,7 @@ int VideoStore::writeVideoFramePacket( AVPacket *ipkt ) { int duration; //Scale the PTS of the outgoing packet to be the correct time base - if (ipkt->pts != AV_NOPTS_VALUE) { + if ( ipkt->pts != AV_NOPTS_VALUE ) { if ( ! video_last_pts ) { // This is the first packet. @@ -696,9 +707,9 @@ int VideoStore::writeVideoFramePacket( AVPacket *ipkt ) { } AVPacket safepkt; - memcpy(&safepkt, &opkt, sizeof(AVPacket)); + memcpy( &safepkt, &opkt, sizeof(AVPacket) ); -Debug(1, "writing video packet pts(%d) dts(%d) duration(%d)", opkt.pts, opkt.dts, opkt.duration ); + Debug(1, "writing video packet pts(%d) dts(%d) duration(%d)", opkt.pts, opkt.dts, opkt.duration ); if ((opkt.data == NULL)||(opkt.size < 1)) { Warning("%s:%d: Mangled AVPacket: discarding frame", __FILE__, __LINE__ ); dumpPacket( ipkt); @@ -714,10 +725,14 @@ Debug(1, "writing video packet pts(%d) dts(%d) duration(%d)", opkt.pts, opkt.dts video_previous_dts = opkt.dts; // Unsure if av_interleaved_write_frame() clobbers opkt.dts when out of order, so storing in advance video_previous_pts = opkt.pts; ret = av_interleaved_write_frame(oc, &opkt); - if(ret<0){ + if ( ret < 0 ) { // There's nothing we can really do if the frame is rejected, just drop it and get on with the next Warning("%s:%d: Writing frame [av_interleaved_write_frame()] failed: %s(%d) ", __FILE__, __LINE__, av_make_error_string(ret).c_str(), (ret)); dumpPacket(&safepkt); +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + zm_dump_codecpar( video_input_stream->codecpar ); + zm_dump_codecpar( video_output_stream->codecpar ); +#endif } } From 6d46b36c805f022862ba0368941b539ad96f019e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 1 Aug 2017 14:21:50 -0400 Subject: [PATCH 023/114] Hide close button if not in a popup --- web/skins/classic/views/watch.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/web/skins/classic/views/watch.php b/web/skins/classic/views/watch.php index 8bbb6bda0..c64b66d1e 100644 --- a/web/skins/classic/views/watch.php +++ b/web/skins/classic/views/watch.php @@ -59,7 +59,11 @@ xhtmlHeaders( __FILE__, $monitor->Name()." - ".translate('Feed') );
+
'None'); $result = dbQuery( 'SELECT * FROM Servers ORDER BY Name'); $results = $result->fetchALL(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'Server' ); foreach ( $results as $row => $server_obj ) { - $servers[$server_obj->Id] = $server_obj->Name(); + $servers[$server_obj->Id()] = $server_obj->Name(); } + echo htmlSelect( 'newMonitor[ServerId]', $servers, $monitor->ServerId() ); ?> - -
Type() ); ?>
checked="checked"/>
-
Enabled()) ) { ?> checked="checked"/>
+ -
 ()
 ()
+
Method(), "submitTab( '$tab' );" ); ?>
- /> - - /> - - /> - -
+ V4LMultiBuffer() == 1 ? 'checked="checked"' : '' ) ?>/> + + V4LMultiBuffer() == 0 ? 'checked="checked"' : '' ) ?>/> + + V4LMultiBuffer()) ? 'checked="checked"' : '' ) ?>/> + +
Protocol(), "updateMethods( this );if(this.value=='rtsp'){\$('RTSPDescribe').setStyle('display','table-row');}else{\$('RTSPDescribe').hide();}" ); ?>
Method() ); ?>
Method() ); ?>
 ()
 ()
 ()Method() ); ?>
 (Type()), 'zmOptionHelp', 'optionhelp', '?' ) ?>)
()
()
()
()
 () RTSPDescribe()) ) { ?> checked="checked"/>
checked="checked"/>
RecordAudio()) ) { ?> checked="checked"/>
checked="checked"/>
Controllable()) ) { ?> checked="checked"/>
 
checked="checked"/>
TrackMotion()) ) { ?> checked="checked"/>
DefaultRate() ); ?>
DefaultScale() ); ?>
    
+ +      +
    
 () checked="checked"/>
+ +      +
 () Exif()) ) { ?> checked="checked"/>
'.$monitor['Device'].' ('.$monitor['Channel'].')', canEdit( 'Monitors' ) ) ?>'.preg_replace( '/^.*@/', '', $monitor['Host'] ).'', canEdit( 'Monitors' ) ) ?>'.preg_replace( '/^.*\//', '', $monitor['Path'] ).'', canEdit( 'Monitors' ) ) ?>'.$shortpath.'', canEdit( 'Monitors' ) ) ?>'.preg_replace( '/^.*\//', '', $monitor['Path'] ).'', canEdit( 'Monitors' ) ) ?> 
Id().$filterQuery.$sortQuery.'&page=1', 'zmEvent', array( 'event', reScale( $event->Width(), $scale ), reScale( $event->Height(), $scale ) ), $event->Id().($event->Archived()?'*':'') ) ?> Id().$filterQuery.$sortQuery.'&page=1', 'zmEvent', array( 'event', reScale( $event->Width(), $event->DefaultScale(), ZM_WEB_DEFAULT_SCALE ), reScale( $event->Height(), $event->DefaultScale(), ZM_WEB_DEFAULT_SCALE ) ), validHtmlStr($event->Name()).($event->Archived()?'*':'' ) ) ?>MonitorName() ?>MonitorId(), 'zmMonitor'.$event->Monitorid(), 'monitor', $event->MonitorName(), canEdit( 'Monitors' ) ) + ?> Id(), 'zmEventDetail', 'eventdetail', validHtmlStr($event->Cause()), canEdit( 'Events' ), 'title="'.htmlspecialchars($event->Notes()).'"' ) ?> StartTime()) ) ?> Length() ) ?>
- +
+ - - + - - + + - - - - + + + + - - + + + + Type() != 'Local' && $monitor->Type() != 'File' ) { ?> - + - + - - + + - - - + + + + + + + - - + + @@ -753,148 +763,150 @@ switch ( $tab ) { if ( $optCount && ($optCount%$breakCount == 0) ) echo '
'; ?> - checked="checked"/>  + Triggers() ) && in_array( $optTrigger, $monitor->Triggers() ) ) { ?> checked="checked"/>  - - - - + + + + Type() == 'Local' ) { ?> - - + + Method() == 'v4l1' ) { ?> - - - + + + - - - + + + - - + + Type() == 'Remote' ) { ?> - + Protocol()) || $monitor->Protocol() == 'http' ) { ?> - + - + - - - + + + Type() == 'File' ) { ?> - + Type() == 'cURL' ) { ?> - - - + + + Type() == 'Ffmpeg' || $monitor->Type() == 'Libvlc' ) { ?> - - - + + + - - - - - + + + + + Type() == 'Local' ) { ?> - + + + - - - > + } + ?> + Type() == 'Remote' ) { + ?> + Protocol()!= 'rtsp' ) { echo ' style="display:none;"'; } ?>> - - - - + + + + - - - - + + + + - - - - - - + + + + + + - + - - - - + + + + translate('None'), @@ -902,9 +914,9 @@ switch ( $tab ) { '1' => translate('Preset')." 1", ); ?> - + - + - - - - - - - + + + + + + - - + + + Type() == 'Local' ) { ?> - + + + + - - + + + + + + + + From 00533fc6241b7724a19b6b606bc49722dde23dc1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 3 Aug 2017 12:41:26 -0400 Subject: [PATCH 028/114] potentially fix memleaks --- src/zm_ffmpeg_camera.cpp | 68 +++++++++++++++++++++------------------- src/zm_videostore.cpp | 18 ++++++----- 2 files changed, 46 insertions(+), 40 deletions(-) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index dc29363cf..3da5ee610 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -68,13 +68,13 @@ FfmpegCamera::FfmpegCamera( int p_id, const std::string &p_path, const std::stri mConvertContext = NULL; #endif /* Has to be located inside the constructor so other components such as zma will receive correct colours and subpixel order */ - if(colours == ZM_COLOUR_RGB32) { + if ( colours == ZM_COLOUR_RGB32 ) { subpixelorder = ZM_SUBPIX_ORDER_RGBA; imagePixFormat = AV_PIX_FMT_RGBA; - } else if(colours == ZM_COLOUR_RGB24) { + } else if ( colours == ZM_COLOUR_RGB24 ) { subpixelorder = ZM_SUBPIX_ORDER_RGB; imagePixFormat = AV_PIX_FMT_RGB24; - } else if(colours == ZM_COLOUR_GRAY8) { + } else if ( colours == ZM_COLOUR_GRAY8 ) { subpixelorder = ZM_SUBPIX_ORDER_NONE; imagePixFormat = AV_PIX_FMT_GRAY8; } else { @@ -93,6 +93,7 @@ FfmpegCamera::~FfmpegCamera() { if ( capture ) { Terminate(); } + avformat_network_deinit(); } void FfmpegCamera::Initialise() { @@ -113,30 +114,29 @@ int FfmpegCamera::PrimeCapture() { mAudioStreamId = -1; Info( "Priming capture from %s", mPath.c_str() ); - if (OpenFfmpeg() != 0){ + if ( OpenFfmpeg() != 0 ) { ReopenFfmpeg(); } return 0; } -int FfmpegCamera::PreCapture() -{ +int FfmpegCamera::PreCapture() { // Nothing to do here return( 0 ); } int FfmpegCamera::Capture( Image &image ) { - if (!mCanCapture){ + if ( ! mCanCapture ) { return -1; } // If the reopen thread has a value, but mCanCapture != 0, then we have just reopened the connection to the ffmpeg device, and we can clean up the thread. - if (mReopenThread != 0) { + if ( mReopenThread != 0 ) { void *retval = 0; int ret; ret = pthread_join(mReopenThread, &retval); - if (ret != 0){ + if ( ret != 0 ) { Error("Could not join reopen thread."); } @@ -216,21 +216,21 @@ int FfmpegCamera::Capture( Image &image ) { #endif #if HAVE_LIBSWSCALE - if(mConvertContext == NULL) { + if ( mConvertContext == NULL ) { mConvertContext = sws_getContext(mVideoCodecContext->width, mVideoCodecContext->height, mVideoCodecContext->pix_fmt, width, height, imagePixFormat, SWS_BICUBIC, NULL, NULL, NULL); - if(mConvertContext == NULL) + if ( mConvertContext == NULL ) Fatal( "Unable to create conversion context for %s", mPath.c_str() ); } - if (sws_scale(mConvertContext, mRawFrame->data, mRawFrame->linesize, 0, mVideoCodecContext->height, mFrame->data, mFrame->linesize) < 0) + if ( sws_scale(mConvertContext, mRawFrame->data, mRawFrame->linesize, 0, mVideoCodecContext->height, mFrame->data, mFrame->linesize) < 0 ) Fatal("Unable to convert raw format %u to target format %u at frame %d", mVideoCodecContext->pix_fmt, imagePixFormat, frameCount); #else // HAVE_LIBSWSCALE - Fatal( "You must compile ffmpeg with the --enable-swscale option to use ffmpeg cameras" ); + Fatal("You must compile ffmpeg with the --enable-swscale option to use ffmpeg cameras"); #endif // HAVE_LIBSWSCALE frameCount++; @@ -260,12 +260,12 @@ int FfmpegCamera::OpenFfmpeg() { // Open the input, not necessarily a file #if !LIBAVFORMAT_VERSION_CHECK(53, 2, 0, 4, 0) Debug ( 1, "Calling av_open_input_file" ); - if ( av_open_input_file( &mFormatContext, mPath.c_str(), NULL, 0, NULL ) !=0 ) + if ( av_open_input_file( &mFormatContext, mPath.c_str(), NULL, 0, NULL ) != 0 ) #else // Handle options AVDictionary *opts = 0; ret = av_dict_parse_string(&opts, Options().c_str(), "=", ",", 0); - if (ret < 0) { + if ( ret < 0 ) { Warning("Could not parse ffmpeg input options list '%s'\n", Options().c_str()); } @@ -288,7 +288,7 @@ int FfmpegCamera::OpenFfmpeg() { mFormatContext->interrupt_callback.callback = FfmpegInterruptCallback; mFormatContext->interrupt_callback.opaque = this; - if ( avformat_open_input( &mFormatContext, mPath.c_str(), NULL, &opts ) !=0 ) + if ( avformat_open_input( &mFormatContext, mPath.c_str(), NULL, &opts ) != 0 ) #endif { mIsOpening = false; @@ -326,7 +326,7 @@ int FfmpegCamera::OpenFfmpeg() { // The one we want Might not be the first mVideoStreamId = -1; mAudioStreamId = -1; - for (unsigned int i=0; i < mFormatContext->nb_streams; i++ ) { + for ( unsigned int i=0; i < mFormatContext->nb_streams; i++ ) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) if ( mFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ) { #else @@ -403,7 +403,7 @@ int FfmpegCamera::OpenFfmpeg() { #else mAudioCodecContext = mFormatContext->streams[mAudioStreamId]->codec; #endif - if ((mAudioCodec = avcodec_find_decoder(mAudioCodecContext->codec_id)) == NULL) { + if ( (mAudioCodec = avcodec_find_decoder(mAudioCodecContext->codec_id)) == NULL ) { Debug(1, "Can't find codec for audio stream from %s", mPath.c_str()); } else { Debug(1, "Audio Found decoder"); @@ -411,10 +411,10 @@ int FfmpegCamera::OpenFfmpeg() { // Open the codec #if !LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 8, 0) Debug ( 1, "Calling avcodec_open" ); - if (avcodec_open(mAudioCodecContext, mAudioCodec) < 0) + if ( avcodec_open(mAudioCodecContext, mAudioCodec) < 0 ) #else Debug ( 1, "Calling avcodec_open2" ); - if (avcodec_open2(mAudioCodecContext, mAudioCodec, 0) < 0) + if ( avcodec_open2(mAudioCodecContext, mAudioCodec, 0) < 0 ) #endif Fatal( "Unable to open codec for video stream from %s", mPath.c_str() ); } @@ -428,7 +428,7 @@ int FfmpegCamera::OpenFfmpeg() { // Allocate space for the converted video frame mFrame = zm_av_frame_alloc(); - if(mRawFrame == NULL || mFrame == NULL) + if ( mRawFrame == NULL || mFrame == NULL ) Fatal( "Unable to allocate frame for %s", mPath.c_str() ); Debug ( 1, "Allocated frames" ); @@ -439,7 +439,7 @@ int FfmpegCamera::OpenFfmpeg() { int pSize = avpicture_get_size( imagePixFormat, width, height ); #endif - if( (unsigned int)pSize != imagesize) { + if ( (unsigned int)pSize != imagesize ) { Fatal("Image size mismatch. Required: %d Available: %d",pSize,imagesize); } @@ -447,11 +447,11 @@ int FfmpegCamera::OpenFfmpeg() { #if HAVE_LIBSWSCALE Debug ( 1, "Calling sws_isSupportedInput" ); - if (!sws_isSupportedInput(mVideoCodecContext->pix_fmt)) { + if ( !sws_isSupportedInput(mVideoCodecContext->pix_fmt) ) { Fatal("swscale does not support the codec format: %c%c%c%c", (mVideoCodecContext->pix_fmt)&0xff, ((mVideoCodecContext->pix_fmt >> 8)&0xff), ((mVideoCodecContext->pix_fmt >> 16)&0xff), ((mVideoCodecContext->pix_fmt >> 24)&0xff)); } - if(!sws_isSupportedOutput(imagePixFormat)) { + if ( !sws_isSupportedOutput(imagePixFormat) ) { Fatal("swscale does not support the target format: %c%c%c%c",(imagePixFormat)&0xff,((imagePixFormat>>8)&0xff),((imagePixFormat>>16)&0xff),((imagePixFormat>>24)&0xff)); } @@ -489,7 +489,7 @@ int FfmpegCamera::ReopenFfmpeg() { return 0; } -int FfmpegCamera::CloseFfmpeg(){ +int FfmpegCamera::CloseFfmpeg() { Debug(2, "CloseFfmpeg called."); @@ -505,12 +505,14 @@ int FfmpegCamera::CloseFfmpeg(){ } #endif - if (mVideoCodecContext) { + if ( mVideoCodecContext ) { avcodec_close(mVideoCodecContext); + av_free(mVideoCodecContext); mVideoCodecContext = NULL; // Freed by av_close_input_file } - if (mAudioCodecContext) { + if ( mAudioCodecContext ) { avcodec_close(mAudioCodecContext); + av_free(mAudioCodecContext); mAudioCodecContext = NULL; // Freed by av_close_input_file } @@ -528,9 +530,9 @@ int FfmpegCamera::CloseFfmpeg(){ int FfmpegCamera::FfmpegInterruptCallback(void *ctx) { FfmpegCamera* camera = reinterpret_cast(ctx); - if (camera->mIsOpening){ + if ( camera->mIsOpening ) { int now = time(NULL); - if ((now - camera->mOpenStart) > config.ffmpeg_open_timeout) { + if ( (now - camera->mOpenStart) > config.ffmpeg_open_timeout ) { Error ( "Open video took more than %d seconds.", config.ffmpeg_open_timeout ); return 1; } @@ -551,12 +553,12 @@ void *FfmpegCamera::ReopenFfmpegThreadCallback(void *ctx){ // Sleep if necessary to not reconnect too fast. int wait = config.ffmpeg_open_timeout - (time(NULL) - camera->mOpenStart); wait = wait < 0 ? 0 : wait; - if (wait > 0){ + if ( wait > 0 ) { Debug( 1, "Sleeping %d seconds before reopening stream.", wait ); sleep(wait); } - if (camera->OpenFfmpeg() == 0){ + if ( camera->OpenFfmpeg() == 0 ) { return NULL; } } @@ -646,8 +648,8 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event if ( last_event_id and ! videoStore ) { //Instantiate the video storage module - if (record_audio) { - if (mAudioStreamId == -1) { + if ( record_audio ) { + if ( mAudioStreamId == -1 ) { Debug(3, "Record Audio on but no audio stream found"); videoStore = new VideoStore((const char *) event_file, "mp4", mFormatContext->streams[mVideoStreamId], diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 4df2d902d..abcb724ae 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -326,34 +326,34 @@ VideoStore::~VideoStore(){ pkt.size = 0; int64_t size; - while(1) { + while ( 1 ) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) ret = avcodec_receive_packet( audio_output_context, &pkt ); #else ret = avcodec_encode_audio2( audio_output_context, &pkt, NULL, &got_packet ); #endif - if (ret < 0) { + if ( ret < 0 ) { Error("ERror encoding audio while flushing"); break; } Debug(1, "Have audio encoder, need to flush it's output" ); size += pkt.size; - if (!got_packet) { + if ( ! got_packet ) { break; } Debug(2, "writing flushed packet pts(%d) dts(%d) duration(%d)", pkt.pts, pkt.dts, pkt.duration ); - if (pkt.pts != AV_NOPTS_VALUE) + if ( pkt.pts != AV_NOPTS_VALUE ) pkt.pts = av_rescale_q(pkt.pts, audio_output_context->time_base, audio_output_stream->time_base); - if (pkt.dts != AV_NOPTS_VALUE) + if ( pkt.dts != AV_NOPTS_VALUE ) pkt.dts = av_rescale_q(pkt.dts, audio_output_context->time_base, audio_output_stream->time_base); - if (pkt.duration > 0) + if ( pkt.duration > 0 ) pkt.duration = av_rescale_q(pkt.duration, audio_output_context->time_base, audio_output_stream->time_base); Debug(2, "writing flushed packet pts(%d) dts(%d) duration(%d)", pkt.pts, pkt.dts, pkt.duration ); pkt.stream_index = audio_output_stream->index; av_interleaved_write_frame( oc, &pkt ); zm_av_packet_unref( &pkt ); } // while 1 - } + } // end if audio_output_codec // Flush Queues av_interleaved_write_frame( oc, NULL ); @@ -370,9 +370,13 @@ Debug(2, "writing flushed packet pts(%d) dts(%d) duration(%d)", pkt.pts, pkt.dts // What if we were only doing audio recording? if ( video_output_stream ) { avcodec_close(video_output_context); + av_free(video_output_context); + video_output_context = NULL; } if (audio_output_stream) { avcodec_close(audio_output_context); + av_free(audio_output_context); + audio_output_context = NULL; #ifdef HAVE_LIBAVRESAMPLE if ( resample_context ) { avresample_close( resample_context ); From 7cb4090d7dfd91497577ebc57471084f20b5d6aa Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 3 Aug 2017 12:41:43 -0400 Subject: [PATCH 029/114] can't use jquery like that --- web/skins/classic/views/js/watch.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/web/skins/classic/views/js/watch.js b/web/skins/classic/views/js/watch.js index 2909f0476..57ad9d86c 100644 --- a/web/skins/classic/views/js/watch.js +++ b/web/skins/classic/views/js/watch.js @@ -31,7 +31,7 @@ function changeScale() { Cookie.write( 'zmWatchScale'+monitorId, scale, { duration: 10*365 } ); /*Stream could be an applet so can't use moo tools*/ - var streamImg = $('#liveStream'+monitorId); + var streamImg = $('liveStream'+monitorId); if ( streamImg ) { streamImg.style.width = newWidth + "px"; streamImg.style.height = newHeight + "px"; @@ -197,7 +197,7 @@ function getStreamCmdResponse( respObj, respText ) { var streamImg = $('liveStream'+monitorId); if ( streamImg ) { streamImg.src = streamImg.src.replace(/rand=\d+/i,'rand='+Math.floor((Math.random() * 1000000) )); - console.log("Changing lviestream src to " + streamImg.src); + console.log("Changing livestream src to " + streamImg.src); } else { console.log("Unable to find streamImg liveStream"); } @@ -357,7 +357,14 @@ function statusCmdQuery() { var alarmCmdParms = "view=request&request=alarm&id="+monitorId; if ( auth_hash ) alarmCmdParms += '&auth='+auth_hash; -var alarmCmdReq = new Request.JSON( { url: monitorUrl+thisUrl, method: 'post', timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getAlarmCmdResponse, onTimeout: streamCmdQuery } ); +var alarmCmdReq = new Request.JSON( { + url: monitorUrl+thisUrl, + method: 'post', + timeout: AJAX_TIMEOUT, + link: 'cancel', + onSuccess: getAlarmCmdResponse, + onTimeout: streamCmdQuery +} ); var alarmCmdFirst = true; function getAlarmCmdResponse( respObj, respText ) { @@ -378,11 +385,13 @@ function cmdForceAlarm() { function cmdCancelForcedAlarm() { alarmCmdReq.send( alarmCmdParms+"&command=cancelForcedAlarm" ); + return false; } function getActResponse( respObj, respText ) { if ( respObj.result == 'Ok' ) { if ( respObj.refreshParent ) { + console.log('refreshing'); window.opener.location.reload(); } } From b203e10c65c1058ccc0ddfacd72b35d8c84c48e2 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 4 Aug 2017 14:14:25 -0400 Subject: [PATCH 030/114] remove some newlines that shouldn't be there. Fix some logic when flushing audio encoder --- src/zm_videostore.cpp | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index abcb724ae..45ed8186b 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -53,7 +53,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, filename = filename_in; format = format_in; - Info("Opening video storage stream %s format: %s\n", filename, format); + Info("Opening video storage stream %s format: %s", filename, format); ret = avformat_alloc_output_context2(&oc, NULL, NULL, filename); if ( ret < 0 ) { @@ -320,7 +320,6 @@ VideoStore::~VideoStore(){ if ( audio_output_codec ) { // Do we need to flush the outputs? I have no idea. AVPacket pkt; - int got_packet = 0; av_init_packet(&pkt); pkt.data = NULL; pkt.size = 0; @@ -329,18 +328,23 @@ VideoStore::~VideoStore(){ while ( 1 ) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) ret = avcodec_receive_packet( audio_output_context, &pkt ); -#else - ret = avcodec_encode_audio2( audio_output_context, &pkt, NULL, &got_packet ); -#endif if ( ret < 0 ) { - Error("ERror encoding audio while flushing"); + Error("ERror encoding audio while flushing (%d) (%s)", ret, av_err2str( ret ) ); + break; + } +#else + int got_packet = 0; + ret = avcodec_encode_audio2( audio_output_context, &pkt, NULL, &got_packet ); + if ( ret < 0 ) { + Error("ERror encoding audio while flushing (%d) (%s)", ret, av_err2str( ret ) ); break; } Debug(1, "Have audio encoder, need to flush it's output" ); - size += pkt.size; if ( ! got_packet ) { break; } +#endif + size += pkt.size; Debug(2, "writing flushed packet pts(%d) dts(%d) duration(%d)", pkt.pts, pkt.dts, pkt.duration ); if ( pkt.pts != AV_NOPTS_VALUE ) pkt.pts = av_rescale_q(pkt.pts, audio_output_context->time_base, audio_output_stream->time_base); @@ -531,10 +535,11 @@ bool VideoStore::setup_resampler() { // Some formats (i.e. WAV) do not produce the proper channel layout if ( audio_input_context->channel_layout == 0 ) { - Error( "Bad channel layout. Need to set it to mono.\n"); - av_opt_set_int( resample_context, "in_channel_layout", av_get_channel_layout( "mono" ), 0 ); + uint64_t layout = av_get_channel_layout( "mono" ); + av_opt_set_int( resample_context, "in_channel_layout", av_get_channel_layout( "mono" ), 0 ); + Debug( 1, "Bad channel layout. Need to set it to mono (%d).", layout ); } else { - av_opt_set_int( resample_context, "in_channel_layout", audio_input_context->channel_layout, 0 ); + av_opt_set_int( resample_context, "in_channel_layout", audio_input_context->channel_layout, 0 ); } av_opt_set_int( resample_context, "in_sample_fmt", audio_input_context->sample_fmt, 0); From b9addeecfdb018ed3bef24b01d6a6a27250b39a6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 8 Aug 2017 15:02:40 -0400 Subject: [PATCH 031/114] update deleting the events when deleting a monitor --- web/includes/actions.php | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/web/includes/actions.php b/web/includes/actions.php index 0516f0a38..836328829 100644 --- a/web/includes/actions.php +++ b/web/includes/actions.php @@ -541,6 +541,18 @@ Warning("Addterm"); zmcControl( $monitor, 'stop' ); } + // If fast deletes are on, then zmaudit will clean everything else up later + // If fast deletes are off and there are lots of events then this step may + // well time out before completing, in which case zmaudit will still tidy up + if ( !ZM_OPT_FAST_DELETE ) { + $markEids = dbFetchAll( 'SELECT Id FROM Events WHERE MonitorId=?', NULL, array($markMid) ); + foreach( $markEids as $markEid ) + deleteEvent( $markEid ); + + deletePath( ZM_DIR_EVENTS.'/'.basename($monitor['Name']) ); + deletePath( ZM_DIR_EVENTS.'/'.$monitor['Id'] ); // I'm trusting the Id. + } // end if ZM_OPT_FAST_DELETE + // This is the important stuff dbQuery( 'DELETE FROM Monitors WHERE Id = ?', array($markMid) ); dbQuery( 'DELETE FROM Zones WHERE MonitorId = ?', array($markMid) ); @@ -549,18 +561,6 @@ Warning("Addterm"); fixSequences(); - // If fast deletes are on, then zmaudit will clean everything else up later - // If fast deletes are off and there are lots of events then this step may - // well time out before completing, in which case zmaudit will still tidy up - if ( !ZM_OPT_FAST_DELETE ) { - // Slight hack, we maybe should load *, but we happen to know that the deleteEvent function uses Id and StartTime. - $markEids = dbFetchAll( 'SELECT Id,StartTime FROM Events WHERE MonitorId=?', NULL, array($markMid) ); - foreach( $markEids as $markEid ) - deleteEvent( $markEid, $markMid ); - - deletePath( ZM_DIR_EVENTS.'/'.basename($monitor['Name']) ); - deletePath( ZM_DIR_EVENTS.'/'.$monitor['Id'] ); // I'm trusting the Id. - } // end if ZM_OPT_FAST_DELETE } // end if found the monitor in the db } // end if canedit this monitor } // end foreach monitor in MarkMid From 928c4651a6060e1f63452fa83e1bc164dea94332 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 9 Aug 2017 09:54:27 -0400 Subject: [PATCH 032/114] fix braces, spacing --- web/skins/classic/views/video.php | 188 +++++++++++++----------------- 1 file changed, 81 insertions(+), 107 deletions(-) diff --git a/web/skins/classic/views/video.php b/web/skins/classic/views/video.php index cfbb6f929..75cc8c8ed 100644 --- a/web/skins/classic/views/video.php +++ b/web/skins/classic/views/video.php @@ -18,91 +18,82 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // -if ( !canView( 'Events' ) ) -{ - $view = "error"; - return; +if ( !canView( 'Events' ) ) { + $view = "error"; + return; } +require_once('includes/Event.php'); + $eid = validInt($_REQUEST['eid']); $sql = 'SELECT E.*,M.Name AS MonitorName,M.DefaultRate,M.DefaultScale FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id WHERE E.Id = ?'; $sql_values = array( $eid ); if ( $user['MonitorIds'] ) { - $monitor_ids = explode( ',', $user['MonitorIds'] ); - $sql .= ' AND MonitorId IN (' .implode( ',', array_fill(0,count($monitor_ids),'?') ) . ')'; - $sql_values = array_merge( $sql_values, $monitor_ids ); + $monitor_ids = explode( ',', $user['MonitorIds'] ); + $sql .= ' AND MonitorId IN (' .implode( ',', array_fill(0,count($monitor_ids),'?') ) . ')'; + $sql_values = array_merge( $sql_values, $monitor_ids ); } $event = dbFetchOne( $sql, NULL, $sql_values ); if ( isset( $_REQUEST['rate'] ) ) - $rate = validInt($_REQUEST['rate']); + $rate = validInt($_REQUEST['rate']); else - $rate = reScale( RATE_BASE, $event['DefaultRate'], ZM_WEB_DEFAULT_RATE ); + $rate = reScale( RATE_BASE, $event['DefaultRate'], ZM_WEB_DEFAULT_RATE ); if ( isset( $_REQUEST['scale'] ) ) - $scale = validInt($_REQUEST['scale']); + $scale = validInt($_REQUEST['scale']); else - $scale = reScale( SCALE_BASE, $event['DefaultScale'], ZM_WEB_DEFAULT_SCALE ); + $scale = reScale( SCALE_BASE, $event['DefaultScale'], ZM_WEB_DEFAULT_SCALE ); -$eventPath = ZM_DIR_EVENTS.'/'.getEventPath( $event ); +$Event = new Event( $event['Id'] ); +$eventPath = $Event->Path(); $videoFormats = array(); $ffmpegFormats = preg_split( '/\s+/', ZM_FFMPEG_FORMATS ); -foreach ( $ffmpegFormats as $ffmpegFormat ) -{ - if ( preg_match( '/^([^*]+)(\*\*?)$/', $ffmpegFormat, $matches ) ) - { - $videoFormats[$matches[1]] = $matches[1]; - if ( !isset($videoFormat) && $matches[2] == "*" ) - { - $videoFormat = $matches[1]; - } - } - else - { - $videoFormats[$ffmpegFormat] = $ffmpegFormat; +foreach ( $ffmpegFormats as $ffmpegFormat ) { + if ( preg_match( '/^([^*]+)(\*\*?)$/', $ffmpegFormat, $matches ) ) { + $videoFormats[$matches[1]] = $matches[1]; + if ( !isset($videoFormat) && $matches[2] == '*' ) { + $videoFormat = $matches[1]; } + } else { + $videoFormats[$ffmpegFormat] = $ffmpegFormat; + } } $videoFiles = array(); -if ( $dir = opendir( $eventPath ) ) -{ - while ( ($file = readdir( $dir )) !== false ) - { - $file = $eventPath.'/'.$file; - if ( is_file( $file ) ) - { - if ( preg_match( '/\.(?:'.join( '|', $videoFormats ).')$/', $file ) ) - { - $videoFiles[] = $file; - } - } +if ( $dir = opendir( $eventPath ) ) { + while ( ($file = readdir( $dir )) !== false ) { + $file = $eventPath.'/'.$file; + if ( is_file( $file ) ) { + if ( preg_match( '/\.(?:'.join( '|', $videoFormats ).')$/', $file ) ) { + $videoFiles[] = $file; + } } - closedir( $dir ); + } + closedir( $dir ); } -if ( isset($_REQUEST['deleteIndex']) ) -{ - $deleteIndex = validInt($_REQUEST['deleteIndex']); - unlink( $videoFiles[$deleteIndex] ); - unset( $videoFiles[$deleteIndex] ); +if ( isset($_REQUEST['deleteIndex']) ) { + $deleteIndex = validInt($_REQUEST['deleteIndex']); + unlink( $videoFiles[$deleteIndex] ); + unset( $videoFiles[$deleteIndex] ); } -if ( isset($_REQUEST['downloadIndex']) ) -{ - $downloadIndex = validInt($_REQUEST['downloadIndex']); - header( "Pragma: public" ); - header( "Expires: 0" ); - header( "Cache-Control: must-revalidate, post-check=0, pre-check=0" ); - header( "Cache-Control: private", false ); // required by certain browsers - header( "Content-Description: File Transfer" ); - header( 'Content-disposition: attachment; filename="'.basename($videoFiles[$downloadIndex]).'"' ); // basename is required because the video index contains the path and firefox doesn't strip the path but simply replaces the slashes with an underscore. - header( "Content-Transfer-Encoding: binary" ); - header( "Content-Type: application/force-download" ); - header( "Content-Length: ".filesize($videoFiles[$downloadIndex]) ); - readfile( $videoFiles[$downloadIndex] ); - exit; +if ( isset($_REQUEST['downloadIndex']) ) { + $downloadIndex = validInt($_REQUEST['downloadIndex']); + header( "Pragma: public" ); + header( "Expires: 0" ); + header( "Cache-Control: must-revalidate, post-check=0, pre-check=0" ); + header( "Cache-Control: private", false ); // required by certain browsers + header( "Content-Description: File Transfer" ); + header( 'Content-disposition: attachment; filename="'.basename($videoFiles[$downloadIndex]).'"' ); // basename is required because the video index contains the path and firefox doesn't strip the path but simply replaces the slashes with an underscore. + header( "Content-Transfer-Encoding: binary" ); + header( "Content-Type: application/force-download" ); + header( "Content-Length: ".filesize($videoFiles[$downloadIndex]) ); + readfile( $videoFiles[$downloadIndex] ); + exit; } $focusWindow = true; @@ -119,19 +110,16 @@ xhtmlHeaders(__FILE__, translate('Video') );

@@ -158,29 +146,23 @@ else disabled="disabled"/>

+
'None'); $result = dbQuery( 'SELECT * FROM Servers ORDER BY Name'); $results = $result->fetchALL(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'Server' ); foreach ( $results as $row => $server_obj ) { - $servers[$server_obj->Id] = $server_obj->Name(); + $servers[$server_obj->Id()] = $server_obj->Name(); } + echo htmlSelect( 'newMonitor[ServerId]', $servers, $monitor->ServerId() ); ?> - -
Type() ); ?>
checked="checked"/>
-
Enabled()) ) { ?> checked="checked"/>
+ -
 ()
 ()
+
Method(), "submitTab( '$tab' );" ); ?>
- /> - - /> - - /> - -
+ V4LMultiBuffer() == 1 ? 'checked="checked"' : '' ) ?>/> + + V4LMultiBuffer() == 0 ? 'checked="checked"' : '' ) ?>/> + + V4LMultiBuffer()) ? 'checked="checked"' : '' ) ?>/> + +
Protocol(), "updateMethods( this );if(this.value=='rtsp'){\$('RTSPDescribe').setStyle('display','table-row');}else{\$('RTSPDescribe').hide();}" ); ?>
Method() ); ?>
Method() ); ?>
 ()
 ()
 ()Method() ); ?>
 (Type()), 'zmOptionHelp', 'optionhelp', '?' ) ?>)
()
()
()
()
 () RTSPDescribe()) ) { ?> checked="checked"/>
checked="checked"/>
RecordAudio()) ) { ?> checked="checked"/>
checked="checked"/>
Controllable()) ) { ?> checked="checked"/>
 
checked="checked"/>
TrackMotion()) ) { ?> checked="checked"/>
DefaultRate() ); ?>
DefaultScale() ); ?>
    
+ +      +
    
 () checked="checked"/>
+ +      +
 () Exif()) ) { ?> checked="checked"/>
@@ -194,32 +176,24 @@ else 0 ) - { - preg_match( '/^(.+)-((?:r[_\d]+)|(?:F[_\d]+))-((?:s[_\d]+)|(?:S[0-9a-z]+))\.([^.]+)$/', $file, $matches ); - if ( preg_match( '/^r(.+)$/', $matches[2], $temp_matches ) ) - { - $rate = (int)(100 * preg_replace( '/_/', '.', $temp_matches[1] ) ); - $rateText = isset($rates[$rate])?$rates[$rate]:($rate."x"); - } - elseif ( preg_match( '/^F(.+)$/', $matches[2], $temp_matches ) ) - { - $rateText = $temp_matches[1]."fps"; - } - if ( preg_match( '/^s(.+)$/', $matches[3], $temp_matches ) ) - { - $scale = (int)(100 * preg_replace( '/_/', '.', $temp_matches[1] ) ); - $scaleText = isset($scales[$scale])?$scales[$scale]:($scale."x"); - } - elseif ( preg_match( '/^S(.+)$/', $matches[3], $temp_matches ) ) - { - $scaleText = $temp_matches[1]; - } - $width = $scale?reScale( $event['Width'], $scale ):$event['Width']; - $height = $scale?reScale( $event['Height'], $scale ):$event['Height']; + $index = 0; + foreach ( $videoFiles as $file ) { + if ( filesize( $file ) > 0 ) { + preg_match( '/^(.+)-((?:r[_\d]+)|(?:F[_\d]+))-((?:s[_\d]+)|(?:S[0-9a-z]+))\.([^.]+)$/', $file, $matches ); + if ( preg_match( '/^r(.+)$/', $matches[2], $temp_matches ) ) { + $rate = (int)(100 * preg_replace( '/_/', '.', $temp_matches[1] ) ); + $rateText = isset($rates[$rate])?$rates[$rate]:($rate."x"); + } elseif ( preg_match( '/^F(.+)$/', $matches[2], $temp_matches ) ) { + $rateText = $temp_matches[1]."fps"; + } + if ( preg_match( '/^s(.+)$/', $matches[3], $temp_matches ) ) { + $scale = (int)(100 * preg_replace( '/_/', '.', $temp_matches[1] ) ); + $scaleText = isset($scales[$scale])?$scales[$scale]:($scale."x"); + } elseif ( preg_match( '/^S(.+)$/', $matches[3], $temp_matches ) ) { + $scaleText = $temp_matches[1]; + } + $width = $scale?reScale( $event['Width'], $scale ):$event['Width']; + $height = $scale?reScale( $event['Height'], $scale ):$event['Height']; ?> @@ -229,14 +203,14 @@ else
 /  / 
From 27fe468868ababfb7d4d1350246865ffb7347f44 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 9 Aug 2017 11:15:00 -0400 Subject: [PATCH 033/114] Don't do csrf for view=video because the output buffering will make it run out of ram --- web/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/index.php b/web/index.php index 6673b3079..69bea52ee 100644 --- a/web/index.php +++ b/web/index.php @@ -194,7 +194,7 @@ isset($view) || $view = NULL; isset($request) || $request = NULL; isset($action) || $action = NULL; -if ( ZM_ENABLE_CSRF_MAGIC && $action != 'login' && $view != 'view_video' && $request != 'control' ) { +if ( ZM_ENABLE_CSRF_MAGIC && $action != 'login' && $view != 'view_video' && $view != 'video' && $request != 'control' ) { require_once( 'includes/csrf/csrf-magic.php' ); Logger::Debug("Calling csrf_check with the following values: \$request = \"$request\", \$view = \"$view\", \$action = \"$action\""); csrf_check(); From cc28af8ed20e9d7de3f540d1b48fd45cebff2bd4 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 9 Aug 2017 12:50:46 -0400 Subject: [PATCH 034/114] rework things to always start the recording on a video keyframe. Also fix pts/dts of remaining audio frames --- src/zm_ffmpeg_camera.cpp | 12 ++- src/zm_ffmpeg_camera.h | 1 + src/zm_videostore.cpp | 162 ++++++++++++++++++++++----------------- src/zm_videostore.h | 8 +- 4 files changed, 109 insertions(+), 74 deletions(-) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 3da5ee610..e2152fce9 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -63,6 +63,7 @@ FfmpegCamera::FfmpegCamera( int p_id, const std::string &p_path, const std::stri mReopenThread = 0; videoStore = NULL; video_last_pts = 0; + have_video_keyframe = false; #if HAVE_LIBSWSCALE mConvertContext = NULL; @@ -640,6 +641,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event delete videoStore; videoStore = NULL; + have_video_keyframe = false; monitor->SetVideoWriterEventId( 0 ); } // end if videoStore @@ -692,6 +694,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event Debug(2, "Writing queued packet stream: %d KEY %d, remaining (%d)", avp->stream_index, avp->flags & AV_PKT_FLAG_KEY, packetqueue.size() ); if ( avp->stream_index == mVideoStreamId ) { ret = videoStore->writeVideoFramePacket( avp ); + have_video_keyframe = true; } else if ( avp->stream_index == mAudioStreamId ) { ret = videoStore->writeAudioFramePacket( avp ); } else { @@ -712,6 +715,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event Info("Deleting videoStore instance"); delete videoStore; videoStore = NULL; + have_video_keyframe = false; monitor->SetVideoWriterEventId( 0 ); } @@ -747,13 +751,15 @@ else if ( packet.pts && video_last_pts > packet.pts ) { } // end if recording or not if ( packet.stream_index == mVideoStreamId ) { - if ( videoStore ) { + if ( videoStore && ( have_video_keyframe || key_frame ) ) { + //Write the packet to our video store int ret = videoStore->writeVideoFramePacket( &packet ); if ( ret < 0 ) { //Less than zero and we skipped a frame zm_av_packet_unref( &packet ); return 0; } + have_video_keyframe = true; } Debug(4, "about to decode video" ); @@ -817,6 +823,7 @@ else if ( packet.pts && video_last_pts > packet.pts ) { } else if ( packet.stream_index == mAudioStreamId ) { //FIXME best way to copy all other streams if ( videoStore ) { if ( record_audio ) { + if ( have_video_keyframe ) { Debug(3, "Recording audio packet streamindex(%d) packetstreamindex(%d)", mAudioStreamId, packet.stream_index ); //Write the packet to our video store //FIXME no relevance of last key frame @@ -826,6 +833,9 @@ else if ( packet.pts && video_last_pts > packet.pts ) { zm_av_packet_unref( &packet ); return 0; } + } else { + Debug(3, "Not recording audio because we don't have a bvideo keyframe yet"); + } } else { Debug(4, "Not doing recording of audio packet" ); } diff --git a/src/zm_ffmpeg_camera.h b/src/zm_ffmpeg_camera.h index d472909db..06d22f9a5 100644 --- a/src/zm_ffmpeg_camera.h +++ b/src/zm_ffmpeg_camera.h @@ -78,6 +78,7 @@ class FfmpegCamera : public Camera { char oldDirectory[4096]; unsigned int old_event_id; zm_packetqueue packetqueue; + bool have_video_keyframe; #if HAVE_LIBSWSCALE struct SwsContext *mConvertContext; diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 45ed8186b..f3656143c 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -44,7 +44,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) video_input_context = avcodec_alloc_context3( NULL ); avcodec_parameters_to_context( video_input_context, video_input_stream->codecpar ); - zm_dump_codecpar( video_input_stream->codecpar ); + //zm_dump_codecpar( video_input_stream->codecpar ); #else video_input_context = video_input_stream->codec; #endif @@ -285,7 +285,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, zm_dump_stream_format( oc, 1, 0, 1 ); AVDictionary * opts = NULL; - av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0); + //av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0); //av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0); //av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov+default_base_moof", 0); if ((ret = avformat_write_header( oc, &opts )) < 0) { @@ -308,55 +308,58 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, video_last_dts = 0; audio_last_pts = 0; audio_last_dts = 0; - video_previous_pts = 0; - video_previous_dts = 0; - audio_previous_pts = 0; - audio_previous_dts = 0; + video_next_pts = 0; + video_next_dts = 0; + audio_next_pts = 0; + audio_next_dts = 0; } // VideoStore::VideoStore VideoStore::~VideoStore(){ if ( audio_output_codec ) { - // Do we need to flush the outputs? I have no idea. + // The codec queues data. We need to send a flush command and output whatever we get. Failures are not fatal. AVPacket pkt; av_init_packet(&pkt); - pkt.data = NULL; - pkt.size = 0; - int64_t size; while ( 1 ) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + ret = avcodec_send_frame( audio_output_context, NULL ); + if ( ret < 0 ) { + Error("Error sending flush to encoder (%d) (%s)", ret, av_err2str( ret )); + break; + } ret = avcodec_receive_packet( audio_output_context, &pkt ); if ( ret < 0 ) { - Error("ERror encoding audio while flushing (%d) (%s)", ret, av_err2str( ret ) ); + Error("ERror encoding audio while flushing (%d) (%s)", ret, av_err2str( ret )); break; } #else int got_packet = 0; ret = avcodec_encode_audio2( audio_output_context, &pkt, NULL, &got_packet ); if ( ret < 0 ) { - Error("ERror encoding audio while flushing (%d) (%s)", ret, av_err2str( ret ) ); + Error("ERror encoding audio while flushing (%d) (%s)", ret, av_err2str( ret )); break; } -Debug(1, "Have audio encoder, need to flush it's output" ); + Debug(1, "Have audio encoder, need to flush it's output"); if ( ! got_packet ) { break; } #endif - size += pkt.size; -Debug(2, "writing flushed packet pts(%d) dts(%d) duration(%d)", pkt.pts, pkt.dts, pkt.duration ); - if ( pkt.pts != AV_NOPTS_VALUE ) - pkt.pts = av_rescale_q(pkt.pts, audio_output_context->time_base, audio_output_stream->time_base); - if ( pkt.dts != AV_NOPTS_VALUE ) - pkt.dts = av_rescale_q(pkt.dts, audio_output_context->time_base, audio_output_stream->time_base); + Debug(2, "writing flushed packet pts(%d) dts(%d) duration(%d)", pkt.pts, pkt.dts, pkt.duration); + pkt.pts = audio_next_pts; + pkt.dts = audio_next_dts; + if ( pkt.duration > 0 ) pkt.duration = av_rescale_q(pkt.duration, audio_output_context->time_base, audio_output_stream->time_base); -Debug(2, "writing flushed packet pts(%d) dts(%d) duration(%d)", pkt.pts, pkt.dts, pkt.duration ); + audio_next_pts += pkt.duration; + audio_next_dts += pkt.duration; + + Debug(2, "writing flushed packet pts(%d) dts(%d) duration(%d)", pkt.pts, pkt.dts, pkt.duration); pkt.stream_index = audio_output_stream->index; av_interleaved_write_frame( oc, &pkt ); zm_av_packet_unref( &pkt ); - } // while 1 + } // while have buffered frames } // end if audio_output_codec // Flush Queues @@ -513,6 +516,15 @@ bool VideoStore::setup_resampler() { return false; } + Debug(1, "Audio output bit_rate (%d) sample_rate(%d) channels(%d) fmt(%d) layout(%d) frame_size(%d)", + audio_output_context->bit_rate, + audio_output_context->sample_rate, + audio_output_context->channels, + audio_output_context->sample_fmt, + audio_output_context->channel_layout, + audio_output_context->frame_size + ); + /** Create a new frame to store the audio samples. */ if ( !(input_frame = zm_av_frame_alloc()) ) { Error("Could not allocate input frame"); @@ -635,8 +647,22 @@ void VideoStore::dumpPacket( AVPacket *pkt ){ int VideoStore::writeVideoFramePacket( AVPacket *ipkt ) { av_init_packet(&opkt); - int duration; + opkt.pts = video_next_pts; + opkt.dts = video_next_dts; + int duration; + if ( video_last_pts && ( ipkt->duration == AV_NOPTS_VALUE || ! ipkt->duration ) ) { + duration = av_rescale_q( ipkt->pts - video_last_pts, video_input_stream->time_base, video_output_stream->time_base); + // Video packets don't really have a duration. Audio does. + //opkt.duration = av_rescale_q(duration, video_input_stream->time_base, video_output_stream->time_base); + opkt.duration = 0; + } else { + duration = opkt.duration = av_rescale_q(ipkt->duration, video_input_stream->time_base, video_output_stream->time_base); + } + video_last_pts = ipkt->pts; + video_last_dts = ipkt->dts; + +#if 0 //Scale the PTS of the outgoing packet to be the correct time base if ( ipkt->pts != AV_NOPTS_VALUE ) { @@ -646,63 +672,58 @@ int VideoStore::writeVideoFramePacket( AVPacket *ipkt ) { Debug(2, "Starting video video_last_pts will become (%d)", ipkt->pts ); } else { if ( ipkt->pts < video_last_pts ) { - Debug(1, "Resetting video_last_pts from (%d) to (%d)", video_last_pts, ipkt->pts ); + Debug(1, "Resetting video_last_pts from (%d) to (%d)", video_last_pts, ipkt->pts); // wrap around, need to figure out the distance FIXME having this wrong should cause a jump, but then play ok? - opkt.pts = video_previous_pts + av_rescale_q( ipkt->pts, video_input_stream->time_base, video_output_stream->time_base); + opkt.pts = video_next_pts + av_rescale_q( ipkt->pts, video_input_stream->time_base, video_output_stream->time_base); } else { - opkt.pts = video_previous_pts + av_rescale_q( ipkt->pts - video_last_pts, video_input_stream->time_base, video_output_stream->time_base); + opkt.pts = video_next_pts + av_rescale_q( ipkt->pts - video_last_pts, video_input_stream->time_base, video_output_stream->time_base); } } - Debug(3, "opkt.pts = %d from ipkt->pts(%d) - last_pts(%d)", opkt.pts, ipkt->pts, video_last_pts ); - duration = ipkt->pts - video_last_pts; + Debug(3, "opkt.pts = %d from ipkt->pts(%d) - last_pts(%d)", opkt.pts, ipkt->pts, video_last_pts); video_last_pts = ipkt->pts; } else { Debug(3, "opkt.pts = undef"); opkt.pts = AV_NOPTS_VALUE; } - - //Scale the DTS of the outgoing packet to be the correct time base - // Just because the input stream wraps, doesn't mean the output needs to. Really, if we are limiting ourselves to 10min segments I can't imagine every wrapping in the output. So need to handle input wrap, without causing output wrap. if ( ! video_last_dts ) { // This is the first packet. opkt.dts = 0; - Debug(1, "Starting video video_last_dts will become (%d)", ipkt->dts ); + Debug(1, "Starting video video_last_dts will become (%lu)", ipkt->dts ); video_last_dts = ipkt->dts; } else { + //Scale the DTS of the outgoing packet to be the correct time base + if ( ipkt->dts == AV_NOPTS_VALUE ) { // why are we using cur_dts instead of packet.dts? I think cur_dts is in AV_TIME_BASE_Q, but ipkt.dts is in video_input_stream->time_base if ( video_input_stream->cur_dts < video_last_dts ) { Debug(1, "Resetting video_last_dts from (%d) to (%d) p.dts was (%d)", video_last_dts, video_input_stream->cur_dts, ipkt->dts ); - opkt.dts = video_previous_dts + av_rescale_q(video_input_stream->cur_dts, AV_TIME_BASE_Q, video_output_stream->time_base); + opkt.dts = video_next_dts + av_rescale_q(video_input_stream->cur_dts, AV_TIME_BASE_Q, video_output_stream->time_base); } else { - opkt.dts = video_previous_dts + av_rescale_q(video_input_stream->cur_dts - video_last_dts, AV_TIME_BASE_Q, video_output_stream->time_base); + opkt.dts = video_next_dts + av_rescale_q(video_input_stream->cur_dts - video_last_dts, AV_TIME_BASE_Q, video_output_stream->time_base); } Debug(3, "opkt.dts = %d from video_input_stream->cur_dts(%d) - previus_dts(%d)", opkt.dts, video_input_stream->cur_dts, video_last_dts ); video_last_dts = video_input_stream->cur_dts; } else { if ( ipkt->dts < video_last_dts ) { Debug(1, "Resetting video_last_dts from (%d) to (%d)", video_last_dts, ipkt->dts ); - opkt.dts = video_previous_dts + av_rescale_q( ipkt->dts, video_input_stream->time_base, video_output_stream->time_base); + opkt.dts = video_next_dts + av_rescale_q( ipkt->dts, video_input_stream->time_base, video_output_stream->time_base); } else { - opkt.dts = video_previous_dts + av_rescale_q( ipkt->dts - video_last_dts, video_input_stream->time_base, video_output_stream->time_base); + opkt.dts = video_next_dts + av_rescale_q( ipkt->dts - video_last_dts, video_input_stream->time_base, video_output_stream->time_base); } Debug(3, "opkt.dts = %d from ipkt.dts(%d) - previus_dts(%d)", opkt.dts, ipkt->dts, video_last_dts ); video_last_dts = ipkt->dts; } } +#endif if ( opkt.dts > opkt.pts ) { Debug( 1, "opkt.dts(%d) must be <= opkt.pts(%d). Decompression must happen before presentation.", opkt.dts, opkt.pts ); opkt.dts = opkt.pts; } - if ( ipkt->duration == AV_NOPTS_VALUE ) { - opkt.duration = av_rescale_q( duration, video_input_stream->time_base, video_output_stream->time_base); - } else { - opkt.duration = av_rescale_q(ipkt->duration, video_input_stream->time_base, video_output_stream->time_base); - } opkt.flags = ipkt->flags; - opkt.pos=-1; + int keyframe = opkt.flags & AV_PKT_FLAG_KEY; + opkt.pos = -1; opkt.data = ipkt->data; opkt.size = ipkt->size; @@ -712,21 +733,21 @@ int VideoStore::writeVideoFramePacket( AVPacket *ipkt ) { AVPacket safepkt; memcpy( &safepkt, &opkt, sizeof(AVPacket) ); - Debug(1, "writing video packet pts(%d) dts(%d) duration(%d)", opkt.pts, opkt.dts, opkt.duration ); - if ((opkt.data == NULL)||(opkt.size < 1)) { + Debug(1, "writing video packet keyframe(%d) pts(%d) dts(%d) duration(%d) ipkt.duration(%d)", keyframe, opkt.pts, opkt.dts, duration, ipkt->duration); + if ( (opkt.data == NULL) || (opkt.size < 1) ) { Warning("%s:%d: Mangled AVPacket: discarding frame", __FILE__, __LINE__ ); - dumpPacket( ipkt); + dumpPacket(ipkt); dumpPacket(&opkt); - } else if ((video_previous_dts > 0) && (video_previous_dts > opkt.dts)) { - Warning("%s:%d: DTS out of order: %lld \u226E %lld; discarding frame", __FILE__, __LINE__, video_previous_dts, opkt.dts); - video_previous_dts = opkt.dts; + } else if ( (video_next_dts > 0) && (video_next_dts > opkt.dts) ) { + Warning("%s:%d: DTS out of order: %lld \u226E %lld; discarding frame", __FILE__, __LINE__, video_next_dts, opkt.dts); + video_next_dts = opkt.dts; dumpPacket(&opkt); } else { - video_previous_dts = opkt.dts; // Unsure if av_interleaved_write_frame() clobbers opkt.dts when out of order, so storing in advance - video_previous_pts = opkt.pts; + video_next_dts = opkt.dts + duration; // Unsure if av_interleaved_write_frame() clobbers opkt.dts when out of order, so storing in advance + video_next_pts = opkt.pts + duration; ret = av_interleaved_write_frame(oc, &opkt); if ( ret < 0 ) { // There's nothing we can really do if the frame is rejected, just drop it and get on with the next @@ -873,18 +894,20 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) { } // PTS is difficult, because of the buffering of the audio packets in the resampler. So we have to do it once we actually have a packet... + // audio_last_pts is the pts of ipkt, audio_next_pts is the last pts of the output //Scale the PTS of the outgoing packet to be the correct time base +#if 0 if ( ipkt->pts != AV_NOPTS_VALUE ) { if ( ! audio_last_pts ) { opkt.pts = 0; Debug(1, "No audio_last_pts"); } else { if ( audio_last_pts > ipkt->pts ) { - Debug(1, "Resetting audeo_start_pts from (%d) to (%d)", audio_last_pts, ipkt->pts ); - opkt.pts = audio_previous_pts + av_rescale_q(ipkt->pts, audio_input_stream->time_base, audio_output_stream->time_base); + Debug(1, "Resetting audio_start_pts from (%d) to (%d)", audio_last_pts, ipkt->pts ); + opkt.pts = audio_next_pts + av_rescale_q(ipkt->pts, audio_input_stream->time_base, audio_output_stream->time_base); } else { - opkt.pts = audio_previous_pts + av_rescale_q(ipkt->pts - audio_last_pts, audio_input_stream->time_base, audio_output_stream->time_base); + opkt.pts = audio_next_pts + av_rescale_q(ipkt->pts - audio_last_pts, audio_input_stream->time_base, audio_output_stream->time_base); } Debug(2, "audio opkt.pts = %d from ipkt->pts(%d) - last_pts(%d)", opkt.pts, ipkt->pts, audio_last_pts ); } @@ -893,33 +916,35 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) { Debug(2, "opkt.pts = undef"); opkt.pts = AV_NOPTS_VALUE; } +#else + opkt.pts = audio_next_pts; +#endif - //Scale the DTS of the outgoing packet to be the correct time base - if ( ! audio_last_dts ) { - opkt.dts = 0; - - } else { - if( ipkt->dts == AV_NOPTS_VALUE ) { + opkt.dts = audio_next_dts; + +#if 0 + if ( ipkt->dts == AV_NOPTS_VALUE ) { // So if the input has no dts assigned... still need an output dts... so we use cur_dts? - if ( audio_last_dts > audio_input_stream->cur_dts ) { + if ( audio_last_dts >= audio_input_stream->cur_dts ) { Debug(1, "Resetting audio_last_dts from (%d) to cur_dts (%d)", audio_last_dts, audio_input_stream->cur_dts ); - opkt.dts = audio_previous_dts + av_rescale_q( audio_input_stream->cur_dts, AV_TIME_BASE_Q, audio_output_stream->time_base); + opkt.dts = audio_next_dts + av_rescale_q( audio_input_stream->cur_dts, AV_TIME_BASE_Q, audio_output_stream->time_base); } else { - opkt.dts = audio_previous_dts + av_rescale_q( audio_input_stream->cur_dts - audio_last_dts, AV_TIME_BASE_Q, audio_output_stream->time_base); + opkt.dts = audio_next_dts + av_rescale_q( audio_input_stream->cur_dts - audio_last_dts, AV_TIME_BASE_Q, audio_output_stream->time_base); } audio_last_dts = audio_input_stream->cur_dts; Debug(2, "opkt.dts = %d from video_input_stream->cur_dts(%d) - last_dts(%d)", opkt.dts, audio_input_stream->cur_dts, audio_last_dts ); } else { - if ( audio_last_dts > ipkt->dts ) { + if ( audio_last_dts >= ipkt->dts ) { Debug(1, "Resetting audio_last_dts from (%d) to (%d)", audio_last_dts, ipkt->dts ); - opkt.dts = audio_previous_dts + av_rescale_q(ipkt->dts, audio_input_stream->time_base, audio_output_stream->time_base); + opkt.dts = audio_next_dts + av_rescale_q(ipkt->dts, audio_input_stream->time_base, audio_output_stream->time_base); } else { - opkt.dts = audio_previous_dts + av_rescale_q(ipkt->dts - audio_last_dts, audio_input_stream->time_base, audio_output_stream->time_base); + opkt.dts = audio_next_dts + av_rescale_q(ipkt->dts - audio_last_dts, audio_input_stream->time_base, audio_output_stream->time_base); + Debug(2, "opkt.dts = %d from previous(%d) + ( ipkt->dts(%d) - last_dts(%d) )", opkt.dts, audio_next_dts, ipkt->dts, audio_last_dts ); } - Debug(2, "opkt.dts = %d from ipkt->dts(%d) - last_dts(%d)", opkt.dts, ipkt->dts, audio_last_dts ); } } +#endif audio_last_dts = ipkt->dts; if ( opkt.dts > opkt.pts ) { Debug(1,"opkt.dts(%d) must be <= opkt.pts(%d). Decompression must happen before presentation.", opkt.dts, opkt.pts ); @@ -933,13 +958,13 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) { // pkt.pos: byte position in stream, -1 if unknown opkt.pos = -1; opkt.stream_index = audio_output_stream->index;//ipkt->stream_index; + audio_next_dts = opkt.dts + opkt.duration; + audio_next_pts = opkt.pts + opkt.duration; AVPacket safepkt; memcpy(&safepkt, &opkt, sizeof(AVPacket)); - audio_previous_dts = opkt.dts; // Unsure if av_interleaved_write_frame() clobbers opkt.dts when out of order, so storing in advance - audio_previous_pts = opkt.pts; ret = av_interleaved_write_frame(oc, &opkt); - if(ret!=0){ + if ( ret != 0 ) { Error("Error writing audio frame packet: %s\n", av_make_error_string(ret).c_str()); dumpPacket(&safepkt); } else { @@ -948,4 +973,3 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) { zm_av_packet_unref(&opkt); return 0; } // end int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) - diff --git a/src/zm_videostore.h b/src/zm_videostore.h index 36ddd7bcf..bf91415e7 100644 --- a/src/zm_videostore.h +++ b/src/zm_videostore.h @@ -61,10 +61,10 @@ AVAudioResampleContext* resample_context; int64_t audio_last_dts; // These are for output, should start at zero. We assume they do not wrap because we just aren't going to save files that big. - int64_t video_previous_pts; - int64_t video_previous_dts; - int64_t audio_previous_pts; - int64_t audio_previous_dts; + int64_t video_next_pts; + int64_t video_next_dts; + int64_t audio_next_pts; + int64_t audio_next_dts; int64_t filter_in_rescale_delta_last; From 536ccc0cec6d5ed2da332cce26805c39db31c9cb Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 10 Aug 2017 15:44:20 -0400 Subject: [PATCH 035/114] maybe fix memleak, maybe fix crash --- src/zm_ffmpeg_camera.cpp | 13 +++--- src/zm_image.cpp | 89 ++++++++++++++++++---------------------- src/zm_image.h | 58 ++++++++++++-------------- src/zm_logger.cpp | 3 ++ src/zm_logger.h | 3 +- src/zm_videostore.cpp | 22 +++++----- 6 files changed, 92 insertions(+), 96 deletions(-) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index e2152fce9..12d3f4d19 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -271,12 +271,15 @@ int FfmpegCamera::OpenFfmpeg() { } // Set transport method as specified by method field, rtpUni is default - if ( Method() == "rtpMulti" ) { + const std::string method = Method(); + if ( method == "rtpMulti" ) { ret = av_dict_set(&opts, "rtsp_transport", "udp_multicast", 0); - } else if ( Method() == "rtpRtsp" ) { + } else if ( method == "rtpRtsp" ) { ret = av_dict_set(&opts, "rtsp_transport", "tcp", 0); - } else if ( Method() == "rtpRtspHttp" ) { + } else if ( method == "rtpRtspHttp" ) { ret = av_dict_set(&opts, "rtsp_transport", "http", 0); + } else { + Warning("Unknown method (%s)", method); } if ( ret < 0 ) { @@ -834,7 +837,7 @@ else if ( packet.pts && video_last_pts > packet.pts ) { return 0; } } else { - Debug(3, "Not recording audio because we don't have a bvideo keyframe yet"); + Debug(3, "Not recording audio yet because we don't have a video keyframe yet"); } } else { Debug(4, "Not doing recording of audio packet" ); @@ -848,7 +851,7 @@ else if ( packet.pts && video_last_pts > packet.pts ) { #else Debug( 3, "Some other stream index %d", packet.stream_index ); #endif - } + } // end if is video or audio or something else // the packet contents are ref counted... when queuing, we allocate another packet and reference it with that one, so we should always need to unref here, which should not affect the queued version. zm_av_packet_unref( &packet ); diff --git a/src/zm_image.cpp b/src/zm_image.cpp index c6e54d20a..cab8a225d 100644 --- a/src/zm_image.cpp +++ b/src/zm_image.cpp @@ -107,8 +107,7 @@ Image::Image( const char *filename ) { text[0] = '\0'; } -Image::Image( int p_width, int p_height, int p_colours, int p_subpixelorder, uint8_t *p_buffer ) -{ +Image::Image( int p_width, int p_height, int p_colours, int p_subpixelorder, uint8_t *p_buffer ) { if ( !initialised ) Initialise(); width = p_width; @@ -119,21 +118,17 @@ Image::Image( int p_width, int p_height, int p_colours, int p_subpixelorder, uin size = pixels*colours; buffer = 0; holdbuffer = 0; - if ( p_buffer ) - { + if ( p_buffer ) { allocation = size; buffertype = ZM_BUFTYPE_DONTFREE; buffer = p_buffer; - } - else - { + } else { AllocImgBuffer(size); } text[0] = '\0'; } -Image::Image( const Image &p_image ) -{ +Image::Image( const Image &p_image ) { if ( !initialised ) Initialise(); width = p_image.width; @@ -170,8 +165,7 @@ void Image::Deinitialise() { delete readjpg_dcinfo; readjpg_dcinfo = 0; } - if ( decodejpg_dcinfo ) - { + if ( decodejpg_dcinfo ) { jpeg_destroy_decompress( decodejpg_dcinfo ); delete decodejpg_dcinfo; decodejpg_dcinfo = 0; @@ -186,14 +180,13 @@ void Image::Deinitialise() { } } -void Image::Initialise() -{ +void Image::Initialise() { /* Assign the blend pointer to function */ - if(config.fast_image_blends) { - if(config.cpu_extensions && sseversion >= 20) { + if ( config.fast_image_blends ) { + if ( config.cpu_extensions && sseversion >= 20 ) { fptr_blend = &sse2_fastblend; /* SSE2 fast blend */ Debug(4,"Blend: Using SSE2 fast blend function"); - } else if(config.cpu_extensions && neonversion >= 1) { + } else if ( config.cpu_extensions && neonversion >= 1 ) { #if defined(__aarch64__) fptr_blend = &neon64_armv8_fastblend; /* ARM Neon (AArch64) fast blend */ Debug(4,"Blend: Using ARM Neon (AArch64) fast blend function"); @@ -236,8 +229,8 @@ void Image::Initialise() (*fptr_blend)(blend1,blend2,blendres,128,12.0); /* Compare results with expected results */ - for(int i=0;i<128;i++) { - if(abs(blendexp[i] - blendres[i]) > 3) { + for ( int i=0; i < 128; i ++ ) { + if ( abs(blendexp[i] - blendres[i]) > 3 ) { Panic("Blend function failed self-test: Results differ from the expected results. Column %u Expected %u Got %u",i,blendexp[i],blendres[i]); } } @@ -246,8 +239,8 @@ void Image::Initialise() fptr_delta8_bgr = &std_delta8_bgr; /* Assign the delta functions */ - if(config.cpu_extensions) { - if(sseversion >= 35) { + if ( config.cpu_extensions ) { + if ( sseversion >= 35 ) { /* SSSE3 available */ fptr_delta8_rgba = &ssse3_delta8_rgba; fptr_delta8_bgra = &ssse3_delta8_bgra; @@ -255,7 +248,7 @@ void Image::Initialise() fptr_delta8_abgr = &ssse3_delta8_abgr; fptr_delta8_gray8 = &sse2_delta8_gray8; Debug(4,"Delta: Using SSSE3 delta functions"); - } else if(sseversion >= 20) { + } else if ( sseversion >= 20 ) { /* SSE2 available */ fptr_delta8_rgba = &sse2_delta8_rgba; fptr_delta8_bgra = &sse2_delta8_bgra; @@ -263,7 +256,7 @@ void Image::Initialise() fptr_delta8_abgr = &sse2_delta8_abgr; fptr_delta8_gray8 = &sse2_delta8_gray8; Debug(4,"Delta: Using SSE2 delta functions"); - } else if(neonversion >= 1) { + } else if ( neonversion >= 1 ) { /* ARM Neon available */ #if defined(__aarch64__) fptr_delta8_rgba = &neon64_armv8_delta8_rgba; @@ -329,8 +322,8 @@ void Image::Initialise() (*fptr_delta8_gray8)(delta8_1,delta8_2,delta8_gray8_res,128); /* Compare results with expected results */ - for(int i=0;i<128;i++) { - if(abs(delta8_gray8_exp[i] - delta8_gray8_res[i]) > 7) { + for ( int i=0; i < 128; i++ ) { + if ( abs(delta8_gray8_exp[i] - delta8_gray8_res[i]) > 7 ) { Panic("Delta grayscale function failed self-test: Results differ from the expected results. Column %u Expected %u Got %u",i,delta8_gray8_exp[i],delta8_gray8_res[i]); } } @@ -339,8 +332,8 @@ void Image::Initialise() (*fptr_delta8_rgba)(delta8_1,delta8_2,delta8_rgba_res,32); /* Compare results with expected results */ - for(int i=0;i<32;i++) { - if(abs(delta8_rgba_exp[i] - delta8_rgba_res[i]) > 7) { + for ( int i=0; i < 32; i++ ) { + if ( abs(delta8_rgba_exp[i] - delta8_rgba_res[i]) > 7 ) { Panic("Delta RGBA function failed self-test: Results differ from the expected results. Column %u Expected %u Got %u",i,delta8_rgba_exp[i],delta8_rgba_res[i]); } } @@ -359,7 +352,7 @@ void Image::Initialise() #if defined(__i386__) && !defined(__x86_64__) /* Use SSE2 aligned memory copy? */ - if(config.cpu_extensions && sseversion >= 20) { + if ( config.cpu_extensions && sseversion >= 20 ) { fptr_imgbufcpy = &sse2_aligned_memcpy; Debug(4,"Image buffer copy: Using SSE2 aligned memcpy"); } else { @@ -425,24 +418,24 @@ void Image::Initialise() uint8_t* Image::WriteBuffer(const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder) { unsigned int newsize; - if(p_colours != ZM_COLOUR_GRAY8 && p_colours != ZM_COLOUR_RGB24 && p_colours != ZM_COLOUR_RGB32) { + if ( p_colours != ZM_COLOUR_GRAY8 && p_colours != ZM_COLOUR_RGB24 && p_colours != ZM_COLOUR_RGB32 ) { Error("WriteBuffer called with unexpected colours: %d",p_colours); return NULL; } - if(!p_height || !p_width) { + if ( !p_height || !p_width ) { Error("WriteBuffer called with invalid width or height: %d %d",p_width,p_height); return NULL; } - if(p_width != width || p_height != height || p_colours != colours || p_subpixelorder != subpixelorder) { + if ( p_width != width || p_height != height || p_colours != colours || p_subpixelorder != subpixelorder ) { newsize = (p_width * p_height) * p_colours; - if(buffer == NULL) { + if ( buffer == NULL ) { AllocImgBuffer(newsize); } else { - if(allocation < newsize) { - if(holdbuffer) { + if ( allocation < newsize ) { + if ( holdbuffer ) { Error("Held buffer is undersized for requested buffer"); return NULL; } else { @@ -467,30 +460,30 @@ uint8_t* Image::WriteBuffer(const unsigned int p_width, const unsigned int p_hei /* Assign an existing buffer to the image instead of copying from a source buffer. The goal is to reduce the amount of memory copying and increase efficiency and buffer reusing. */ void Image::AssignDirect( const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder, uint8_t *new_buffer, const size_t buffer_size, const int p_buffertype) { - if(new_buffer == NULL) { + if ( new_buffer == NULL ) { Error("Attempt to directly assign buffer from a NULL pointer"); return; } - if(!p_height || !p_width) { + if ( !p_height || !p_width ) { Error("Attempt to directly assign buffer with invalid width or height: %d %d",p_width,p_height); return; } - if(p_colours != ZM_COLOUR_GRAY8 && p_colours != ZM_COLOUR_RGB24 && p_colours != ZM_COLOUR_RGB32) { + if ( p_colours != ZM_COLOUR_GRAY8 && p_colours != ZM_COLOUR_RGB24 && p_colours != ZM_COLOUR_RGB32 ) { Error("Attempt to directly assign buffer with unexpected colours per pixel: %d",p_colours); return; } unsigned int new_buffer_size = ((p_width*p_height)*p_colours); - if(buffer_size < new_buffer_size) { + if ( buffer_size < new_buffer_size ) { Error("Attempt to directly assign buffer from an undersized buffer of size: %zu, needed %dx%d*%d colours = %zu",buffer_size, p_width, p_height, p_colours, new_buffer_size ); return; } - if(holdbuffer && buffer) { - if(new_buffer_size > allocation) { + if ( holdbuffer && buffer ) { + if ( new_buffer_size > allocation ) { Error("Held buffer is undersized for assigned buffer"); return; } else { @@ -502,7 +495,7 @@ void Image::AssignDirect( const unsigned int p_width, const unsigned int p_heigh size = new_buffer_size; // was pixels*colours, but we already calculated it above as new_buffer_size /* Copy into the held buffer */ - if(new_buffer != buffer) + if ( new_buffer != buffer ) (*fptr_imgbufcpy)(buffer, new_buffer, size); /* Free the new buffer */ @@ -529,35 +522,35 @@ void Image::AssignDirect( const unsigned int p_width, const unsigned int p_heigh void Image::Assign(const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder, const uint8_t* new_buffer, const size_t buffer_size) { unsigned int new_size = (p_width * p_height) * p_colours; - if(new_buffer == NULL) { + if ( new_buffer == NULL ) { Error("Attempt to assign buffer from a NULL pointer"); return; } - if(buffer_size < new_size) { + if ( buffer_size < new_size ) { Error("Attempt to assign buffer from an undersized buffer of size: %zu",buffer_size); return; } - if(!p_height || !p_width) { + if ( !p_height || !p_width ) { Error("Attempt to assign buffer with invalid width or height: %d %d",p_width,p_height); return; } - if(p_colours != ZM_COLOUR_GRAY8 && p_colours != ZM_COLOUR_RGB24 && p_colours != ZM_COLOUR_RGB32) { + if ( p_colours != ZM_COLOUR_GRAY8 && p_colours != ZM_COLOUR_RGB24 && p_colours != ZM_COLOUR_RGB32 ) { Error("Attempt to assign buffer with unexpected colours per pixel: %d",p_colours); return; } - if ( !buffer || p_width != width || p_height != height || p_colours != colours || p_subpixelorder != subpixelorder) { + if ( !buffer || p_width != width || p_height != height || p_colours != colours || p_subpixelorder != subpixelorder ) { - if (holdbuffer && buffer) { - if (new_size > allocation) { + if ( holdbuffer && buffer ) { + if ( new_size > allocation ) { Error("Held buffer is undersized for assigned buffer"); return; } } else { - if(new_size > allocation || !buffer) { + if ( new_size > allocation || !buffer ) { DumpImgBuffer(); AllocImgBuffer(new_size); } diff --git a/src/zm_image.h b/src/zm_image.h index 1982d4232..e68e0ff70 100644 --- a/src/zm_image.h +++ b/src/zm_image.h @@ -55,23 +55,26 @@ extern imgbufcpy_fptr_t fptr_imgbufcpy; /* Should be called from Image class functions */ inline static uint8_t* AllocBuffer(size_t p_bufsize) { uint8_t* buffer = (uint8_t*)zm_mallocaligned(64,p_bufsize); - if(buffer == NULL) + if ( buffer == NULL ) Fatal("Memory allocation failed: %s",strerror(errno)); return buffer; } inline static void DumpBuffer(uint8_t* buffer, int buffertype) { - if (buffer && buffertype != ZM_BUFTYPE_DONTFREE) { - if(buffertype == ZM_BUFTYPE_ZM) - zm_freealigned(buffer); - else if(buffertype == ZM_BUFTYPE_MALLOC) - free(buffer); - else if(buffertype == ZM_BUFTYPE_NEW) - delete buffer; + if ( buffer && buffertype != ZM_BUFTYPE_DONTFREE ) { + if ( buffertype == ZM_BUFTYPE_ZM ) { + zm_freealigned(buffer); + } else if ( buffertype == ZM_BUFTYPE_MALLOC ) { + free(buffer); + } else if ( buffertype == ZM_BUFTYPE_NEW ) { + delete buffer; /*else if(buffertype == ZM_BUFTYPE_AVMALLOC) av_free(buffer); */ + } else { + Error( "Unknown buffer type in DumpBuffer(%d)", buffertype ); + } } } @@ -80,27 +83,23 @@ inline static void DumpBuffer(uint8_t* buffer, int buffertype) { // This is image class, and represents a frame captured from a // camera in raw form. // -class Image -{ +class Image { protected: - struct Edge - { + struct Edge { int min_y; int max_y; double min_x; double _1_m; - static int CompareYX( const void *p1, const void *p2 ) - { + static int CompareYX( const void *p1, const void *p2 ) { const Edge *e1 = (const Edge *)p1, *e2 = (const Edge *)p2; if ( e1->min_y == e2->min_y ) return( int(e1->min_x - e2->min_x) ); else return( int(e1->min_y - e2->min_y) ); } - static int CompareX( const void *p1, const void *p2 ) - { + static int CompareX( const void *p1, const void *p2 ) { const Edge *e1 = (const Edge *)p1, *e2 = (const Edge *)p2; return( int(e1->min_x - e2->min_x) ); } @@ -113,7 +112,7 @@ protected: } inline void AllocImgBuffer(size_t p_bufsize) { - if(buffer) + if ( buffer ) DumpImgBuffer(); buffer = AllocBuffer(p_bufsize); @@ -176,27 +175,24 @@ public: inline void HoldBuffer(int tohold) { holdbuffer = tohold; } inline void Empty() { - if(!holdbuffer) - DumpImgBuffer(); - - width = height = colours = size = pixels = subpixelorder = 0; + if ( !holdbuffer ) + DumpImgBuffer(); + + width = height = colours = size = pixels = subpixelorder = 0; } void Assign( unsigned int p_width, unsigned int p_height, unsigned int p_colours, unsigned int p_subpixelorder, const uint8_t* new_buffer, const size_t buffer_size); void Assign( const Image &image ); void AssignDirect( const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder, uint8_t *new_buffer, const size_t buffer_size, const int p_buffertype); - inline void CopyBuffer( const Image &image ) - { + inline void CopyBuffer( const Image &image ) { Assign(image); } - inline Image &operator=( const Image &image ) - { + inline Image &operator=( const Image &image ) { Assign(image); return *this; } - inline Image &operator=( const unsigned char *new_buffer ) - { + inline Image &operator=( const unsigned char *new_buffer ) { (*fptr_imgbufcpy)(buffer, new_buffer, size); return( *this ); } @@ -207,9 +203,9 @@ public: bool ReadJpeg( const char *filename, unsigned int p_colours, unsigned int p_subpixelorder); bool WriteJpeg ( const char *filename) const; - bool WriteJpeg ( const char *filename, int quality_override ) const; - bool WriteJpeg ( const char *filename, struct timeval timestamp ) const; - bool WriteJpeg ( const char *filename, int quality_override, struct timeval timestamp ) const; + bool WriteJpeg ( const char *filename, int quality_override ) const; + bool WriteJpeg ( const char *filename, struct timeval timestamp ) const; + bool WriteJpeg ( const char *filename, int quality_override, struct timeval timestamp ) const; bool DecodeJpeg( const JOCTET *inbuffer, int inbuffer_size, unsigned int p_colours, unsigned int p_subpixelorder); bool EncodeJpeg( JOCTET *outbuffer, int *outbuffer_size, int quality_override=0 ) const; @@ -232,7 +228,7 @@ public: void Delta( const Image &image, Image* targetimage) const; const Coord centreCoord( const char *text ) const; - void MaskPrivacy( const unsigned char *p_bitmask, const Rgb pixel_colour=0x00222222 ); + void MaskPrivacy( const unsigned char *p_bitmask, const Rgb pixel_colour=0x00222222 ); void Annotate( const char *p_text, const Coord &coord, const unsigned int size=1, const Rgb fg_colour=RGB_WHITE, const Rgb bg_colour=RGB_BLACK ); Image *HighlightEdges( Rgb colour, unsigned int p_colours, unsigned int p_subpixelorder, const Box *limits=0 ); //Image *HighlightEdges( Rgb colour, const Polygon &polygon ); diff --git a/src/zm_logger.cpp b/src/zm_logger.cpp index a30c819e3..4a4756f4c 100644 --- a/src/zm_logger.cpp +++ b/src/zm_logger.cpp @@ -112,6 +112,9 @@ Logger::Logger() : Logger::~Logger() { terminate(); + for ( StringMap::iterator itr = smCodes.begin(); itr != smCodes.end(); itr ++ ) { + smCodes.erase( itr ); + } } void Logger::initialise( const std::string &id, const Options &options ) { diff --git a/src/zm_logger.h b/src/zm_logger.h index e50b81ca5..27a998c5f 100644 --- a/src/zm_logger.h +++ b/src/zm_logger.h @@ -30,8 +30,7 @@ #endif // HAVE_SYS_SYSCALL_H #include -class Logger -{ +class Logger { public: enum { NOOPT=-6, diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index f3656143c..d87886002 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -63,24 +63,24 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, av_make_error_string(ret).c_str() ); } else { - Debug(2, "Success allocating output context"); + Debug(4, "Success allocating output format context"); } //Couldn't deduce format from filename, trying from format name - if ( ! oc ) { + if ( !oc ) { avformat_alloc_output_context2(&oc, NULL, format, filename); - if (!oc) { + if ( !oc ) { Fatal("Could not create video storage stream %s as no output context" " could not be assigned based on filename or format %s", filename, format); + } else { + Debug(4, "Success alocateing output context"); } - } else { - Debug(2, "Success alocateing output context"); - } + } // end if ! oc AVDictionary *pmetadata = NULL; int dsr = av_dict_set(&pmetadata, "title", "Zoneminder Security Recording", 0); - if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__ ); + if ( dsr < 0 ) Warning("%s:%d: title set failed", __FILE__, __LINE__ ); oc->metadata = pmetadata; output_format = oc->oformat; @@ -348,7 +348,7 @@ VideoStore::~VideoStore(){ #endif Debug(2, "writing flushed packet pts(%d) dts(%d) duration(%d)", pkt.pts, pkt.dts, pkt.duration); pkt.pts = audio_next_pts; - pkt.dts = audio_next_dts; + pkt.dts = audio_next_dts; if ( pkt.duration > 0 ) pkt.duration = av_rescale_q(pkt.duration, audio_output_context->time_base, audio_output_stream->time_base); @@ -377,12 +377,12 @@ VideoStore::~VideoStore(){ // What if we were only doing audio recording? if ( video_output_stream ) { avcodec_close(video_output_context); - av_free(video_output_context); + //av_free(video_output_context); video_output_context = NULL; } if (audio_output_stream) { avcodec_close(audio_output_context); - av_free(audio_output_context); + //av_free(audio_output_context); audio_output_context = NULL; #ifdef HAVE_LIBAVRESAMPLE if ( resample_context ) { @@ -871,6 +871,8 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) { zm_av_packet_unref(&opkt); return 0; } + av_frame_unref( input_frame ); + av_frame_unref( output_frame ); #else if (( ret = avcodec_encode_audio2( audio_output_context, &opkt, output_frame, &data_present )) < 0) { Error( "Could not encode frame (error '%s')", From fd7ea84e81b8d1afc7a2878025a86dbfdd06b2dd Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Thu, 10 Aug 2017 20:34:05 -0500 Subject: [PATCH 036/114] Update README.md Point users to rpmfusion for zoneminder rpm releases --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 460fe62ff..60b8451d5 100644 --- a/README.md +++ b/README.md @@ -27,8 +27,8 @@ This is the recommended method to install ZoneMinder onto your system. ZoneMinde - Ubuntu via [Iconnor's PPA](https://launchpad.net/~iconnor/+archive/ubuntu/zoneminder) - Debian from their [default repository](https://packages.debian.org/search?searchon=names&keywords=zoneminder) -- RHEL/CentOS and clones via [zmrepo](http://zmrepo.zoneminder.com/) -- Fedora via [zmrepo](http://zmrepo.zoneminder.com/) +- RHEL/CentOS and clones via [RPMFusion](http://rpmfusion.org) +- Fedora via [RPMFusion](http://rpmfusion.org) - OpenSuse via [third party repository](http://www.zoneminder.com/wiki/index.php/Installing_using_ZoneMinder_RPMs_for_SuSE) - Mageia from their default repository From a64810fcfcc94ffdf9d757d21bc10e9f5241e715 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Thu, 10 Aug 2017 20:34:48 -0500 Subject: [PATCH 037/114] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 60b8451d5..4c318b659 100644 --- a/README.md +++ b/README.md @@ -27,8 +27,8 @@ This is the recommended method to install ZoneMinder onto your system. ZoneMinde - Ubuntu via [Iconnor's PPA](https://launchpad.net/~iconnor/+archive/ubuntu/zoneminder) - Debian from their [default repository](https://packages.debian.org/search?searchon=names&keywords=zoneminder) -- RHEL/CentOS and clones via [RPMFusion](http://rpmfusion.org) -- Fedora via [RPMFusion](http://rpmfusion.org) +- RHEL/CentOS and clones via [RPM Fusion](http://rpmfusion.org) +- Fedora via [RPM Fusion](http://rpmfusion.org) - OpenSuse via [third party repository](http://www.zoneminder.com/wiki/index.php/Installing_using_ZoneMinder_RPMs_for_SuSE) - Mageia from their default repository From 0a5188d79f47f3c7366fa27a499fecbf2d97cc21 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Thu, 10 Aug 2017 20:55:22 -0500 Subject: [PATCH 038/114] Update redhat.rst --- docs/installationguide/redhat.rst | 40 +++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/docs/installationguide/redhat.rst b/docs/installationguide/redhat.rst index d662d1812..6f4240d6b 100644 --- a/docs/installationguide/redhat.rst +++ b/docs/installationguide/redhat.rst @@ -23,30 +23,46 @@ Fedora has a short life-cycle of just 6 months. However, Fedora, and consequentl If you desire newer packages than what is available in RHEL or CentOS, you should consider using Fedora. -Zmrepo – A ZoneMinder RPM Repository ------------------------------------- +How To Avoid Known Installation Problems +---------------------------------------- -Zmrepo is a turn key solution. It will install all of ZoneMinder's dependencies for you. This is the easiest and the recommended way to install ZoneMinder on any system running a Redhat based distribution. +The following notes are based on real problems which have occurred by those who came before you: -Zmrepo supports the two most recent, major releases of each Redhat based distro. - -The following notes are based on real problems which have occurred: - -- Zmrepo assumes you have installed the underlying distribution **using the official installation media for that distro**. Third party "Spins" are not supported and may not work correctly. +- Zmrepo assumes you have installed the underlying distribution **using the official installation media for that distro**. Third party "Spins" may not work correctly. - ZoneMinder is intended to be installed in an environment dedicated to ZoneMinder. While ZoneMinder will play well with many applications, some invariably will not. Asterisk is one such example. -- Be advised that you need to start with a clean system before using zmrepo. +- Be advised that you need to start with a clean system before installing ZoneMinder. - If you have previously installed ZoneMinder from-source, then your system is **NOT** clean. You must manually search for and delete all ZoneMinder related files before using zmrepo (look under /usr/local). Make uninstall helps, but it will not do this for you correctly. You **WILL** have problems if you ignore this step. -- It is not necessary, and not recommended, to install a LAMP stack ahead of time. +- Unlike the Debian/Ubuntu packages, it is not necessary, and not recommended, to install a LAMP stack ahead of time. -- Disable other third party repos and uninstall any of ZoneMinder's third party dependencies, which might already be on the system, especially ffmpeg and vlc. Attempting to install dependencies yourself often causes problems. +- Disable any other third party repos and uninstall any of ZoneMinder's third party dependencies, which might already be on the system, especially ffmpeg and vlc. Attempting to install dependencies yourself often causes problems. - Each ZoneMinder rpm includes a README file under /usr/share/doc. You must follow the all steps in this README file, precisely, each and every time ZoneMinder is installed or upgraded. **Failure to do so is guaranteed to result in a non-functional system.** -To begin the installation of ZoneMinder on your Redhat based distro, please navigate to: http://zmrepo.zoneminder.com +How to Install ZoneMinder +------------------------- + +These instructions apply to all redhat user, except for RHEL/CEntOS 6. + +ZoneMinder releases are now being hosted at RPM Fusion. New users should navigate the `RPM Fusion site `_ then follow the instructions to enable that repo. Note the RHEL/CentOS must also navaigate to the `EPEL Site `_ and enable that repo as well. Once both of these repositories are enabled, install ZoneMinder from the commandline: + +:: + + sudo dnf install zoneminder + +Note that RHEL/CentOS 7 users should substitute yum for dnf. + +Once ZoneMinder has been installed, it is critically important that you read the README file under /usr/share/doc/zoneminder. ZoneMinder will not run without completing the steps outlined in the README. + +How to Install ZoneMinder on RHEL/CentOS 6 +------------------------------------------ + +We continue to encounter build problems, caused by the age of this distro. However, we can see the writing on the wall. The end of the line for this distros is near. + +Please be advised that we do not recommend any new ZoneMinder installations using CentOS 6. However, for the time being, ZoneMinder rpms will continue to be hosted at `zmrepo `_. How to Build a (Custom) ZoneMinder Package ------------------------------------------ From 27796ab720e1e3a645533739d6eac793009f2e08 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Thu, 10 Aug 2017 20:57:26 -0500 Subject: [PATCH 039/114] Update redhat.rst --- docs/installationguide/redhat.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/installationguide/redhat.rst b/docs/installationguide/redhat.rst index 6f4240d6b..f9403ba49 100644 --- a/docs/installationguide/redhat.rst +++ b/docs/installationguide/redhat.rst @@ -45,7 +45,7 @@ The following notes are based on real problems which have occurred by those who How to Install ZoneMinder ------------------------- -These instructions apply to all redhat user, except for RHEL/CEntOS 6. +These instructions apply to all redhat distros and compatible clones, except for RHEL/CEntOS 6. ZoneMinder releases are now being hosted at RPM Fusion. New users should navigate the `RPM Fusion site `_ then follow the instructions to enable that repo. Note the RHEL/CentOS must also navaigate to the `EPEL Site `_ and enable that repo as well. Once both of these repositories are enabled, install ZoneMinder from the commandline: @@ -60,7 +60,7 @@ Once ZoneMinder has been installed, it is critically important that you read the How to Install ZoneMinder on RHEL/CentOS 6 ------------------------------------------ -We continue to encounter build problems, caused by the age of this distro. However, we can see the writing on the wall. The end of the line for this distros is near. +We continue to encounter build problems, caused by the age of this distro. It is unforuntate, but we can see the writing on the wall. We do not have a date set, but the end of the line for this distros is near. Please be advised that we do not recommend any new ZoneMinder installations using CentOS 6. However, for the time being, ZoneMinder rpms will continue to be hosted at `zmrepo `_. From 5589b318a3193b5aec224ed0d871c18c72dea7b4 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 11 Aug 2017 08:02:02 -0400 Subject: [PATCH 040/114] test fix crashes --- src/zm_videostore.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index f3656143c..33451ccf8 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -377,12 +377,12 @@ VideoStore::~VideoStore(){ // What if we were only doing audio recording? if ( video_output_stream ) { avcodec_close(video_output_context); - av_free(video_output_context); + //av_free(video_output_context); video_output_context = NULL; } if (audio_output_stream) { avcodec_close(audio_output_context); - av_free(audio_output_context); + //av_free(audio_output_context); audio_output_context = NULL; #ifdef HAVE_LIBAVRESAMPLE if ( resample_context ) { @@ -402,9 +402,6 @@ VideoStore::~VideoStore(){ Debug(3, "Not closing avio because we are not writing to a file."); } - /* free the stream */ - avformat_free_context(oc); - if ( input_frame ) { av_frame_free( &input_frame ); input_frame = NULL; @@ -413,6 +410,10 @@ VideoStore::~VideoStore(){ av_frame_free( &output_frame ); output_frame = NULL; } + + /* free the stream */ + avformat_free_context(oc); + } bool VideoStore::setup_resampler() { From 4941e6715cd30443e7a2be87033094a0a67af51a Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Fri, 11 Aug 2017 07:49:59 -0500 Subject: [PATCH 041/114] Update redhat.rst --- docs/installationguide/redhat.rst | 32 ++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/docs/installationguide/redhat.rst b/docs/installationguide/redhat.rst index f9403ba49..8724436a4 100644 --- a/docs/installationguide/redhat.rst +++ b/docs/installationguide/redhat.rst @@ -34,9 +34,9 @@ The following notes are based on real problems which have occurred by those who - Be advised that you need to start with a clean system before installing ZoneMinder. -- If you have previously installed ZoneMinder from-source, then your system is **NOT** clean. You must manually search for and delete all ZoneMinder related files before using zmrepo (look under /usr/local). Make uninstall helps, but it will not do this for you correctly. You **WILL** have problems if you ignore this step. +- If you have previously installed ZoneMinder from-source, then your system is **NOT** clean. You must manually search for and delete all ZoneMinder related files first (look under /usr/local). Issuing a "make uninstall" helps, but it will not do this for you correctly. You **WILL** have problems if you ignore this step. -- Unlike the Debian/Ubuntu packages, it is not necessary, and not recommended, to install a LAMP stack ahead of time. +- Unlike Debian/Ubuntu distros, it is not necessary, and not recommended, to install a LAMP stack ahead of time. - Disable any other third party repos and uninstall any of ZoneMinder's third party dependencies, which might already be on the system, especially ffmpeg and vlc. Attempting to install dependencies yourself often causes problems. @@ -45,15 +45,15 @@ The following notes are based on real problems which have occurred by those who How to Install ZoneMinder ------------------------- -These instructions apply to all redhat distros and compatible clones, except for RHEL/CEntOS 6. +These instructions apply to all redhat distros and compatible clones, except for RHEL/CentOS 6. -ZoneMinder releases are now being hosted at RPM Fusion. New users should navigate the `RPM Fusion site `_ then follow the instructions to enable that repo. Note the RHEL/CentOS must also navaigate to the `EPEL Site `_ and enable that repo as well. Once both of these repositories are enabled, install ZoneMinder from the commandline: +ZoneMinder releases are now being hosted at RPM Fusion. New users should navigate the `RPM Fusion site `_ then follow the instructions to enable that repo. RHEL/CentOS users must also navaigate to the `EPEL Site `_ and enable that repo as well. Once enabled, install ZoneMinder from the commandline: :: sudo dnf install zoneminder -Note that RHEL/CentOS 7 users should substitute yum for dnf. +Note that RHEL/CentOS 7 users should use yum instead of dnf. Once ZoneMinder has been installed, it is critically important that you read the README file under /usr/share/doc/zoneminder. ZoneMinder will not run without completing the steps outlined in the README. @@ -64,6 +64,28 @@ We continue to encounter build problems, caused by the age of this distro. It is Please be advised that we do not recommend any new ZoneMinder installations using CentOS 6. However, for the time being, ZoneMinder rpms will continue to be hosted at `zmrepo `_. +How to Install Nightly Development Builds +----------------------------------------- + +ZoneMinder development packages, which represent the most recent build from our master branch, are available from `zmrepo `_. + +The feedback we get from those who use these development packages is extremely helpful. However, please understand these packages are intended for testing the latest master branch only. They are not intended to be used on any production system. There will be new bugs, and new features may not be documented. This is bleeding edge, and there might be breakage. Please keep that in mind when using this repo. We know from our user forum that this can't be stated enough. + +How to Change from Zmrepo to RPM Fusion +--------------------------------------- + +As mentioned above, the place to get the latest ZoneMinder release is now `RPM Fusion `_. If you are currently using ZoneMinder release packages from Zmrepo, then the following steps will change you over to RPM Fusion: + +- Navigate to the `RPM Fusion site `_ and enable RPM Fusion on your system +- Now issue the following from the command line: + +:: + + sudo dnf remove zmrepo + sudo dnf update + +Note that RHEL/CentOS 7 users should use yum instead of dnf. + How to Build a (Custom) ZoneMinder Package ------------------------------------------ From 64cf80ccf48e3f68a44f4074a0654211a5fce69e Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Fri, 11 Aug 2017 07:52:25 -0500 Subject: [PATCH 042/114] Update redhat.rst --- docs/installationguide/redhat.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installationguide/redhat.rst b/docs/installationguide/redhat.rst index 8724436a4..00a39c9c9 100644 --- a/docs/installationguide/redhat.rst +++ b/docs/installationguide/redhat.rst @@ -10,7 +10,7 @@ Background: RHEL, CentOS, and Clones These distributions are classified as enterprise operating systems and have a long operating lifetime of many years. By design, they will not have the latest and greatest versions of any package. Instead, stable packages are the emphasis. -Replacing any core package in these distributions with a newer package from a third party is expressly verboten. The ZoneMinder development team will not do this, and neither should you. If you have the perception that you've got to have a newer version of mysql, gnome, apache, etc. then, rather than upgrade these packages, you should instead consider using a different distribution such as Fedora. +Replacing any core package in these distributions with a newer package from a third party is expressly verboten. The ZoneMinder development team will not do this, and neither should you. If you have the perception that you've got to have a newer version of php, mysql, gnome, apache, etc. then, rather than upgrade these packages, you should instead consider using a different distribution such as Fedora. The ZoneMinder team will not provide support for systems which have had any core package replaced with a package from a third party. From 565612b86b229302c4d3277ec9f2f04f9148318c Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Fri, 11 Aug 2017 07:55:29 -0500 Subject: [PATCH 043/114] Update redhat.rst --- docs/installationguide/redhat.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installationguide/redhat.rst b/docs/installationguide/redhat.rst index 00a39c9c9..adb6b4503 100644 --- a/docs/installationguide/redhat.rst +++ b/docs/installationguide/redhat.rst @@ -40,7 +40,7 @@ The following notes are based on real problems which have occurred by those who - Disable any other third party repos and uninstall any of ZoneMinder's third party dependencies, which might already be on the system, especially ffmpeg and vlc. Attempting to install dependencies yourself often causes problems. -- Each ZoneMinder rpm includes a README file under /usr/share/doc. You must follow the all steps in this README file, precisely, each and every time ZoneMinder is installed or upgraded. **Failure to do so is guaranteed to result in a non-functional system.** +- Each ZoneMinder rpm includes a README file under /usr/share/doc. You must follow all the steps in this README file, precisely, each and every time ZoneMinder is installed or upgraded. **Failure to do so is guaranteed to result in a non-functional system.** How to Install ZoneMinder ------------------------- From c60939e8247543b7af56c98b446c03de7f93c094 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 11 Aug 2017 09:08:00 -0400 Subject: [PATCH 044/114] fix absolute path to index.php in console.js --- web/skins/classic/views/js/console.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/console.js b/web/skins/classic/views/js/console.js index 5e8f147b1..91655aac5 100644 --- a/web/skins/classic/views/js/console.js +++ b/web/skins/classic/views/js/console.js @@ -88,7 +88,7 @@ $j( function() { function applySort(event, ui) { var monitor_ids = $j(this).sortable('toArray'); var ajax = new Request.JSON( { - url: '/index.php?request=console', + url: '?request=console', data: { monitor_ids: monitor_ids, action: 'sort' }, method: 'post', timeout: AJAX_TIMEOUT From ae8873c2ccb0ca53baf025429ae1a21fe4e9de83 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Fri, 11 Aug 2017 08:44:02 -0500 Subject: [PATCH 045/114] Update redhat.rst --- docs/installationguide/redhat.rst | 35 ++++++++++++++----------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/docs/installationguide/redhat.rst b/docs/installationguide/redhat.rst index adb6b4503..b91b12185 100644 --- a/docs/installationguide/redhat.rst +++ b/docs/installationguide/redhat.rst @@ -86,14 +86,14 @@ As mentioned above, the place to get the latest ZoneMinder release is now `RPM F Note that RHEL/CentOS 7 users should use yum instead of dnf. -How to Build a (Custom) ZoneMinder Package +How to Build a Your Own ZoneMinder Package ------------------------------------------ -If you are looking to do development or the packages in zmrepo just don't suit you, then you should follow these steps to learn how to build your own ZoneMinder RPM. +If you are looking to do development or the available packages just don't suit you, then you can follow these steps to build your own ZoneMinder RPM. Background ********** -The following method documents how to build ZoneMinder into an RPM package, compatible with Fedora, Redhat, CentOS, and other compatible clones. This is exactly how the RPMS in zmrepo are built. +The following method documents how to build ZoneMinder into an RPM package, for Fedora, Redhat, CentOS, and other compatible clones. This is exactly how the RPMS in zmrepo are built. The method documented below was chosen because: @@ -105,22 +105,20 @@ The method documented below was chosen because: - Troubleshooting becomes easier if we are all building ZoneMinder the same way. -The build instructions below make use of a custom script called "buildzm.sh". Advanced users are encouraged to view the contents of this script. Notice that the script doesn't really do a whole lot. The goal of the script is to simply make the process a little easier for the first time user. Once you become familar with the build process, you can issue the mock commands found in the buildzm.sh script yourself if you so desire. - ***IMPORTANT*** -Certain commands in these instructions require root privileges while other commands do not. Pay close attention to this. If the instructions below state to issue a command without a “sudo” prefix, then you should *not* be root while issuing the command. Getting this incorrect will result in a failed build. +Certain commands in these instructions require root privileges while other commands do not. Pay close attention to this. If the instructions below state to issue a command without a “sudo” prefix, then you should *not* be root while issuing the command. Getting this incorrect will result in a failed build, or worse a broken system. Set Up Your Environment *********************** Before you begin, set up an rpmbuild environment by following `this guide `_ by the CentOS developers. -Next, navigate to `Zmrepo `_, and follow the instructions to enable zmrepo on your system. +In addition, make sure RPM Fusion is enabled as described in the previous section `How to Install ZoneMinder`_. -With zmrepo enabled, issue the following command: +With RPM Fusion enabled, issue the following command: :: - sudo yum install zmrepo-mock-configs mock + sudo yum install mock-rpmfusion-free mock Add your user account to the group mock: @@ -134,9 +132,9 @@ Your build environment is now set up. Build from SRPM *************** -To continue, you need a ZoneMinder SRPM. For starters, let's use one of the SRPMS from zmrepo. Go browse the `Zmrepo `_ site and choose an appropriate SRPM and place it into the ~/rpmbuild/SRPMS folder. +To continue, you need a ZoneMinder SRPM. If you wish to rebuild a ZoneMinder release, then browse the `RPM Fusion site `_. If instead you wish to rebuild the latest package from our master branch then browse the `Zmrepo site`_. -For CentOS 7, I have chosen the following SRPM: +For this example, I'll use one of the SRPMS from zmrepo: :: @@ -147,36 +145,35 @@ Now comes the fun part. To build ZoneMinder, issue the following command: :: - buildzm.sh zmrepo-el7-x86_64 ~/rpmbuild/SRPMS/zoneminder-1.28.1-2.el7.centos.src.rpm + mock -r epel-7-x86_64-rpmfusion_free ~/rpmbuild/SRPMS/zoneminder-1.28.1-2.el7.centos.src.rpm Want to build ZoneMinder for Fedora, instead of CentOS, from the same host? Once you download the Fedora SRPM, issue the following: :: - buildzm.sh zmrepo-f21-x86_64 ~/rpmbuild/SRPMS/zoneminder-1.28.1-1.fc21.src.rpm + mock -r fedora-26-x86_64-rpmfusion_free ~/rpmbuild/SRPMS/zoneminder-1.28.1-1.fc21.src.rpm -Notice that the buildzm.sh tool requires the following parameters: +Notice that the mock tool requires the following parameters: :: - buildzm.sh MOCKCONFIG ZONEMINDER_SRPM + mock -r MOCKCONFIG ZONEMINDER_SRPM The list of available Mock config files are available here: :: - ls /etc/mock/zmrepo*.cfg + ls /etc/mock/*rpmfusion_free.cfg You choose the config file based on the desired distro (e.g. el6, el7, f20, f21) and basearch (e.g. x86, x86_64, arhmhfp). Notice that, when specifying the Mock config as a commandline parameter, you should leave off the ".cfg" filename extension. Installation ************ -Once the build completes, you will be presented with a folder containing the RPM's that were built. Copy the newly built ZoneMinder RPM to the desired system, enable zmrepo per the instruction on the `Zmrepo `_ -website, and then install the rpm by issuing the appropriate yum install command. Finish the installation by following the zoneminder setup instructions in the distro specific readme file, named README.{distroname}, which will be installed into the /usr/share/doc/zoneminder* folder. +Once the build completes, you will be presented with a folder containing the RPMs that were built. Copy the newly built ZoneMinder RPMs to the desired system, enable RPM Fusion as described in `How to Install ZoneMinder`_, and then install the rpm by issuing the appropriate yum/dnf install command. Finish the installation by following the zoneminder setup instructions in the distro specific readme file, named README.{distroname}, which will be installed into the /usr/share/doc/zoneminder* folder. -Finally, you may want to consider editing the zmrepo repo file under /etc/yum.repos.d and placing an “exclude=zoneminder*” line into the config file. This will prevent your system from overwriting your manually built RPM with the ZoneMinder RPM found in the repo. +Finally, you may want to consider editing the rpmfusion repo file under /etc/yum.repos.d and placing an “exclude=zoneminder*” line into the config file. This will prevent your system from overwriting your manually built RPM with the ZoneMinder RPM found in the repo. How to Modify the Source Prior to Build *************************************** From 4187da2d5a02a62b509f78a7deced5f35d84d5a5 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Fri, 11 Aug 2017 08:45:34 -0500 Subject: [PATCH 046/114] Update redhat.rst --- docs/installationguide/redhat.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installationguide/redhat.rst b/docs/installationguide/redhat.rst index b91b12185..b0fce8cf6 100644 --- a/docs/installationguide/redhat.rst +++ b/docs/installationguide/redhat.rst @@ -132,7 +132,7 @@ Your build environment is now set up. Build from SRPM *************** -To continue, you need a ZoneMinder SRPM. If you wish to rebuild a ZoneMinder release, then browse the `RPM Fusion site `_. If instead you wish to rebuild the latest package from our master branch then browse the `Zmrepo site`_. +To continue, you need a ZoneMinder SRPM. If you wish to rebuild a ZoneMinder release, then browse the `RPM Fusion site `_. If instead you wish to rebuild the latest package from our master branch then browse the `Zmrepo site `_. For this example, I'll use one of the SRPMS from zmrepo: From 3a7ad58c255dbb639e92ce22521ca36ef022c9e3 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Fri, 11 Aug 2017 08:55:57 -0500 Subject: [PATCH 047/114] Update redhat.rst --- docs/installationguide/redhat.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/installationguide/redhat.rst b/docs/installationguide/redhat.rst index b0fce8cf6..587dd3532 100644 --- a/docs/installationguide/redhat.rst +++ b/docs/installationguide/redhat.rst @@ -171,7 +171,13 @@ You choose the config file based on the desired distro (e.g. el6, el7, f20, f21) Installation ************ -Once the build completes, you will be presented with a folder containing the RPMs that were built. Copy the newly built ZoneMinder RPMs to the desired system, enable RPM Fusion as described in `How to Install ZoneMinder`_, and then install the rpm by issuing the appropriate yum/dnf install command. Finish the installation by following the zoneminder setup instructions in the distro specific readme file, named README.{distroname}, which will be installed into the /usr/share/doc/zoneminder* folder. +Once the build completes, you will be presented with a message stating where the newly built rpms can be found. It will look similar to this: + +:: + + INFO: Results and/or logs in: /var/lib/mock/fedora-26-x86_64/result + +Copy the newly built ZoneMinder RPMs to the desired system, enable RPM Fusion as described in `How to Install ZoneMinder`_, and then install the rpm by issuing the appropriate yum/dnf install command. Finish the installation by following the zoneminder setup instructions in the distro specific readme file, named README.{distroname}, which will be installed into the /usr/share/doc/zoneminder* folder. Finally, you may want to consider editing the rpmfusion repo file under /etc/yum.repos.d and placing an “exclude=zoneminder*” line into the config file. This will prevent your system from overwriting your manually built RPM with the ZoneMinder RPM found in the repo. From daee5b4450635b4045133b25b1b241d8b03d1e44 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 11 Aug 2017 12:03:37 -0400 Subject: [PATCH 048/114] experiment with no ffmpeg thread --- src/zm_config.cpp | 2 + src/zm_ffmpeg_camera.cpp | 53 ++++++++---- src/zm_logger.cpp | 183 +++++++++++++++++++++------------------ src/zm_monitor.cpp | 101 ++++++++++++--------- src/zm_videostore.cpp | 42 +++++---- 5 files changed, 222 insertions(+), 159 deletions(-) diff --git a/src/zm_config.cpp b/src/zm_config.cpp index 03f7b587a..945838567 100644 --- a/src/zm_config.cpp +++ b/src/zm_config.cpp @@ -288,8 +288,10 @@ Config::~Config() { if ( items ) { for ( int i = 0; i < n_items; i++ ) { delete items[i]; + items[i] = NULL; } delete[] items; + items = NULL; } } diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 12d3f4d19..c1884a9f4 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -115,13 +115,20 @@ int FfmpegCamera::PrimeCapture() { mAudioStreamId = -1; Info( "Priming capture from %s", mPath.c_str() ); +#if THREAD if ( OpenFfmpeg() != 0 ) { ReopenFfmpeg(); } return 0; +#else + return OpenFfmpeg(); +#endif } int FfmpegCamera::PreCapture() { + // If Reopen was called, then ffmpeg is closed and we need to reopen it. + if ( ! mCanCapture ) + return OpenFfmpeg(); // Nothing to do here return( 0 ); } @@ -283,14 +290,18 @@ int FfmpegCamera::OpenFfmpeg() { } if ( ret < 0 ) { - Warning("Could not set rtsp_transport method '%s'\n", Method().c_str()); + Warning("Could not set rtsp_transport method '%s'\n", method.c_str()); } - Debug ( 1, "Calling avformat_open_input" ); + Debug ( 1, "Calling avformat_open_input for %s", mPath.c_str() ); mFormatContext = avformat_alloc_context( ); - mFormatContext->interrupt_callback.callback = FfmpegInterruptCallback; - mFormatContext->interrupt_callback.opaque = this; + //mFormatContext->interrupt_callback.callback = FfmpegInterruptCallback; + //mFormatContext->interrupt_callback.opaque = this; + // Speed up find_stream_info + //FIXME can speed up initial analysis but need sensible parameters... + //mFormatContext->probesize = 32; + //mFormatContext->max_analyze_duration = 32; if ( avformat_open_input( &mFormatContext, mPath.c_str(), NULL, &opts ) != 0 ) #endif @@ -310,10 +321,6 @@ int FfmpegCamera::OpenFfmpeg() { Info( "Stream open %s", mPath.c_str() ); - //FIXME can speed up initial analysis but need sensible parameters... - //mFormatContext->probesize = 32; - //mFormatContext->max_analyze_duration = 32; - // Locate stream info from avformat_open_input #if !LIBAVFORMAT_VERSION_CHECK(53, 6, 0, 6, 0) Debug ( 1, "Calling av_find_stream_info" ); if ( av_find_stream_info( mFormatContext ) < 0 ) @@ -484,11 +491,17 @@ int FfmpegCamera::ReopenFfmpeg() { Debug(2, "ReopenFfmpeg called."); +#if THREAD mCanCapture = false; - if (pthread_create( &mReopenThread, NULL, ReopenFfmpegThreadCallback, (void*) this) != 0){ + if ( pthread_create( &mReopenThread, NULL, ReopenFfmpegThreadCallback, (void*) this) != 0 ) { // Log a fatal error and exit the process. Fatal( "ReopenFfmpeg failed to create worker thread." ); } +#else + CloseFfmpeg(); + OpenFfmpeg(); + +#endif return 0; } @@ -499,8 +512,14 @@ int FfmpegCamera::CloseFfmpeg() { mCanCapture = false; - av_frame_free( &mFrame ); - av_frame_free( &mRawFrame ); + if ( mFrame ) { + av_frame_free( &mFrame ); + mFrame = NULL; + } + if ( mRawFrame ) { + av_frame_free( &mRawFrame ); + mRawFrame = NULL; + } #if HAVE_LIBSWSCALE if ( mConvertContext ) { @@ -511,12 +530,12 @@ int FfmpegCamera::CloseFfmpeg() { if ( mVideoCodecContext ) { avcodec_close(mVideoCodecContext); - av_free(mVideoCodecContext); + //av_free(mVideoCodecContext); mVideoCodecContext = NULL; // Freed by av_close_input_file } if ( mAudioCodecContext ) { avcodec_close(mAudioCodecContext); - av_free(mAudioCodecContext); + //av_free(mAudioCodecContext); mAudioCodecContext = NULL; // Freed by av_close_input_file } @@ -533,11 +552,12 @@ int FfmpegCamera::CloseFfmpeg() { } int FfmpegCamera::FfmpegInterruptCallback(void *ctx) { + Debug(3,"FfmpegInteruptCallback"); FfmpegCamera* camera = reinterpret_cast(ctx); if ( camera->mIsOpening ) { int now = time(NULL); if ( (now - camera->mOpenStart) > config.ffmpeg_open_timeout ) { - Error ( "Open video took more than %d seconds.", config.ffmpeg_open_timeout ); + Error( "Open video took more than %d seconds.", config.ffmpeg_open_timeout ); return 1; } } @@ -546,11 +566,12 @@ int FfmpegCamera::FfmpegInterruptCallback(void *ctx) { } void *FfmpegCamera::ReopenFfmpegThreadCallback(void *ctx){ - if (ctx == NULL) return NULL; + Debug(3,"FfmpegReopenThreadtCallback"); + if ( ctx == NULL ) return NULL; FfmpegCamera* camera = reinterpret_cast(ctx); - while (1){ + while (1) { // Close current stream. camera->CloseFfmpeg(); diff --git a/src/zm_logger.cpp b/src/zm_logger.cpp index 4a4756f4c..909aeed5e 100644 --- a/src/zm_logger.cpp +++ b/src/zm_logger.cpp @@ -112,9 +112,16 @@ Logger::Logger() : Logger::~Logger() { terminate(); + smCodes.clear(); + smSyslogPriorities.clear(); +#if 0 for ( StringMap::iterator itr = smCodes.begin(); itr != smCodes.end(); itr ++ ) { smCodes.erase( itr ); } + for ( IntMap::iterator itr = smSyslogPriorities.begin(); itr != smSyslogPriorities.end(); itr ++ ) { + smSyslogPriorities.erase(itr); + } +#endif } void Logger::initialise( const std::string &id, const Options &options ) { @@ -417,124 +424,128 @@ void Logger::closeSyslog() { } void Logger::logPrint( bool hex, const char * const filepath, const int line, const int level, const char *fstring, ... ) { - if ( level <= mEffectiveLevel ) { - char timeString[64]; - char logString[8192]; - va_list argPtr; - struct timeval timeVal; + if ( level > mEffectiveLevel ) + return; + char timeString[64]; + char logString[8192]; + va_list argPtr; + struct timeval timeVal; - char *filecopy = strdup(filepath); - const char * const file = basename(filecopy); - const char *classString = smCodes[level].c_str(); + char *filecopy = strdup(filepath); + const char * const file = basename(filecopy); + const char *classString = smCodes[level].c_str(); - if ( level < PANIC || level > DEBUG9 ) - Panic( "Invalid logger level %d", level ); + if ( level < PANIC || level > DEBUG9 ) + Panic( "Invalid logger level %d", level ); - gettimeofday( &timeVal, NULL ); + gettimeofday( &timeVal, NULL ); #if 0 - if ( logRuntime ) { - static struct timeval logStart; + if ( logRuntime ) { + static struct timeval logStart; - subtractTime( &timeVal, &logStart ); + subtractTime( &timeVal, &logStart ); - snprintf( timeString, sizeof(timeString), "%ld.%03ld", timeVal.tv_sec, timeVal.tv_usec/1000 ); - } else { + snprintf( timeString, sizeof(timeString), "%ld.%03ld", timeVal.tv_sec, timeVal.tv_usec/1000 ); + } else { #endif - char *timePtr = timeString; - timePtr += strftime( timePtr, sizeof(timeString), "%x %H:%M:%S", localtime(&timeVal.tv_sec) ); - snprintf( timePtr, sizeof(timeString)-(timePtr-timeString), ".%06ld", timeVal.tv_usec ); + char *timePtr = timeString; + timePtr += strftime( timePtr, sizeof(timeString), "%x %H:%M:%S", localtime(&timeVal.tv_sec) ); + snprintf( timePtr, sizeof(timeString)-(timePtr-timeString), ".%06ld", timeVal.tv_usec ); #if 0 - } + } #endif - pid_t tid; + pid_t tid; #ifdef __FreeBSD__ - long lwpid; - thr_self(&lwpid); - tid = lwpid; + long lwpid; + thr_self(&lwpid); + tid = lwpid; - if (tid < 0 ) // Thread/Process id + if (tid < 0 ) // Thread/Process id #else #ifdef HAVE_SYSCALL #ifdef __FreeBSD_kernel__ - if ( (syscall(SYS_thr_self, &tid)) < 0 ) // Thread/Process id + if ( (syscall(SYS_thr_self, &tid)) < 0 ) // Thread/Process id # else - // SOLARIS doesn't have SYS_gettid; don't assume + // SOLARIS doesn't have SYS_gettid; don't assume #ifdef SYS_gettid - if ( (tid = syscall(SYS_gettid)) < 0 ) // Thread/Process id + if ( (tid = syscall(SYS_gettid)) < 0 ) // Thread/Process id #endif // SYS_gettid #endif #endif // HAVE_SYSCALL #endif - tid = getpid(); // Process id + tid = getpid(); // Process id - char *logPtr = logString; - logPtr += snprintf( logPtr, sizeof(logString), "%s %s[%d].%s-%s/%d [", - timeString, - mId.c_str(), - tid, - classString, - file, - line - ); - char *syslogStart = logPtr; + char *logPtr = logString; + logPtr += snprintf( logPtr, sizeof(logString), "%s %s[%d].%s-%s/%d [", + timeString, + mId.c_str(), + tid, + classString, + file, + line + ); + char *syslogStart = logPtr; - va_start( argPtr, fstring ); - if ( hex ) { - unsigned char *data = va_arg( argPtr, unsigned char * ); - int len = va_arg( argPtr, int ); - int i; - logPtr += snprintf( logPtr, sizeof(logString)-(logPtr-logString), "%d:", len ); - for ( i = 0; i < len; i++ ) { - logPtr += snprintf( logPtr, sizeof(logString)-(logPtr-logString), " %02x", data[i] ); - } - } else { - logPtr += vsnprintf( logPtr, sizeof(logString)-(logPtr-logString), fstring, argPtr ); + va_start( argPtr, fstring ); + if ( hex ) { + unsigned char *data = va_arg( argPtr, unsigned char * ); + int len = va_arg( argPtr, int ); + int i; + logPtr += snprintf( logPtr, sizeof(logString)-(logPtr-logString), "%d:", len ); + for ( i = 0; i < len; i++ ) { + logPtr += snprintf( logPtr, sizeof(logString)-(logPtr-logString), " %02x", data[i] ); } - va_end(argPtr); - char *syslogEnd = logPtr; - strncpy( logPtr, "]\n", sizeof(logString)-(logPtr-logString) ); + } else { + logPtr += vsnprintf( logPtr, sizeof(logString)-(logPtr-logString), fstring, argPtr ); + } + va_end(argPtr); + char *syslogEnd = logPtr; + strncpy( logPtr, "]\n", sizeof(logString)-(logPtr-logString) ); - if ( level <= mTermLevel ) { - printf( "%s", logString ); - fflush( stdout ); - } - if ( level <= mFileLevel ) { - fprintf( mLogFileFP, "%s", logString ); + if ( level <= mTermLevel ) { + puts( logString ); + fflush( stdout ); + } + if ( level <= mFileLevel ) { + if ( mLogFileFP ) { + fputs( logString, mLogFileFP ); if ( mFlush ) fflush( mLogFileFP ); + } else { + puts("Logging to file, but file not open\n"); } - *syslogEnd = '\0'; - if ( level <= mDatabaseLevel ) { - char sql[ZM_SQL_MED_BUFSIZ]; - char escapedString[(strlen(syslogStart)*2)+1]; + } + *syslogEnd = '\0'; + if ( level <= mDatabaseLevel ) { + char sql[ZM_SQL_MED_BUFSIZ]; + char escapedString[(strlen(syslogStart)*2)+1]; - mysql_real_escape_string( &dbconn, escapedString, syslogStart, strlen(syslogStart) ); + mysql_real_escape_string( &dbconn, escapedString, syslogStart, strlen(syslogStart) ); - snprintf( sql, sizeof(sql), "insert into Logs ( TimeKey, Component, ServerId, Pid, Level, Code, Message, File, Line ) values ( %ld.%06ld, '%s', %d, %d, %d, '%s', '%s', '%s', %d )", timeVal.tv_sec, timeVal.tv_usec, mId.c_str(), staticConfig.SERVER_ID, tid, level, classString, escapedString, file, line ); - if ( mysql_query( &dbconn, sql ) ) { - Level tempDatabaseLevel = mDatabaseLevel; - databaseLevel( NOLOG ); - Error( "Can't insert log entry: sql(%s) error(%s)", sql, mysql_error( &dbconn ) ); - databaseLevel(tempDatabaseLevel); - } - } - if ( level <= mSyslogLevel ) { - int priority = smSyslogPriorities[level]; - //priority |= LOG_DAEMON; - syslog( priority, "%s [%s] [%s]", classString, mId.c_str(), syslogStart ); + snprintf( sql, sizeof(sql), "insert into Logs ( TimeKey, Component, ServerId, Pid, Level, Code, Message, File, Line ) values ( %ld.%06ld, '%s', %d, %d, %d, '%s', '%s', '%s', %d )", timeVal.tv_sec, timeVal.tv_usec, mId.c_str(), staticConfig.SERVER_ID, tid, level, classString, escapedString, file, line ); + if ( mysql_query( &dbconn, sql ) ) { + Level tempDatabaseLevel = mDatabaseLevel; + databaseLevel( NOLOG ); + Error( "Can't insert log entry: sql(%s) error(%s)", sql, mysql_error( &dbconn ) ); + databaseLevel(tempDatabaseLevel); } + } + if ( level <= mSyslogLevel ) { + int priority = smSyslogPriorities[level]; + //priority |= LOG_DAEMON; + syslog( priority, "%s [%s] [%s]", classString, mId.c_str(), syslogStart ); + } - free(filecopy); - if ( level <= FATAL ) { - logTerm(); - zmDbClose(); - if ( level <= PANIC ) - abort(); - exit( -1 ); - } + free(filecopy); + if ( level <= FATAL ) { + logTerm(); + zmDbClose(); + if ( level <= PANIC ) + abort(); + exit( -1 ); } } @@ -547,6 +558,8 @@ void logInit( const char *name, const Logger::Options &options ) { } void logTerm() { - if ( Logger::smInstance ) + if ( Logger::smInstance ) { delete Logger::smInstance; + Logger::smInstance = NULL; + } } diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 88683a698..698e164e3 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -396,8 +396,10 @@ Monitor::Monitor( if ( purpose == CAPTURE ) { - this->connect(); - if ( ! mem_ptr ) exit(-1); + if ( ! this->connect() ) { + Error("unable to connect, but doing capture"); + exit(-1); + } memset( mem_ptr, 0, mem_size ); shared_data->size = sizeof(SharedData); shared_data->active = enabled; @@ -486,38 +488,53 @@ bool Monitor::connect() { #if ZM_MEM_MAPPED snprintf( mem_file, sizeof(mem_file), "%s/zm.mmap.%d", staticConfig.PATH_MAP.c_str(), id ); map_fd = open( mem_file, O_RDWR|O_CREAT, (mode_t)0600 ); - if ( map_fd < 0 ) + if ( map_fd < 0 ) { Fatal( "Can't open memory map file %s, probably not enough space free: %s", mem_file, strerror(errno) ); + } else { + Debug(3, "Success opening mmap file at (%s)", mem_file ); + } struct stat map_stat; if ( fstat( map_fd, &map_stat ) < 0 ) Fatal( "Can't stat memory map file %s: %s, is the zmc process for this monitor running?", mem_file, strerror(errno) ); - if ( map_stat.st_size != mem_size && purpose == CAPTURE ) { - // Allocate the size - if ( ftruncate( map_fd, mem_size ) < 0 ) { - Fatal( "Can't extend memory map file %s to %d bytes: %s", mem_file, mem_size, strerror(errno) ); - } - } else if ( map_stat.st_size == 0 ) { - Error( "Got empty memory map file size %ld, is the zmc process for this monitor running?", map_stat.st_size, mem_size ); - return false; - } else if ( map_stat.st_size != mem_size ) { - Error( "Got unexpected memory map file size %ld, expected %d", map_stat.st_size, mem_size ); - return false; - } else { -#ifdef MAP_LOCKED - mem_ptr = (unsigned char *)mmap( NULL, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, map_fd, 0 ); - if ( mem_ptr == MAP_FAILED ) { - if ( errno == EAGAIN ) { - Debug( 1, "Unable to map file %s (%d bytes) to locked memory, trying unlocked", mem_file, mem_size ); -#endif - mem_ptr = (unsigned char *)mmap( NULL, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, 0 ); - Debug( 1, "Mapped file %s (%d bytes) to locked memory, unlocked", mem_file, mem_size ); -#ifdef MAP_LOCKED + + if ( map_stat.st_size != mem_size ) { + if ( purpose == CAPTURE ) { + // Allocate the size + if ( ftruncate( map_fd, mem_size ) < 0 ) { + Fatal( "Can't extend memory map file %s to %d bytes: %s", mem_file, mem_size, strerror(errno) ); } + } else if ( map_stat.st_size == 0 ) { + Error( "Got empty memory map file size %ld, is the zmc process for this monitor running?", map_stat.st_size, mem_size ); + return false; + } else { + Error( "Got unexpected memory map file size %ld, expected %d", map_stat.st_size, mem_size ); + return false; } + } + + Debug(3, "MMap file size is %ld", map_stat.st_size ); +#ifdef MAP_LOCKED + mem_ptr = (unsigned char *)mmap( NULL, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, map_fd, 0 ); + if ( mem_ptr == MAP_FAILED ) { + if ( errno == EAGAIN ) { + Debug( 1, "Unable to map file %s (%d bytes) to locked memory, trying unlocked", mem_file, mem_size ); + #endif - if ( mem_ptr == MAP_FAILED ) - Fatal( "Can't map file %s (%d bytes) to memory: %s(%d)", mem_file, mem_size, strerror(errno), errno ); + mem_ptr = (unsigned char *)mmap( NULL, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, 0 ); + Debug( 1, "Mapped file %s (%d bytes) to unlocked memory", mem_file, mem_size ); +#ifdef MAP_LOCKED + } else { + Error( "Unable to map file %s (%d bytes) to locked memory (%s)", mem_file, mem_size , strerror(errno) ); + } + } +#endif + if ( mem_ptr == MAP_FAILED ) + Fatal( "Can't map file %s (%d bytes) to memory: %s(%d)", mem_file, mem_size, strerror(errno), errno ); + if ( mem_ptr == NULL ) { + Error( "mmap gave a null address:" ); + } else { + Debug(3, "mmapped to %p", mem_ptr ); } #else // ZM_MEM_MAPPED shm_id = shmget( (config.shm_key&0xffff0000)|id, mem_size, IPC_CREAT|0700 ); @@ -536,26 +553,28 @@ bool Monitor::connect() { 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))); + - if(((unsigned long)shared_images % 64) != 0) { + 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 ( purpose == CAPTURE ) { + 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 ( (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 @@ -567,7 +586,7 @@ bool Monitor::connect() { pre_event_buffer[i].image = new Image( width, height, camera->Colours(), camera->SubpixelOrder()); } } - +Debug(3, "Success connecting"); return true; } diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index d87886002..53ee3aef6 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -228,11 +228,11 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, audio_output_context = avcodec_alloc_context3( audio_output_codec ); // Copy params from inputstream to context ret = avcodec_parameters_to_context( audio_output_context, audio_input_stream->codecpar ); - if (ret < 0) { + if ( ret < 0 ) { Error("Unable to copy audio params to context %s\n", av_make_error_string(ret).c_str()); } ret = avcodec_parameters_from_context( audio_output_stream->codecpar, audio_output_context ); - if (ret < 0) { + if ( ret < 0 ) { Error("Unable to copy audio params to stream %s\n", av_make_error_string(ret).c_str()); } @@ -324,11 +324,13 @@ VideoStore::~VideoStore(){ while ( 1 ) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) +#if 0 ret = avcodec_send_frame( audio_output_context, NULL ); if ( ret < 0 ) { Error("Error sending flush to encoder (%d) (%s)", ret, av_err2str( ret )); break; } +#endif ret = avcodec_receive_packet( audio_output_context, &pkt ); if ( ret < 0 ) { Error("ERror encoding audio while flushing (%d) (%s)", ret, av_err2str( ret )); @@ -377,18 +379,24 @@ VideoStore::~VideoStore(){ // What if we were only doing audio recording? if ( video_output_stream ) { avcodec_close(video_output_context); - //av_free(video_output_context); video_output_context = NULL; } if (audio_output_stream) { avcodec_close(audio_output_context); - //av_free(audio_output_context); audio_output_context = NULL; #ifdef HAVE_LIBAVRESAMPLE if ( resample_context ) { avresample_close( resample_context ); avresample_free( &resample_context ); } + if ( input_frame ) { + av_frame_free( &input_frame ); + input_frame = NULL; + } + if ( output_frame ) { + av_frame_free( &output_frame ); + output_frame = NULL; + } #endif } @@ -404,15 +412,6 @@ VideoStore::~VideoStore(){ /* free the stream */ avformat_free_context(oc); - - if ( input_frame ) { - av_frame_free( &input_frame ); - input_frame = NULL; - } - if ( output_frame ) { - av_frame_free( &output_frame ); - output_frame = NULL; - } } bool VideoStore::setup_resampler() { @@ -803,8 +802,8 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) { * If we are at the end of the file, pass an empty packet to the decoder * to flush it. */ - if ((ret = avcodec_decode_audio4(audio_input_context, input_frame, - &data_present, ipkt)) < 0) { + if ( (ret = avcodec_decode_audio4(audio_input_context, input_frame, + &data_present, ipkt)) < 0 ) { Error( "Could not decode frame (error '%s')\n", av_make_error_string(ret).c_str()); dumpPacket( ipkt ); @@ -829,8 +828,10 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) { input_frame->nb_samples )) < 0 ) { Error( "Could not resample frame (error '%s')\n", av_make_error_string(ret).c_str()); + av_frame_unref( input_frame ); return 0; } + av_frame_unref( input_frame ); if ( avresample_available( resample_context ) < output_frame->nb_samples ) { Debug(1, "No enough samples yet"); @@ -864,15 +865,22 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) { zm_av_packet_unref(&opkt); return 0; } + av_frame_unref( output_frame ); if (( ret = avcodec_receive_packet( audio_output_context, &opkt )) < 0 ) { + if ( EAGAIN == ret ) { + // THe codec may need more samples than it has, perfectly valid + Debug( 3, "Could not recieve packet (error '%s')", + av_make_error_string(ret).c_str()); + } else { Error( "Could not recieve packet (error '%s')", av_make_error_string(ret).c_str()); + } zm_av_packet_unref(&opkt); + av_frame_unref( input_frame ); + av_frame_unref( output_frame ); return 0; } - av_frame_unref( input_frame ); - av_frame_unref( output_frame ); #else if (( ret = avcodec_encode_audio2( audio_output_context, &opkt, output_frame, &data_present )) < 0) { Error( "Could not encode frame (error '%s')", From 83f8a240d5c67f8a09bc5a19b91dbebd2ae8d063 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 11 Aug 2017 12:20:46 -0400 Subject: [PATCH 049/114] blah --- src/zm_monitor.cpp | 2 +- src/zm_monitorstream.cpp | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 698e164e3..20e550ebc 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -560,7 +560,7 @@ 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))); } - if ( purpose == CAPTURE ) { + if ( purpose != ANALYSIS ) { 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++ ) { diff --git a/src/zm_monitorstream.cpp b/src/zm_monitorstream.cpp index aaa5e8289..6b1614d76 100644 --- a/src/zm_monitorstream.cpp +++ b/src/zm_monitorstream.cpp @@ -484,7 +484,10 @@ void MonitorStream::runStream() { openComms(); - checkInitialised(); + if ( ! checkInitialised() ) { + Error("Not initialized"); + return; + } updateFrameRate( monitor->GetFPS() ); From 014951bf78f85f13a013d11efdbf3d12f32269d5 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 11 Aug 2017 13:00:18 -0400 Subject: [PATCH 050/114] fix connect --- src/zm_monitor.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 20e550ebc..aff9c3df0 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -560,7 +560,6 @@ 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))); } - if ( purpose != ANALYSIS ) { 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++ ) { @@ -574,7 +573,6 @@ bool Monitor::connect() { 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 From 4aa15702e793592c80fad33336faa6e456488c4b Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Fri, 11 Aug 2017 12:33:39 -0500 Subject: [PATCH 051/114] Update redhat.rst --- docs/installationguide/redhat.rst | 73 +++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 24 deletions(-) diff --git a/docs/installationguide/redhat.rst b/docs/installationguide/redhat.rst index 587dd3532..d3a8cf49e 100644 --- a/docs/installationguide/redhat.rst +++ b/docs/installationguide/redhat.rst @@ -183,27 +183,18 @@ Finally, you may want to consider editing the rpmfusion repo file under /etc/yum How to Modify the Source Prior to Build *************************************** -Before attempting this part of the instructions, make sure and follow the previous instructions for building one of the unmodified SRPMS from zmrepo. Knowing this part works will assist in troubleshooting should something go wrong. +In the previous section we described how to rebuild an existing ZoneMinder SRPM. The instructions which follow show how to build the ZoneMinder git source tree into an rpm. -These instructions may vary depending on what exactly you want to do. The following example assumes you want to build a development snapshot from the master branch. +Before attempting this part of the instructions, make sure and follow the previous instructions `Build from SRPM`_. Knowing this part works will assist in troubleshooting later should something go wrong. -From the previous instructions, we downloaded a CentOS 7 ZoneMinder SRPM and placed it into ~/rpmbuild/SRPMS. For this example, install it onto your system: +Make sure git and rpmdevtools are installed: :: - rpm -ivh ~/rpmbuild/SRPMS/zoneminder-1.28.1-2.el7.centos.src.rpm + sudo yum install git rpmdevtools -IMPORTANT: This operation must be done with your normal user account. Do *not* perform this command as root. - -Make sure you have git installed: - -:: - - sudo yum install git - - -Now clone the ZoneMinder git repository: +Now clone the ZoneMinder git repository from your home folder: :: @@ -211,32 +202,66 @@ Now clone the ZoneMinder git repository: git clone https://github.com/ZoneMinder/ZoneMinder cd ZoneMinder -This will create a sub-folder called ZoneMinder, which will contain the latest development. +This will create a sub-folder called ZoneMinder, which will contain the latest development source code. -We want to turn this into a tarball, but first we need to figure out what to name it. Look here: +If you have previsouly cloned the ZoneMinder git repo and wish to update it to the most recent, then issue these commands instead: :: - ls ~/rpmbuild/SOURCES - -The tarball from the previsouly installed SRPM should be there. This is the name we will use. For this example, the name is ZoneMinder-1.28.1.tar.gz. From the root folder of the local ZoneMinder git repository, execute the following: + cd ~\ZoneMinder + git pull origin master + +Get the crud submodule tarball: :: - git archive --prefix=ZoneMinder-1.28.1/ -o ~/rpmbuild/SOURCES/zoneminder-1.28.1.tar.gz HEAD + spectool -f -g -R -s 1 ~/ZoneMinder/distros/redhat/zoneminder.spec -Note that we are overwriting the original tarball. If you wish to keep the original tarball then create a copy prior to creating the new tarball. +At this point, you can make changes to the source code. Depending on what you want to do with those changes, you might want to create a new branch first: + +:: + + cd ~\ZoneMinder + git checkout -b mynewbranch + +When using git, you usually want to work out of a branch, rather than master. + +Again, depending on what you want to do with those changes, you may want to commit your changes: + +:: + + cd ~\ZoneMinder + git add . + git commit + +Once you have made your changes, it is time to turn your work into a new tarball, but first we need to look in the rpm specfile: + +:: + + less ~/ZoneMinder/distros/redhat/zoneminder.spec + +Scroll down until you see the Version field. Note the value which will be in the format x.xx.x. Now create the tarball with the following command: + +:: + + cd ~\ZoneMinder + git archive --prefix=ZoneMinder-1.31.1/ -o ~/rpmbuild/SOURCES/zoneminder-1.31.1.tar.gz HEAD + +Replace "1.31.1" with the Version specified in the rpm specfile. From the root of the local ZoneMinder git repo, execute the following: :: + cd ~\ZoneMinder rpmbuild -bs --nodeps distros/redhat/zoneminder.spec -Notice we used the rpm specfile that is part of the latest master branch you just downloaded, rather than the one that may be in your ~/rpmbbuild/SOURCES folder. +This step will create a source rpm and it will tell you where it was saved. For example: -This step will overwrite the SRPM you originally downloaded, so you may want to back it up prior to completing this step. Note that the name of the specfile will vary slightly depending on the target distro. +:: -You should now have a new SRPM under ~/rpmbuild/SRPMS. In our example, the SRPM is called zoneminder-1.28.1-2.el7.centos.src.rpm. Now follow the previous instructions that describe how to use the buildzm script, using ~/rpmbuild/SRPMS/zoneminder-1.28.1-2.el7.centos.src.rpm as the path to your SRPM. + Wrote: /home/abauer/rpmbuild/SRPMS/zoneminder-1.31.1-1.fc26.src.rpm + +Now follow the previous instructions `Build from SRPM`_ which describe how to build that source rpm into an rpm. From 0936dc79bc7e199245f34d61580f860a0d1cdff4 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Fri, 11 Aug 2017 12:37:44 -0500 Subject: [PATCH 052/114] Update redhat.rst --- docs/installationguide/redhat.rst | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/docs/installationguide/redhat.rst b/docs/installationguide/redhat.rst index d3a8cf49e..75158ffa6 100644 --- a/docs/installationguide/redhat.rst +++ b/docs/installationguide/redhat.rst @@ -181,11 +181,9 @@ Copy the newly built ZoneMinder RPMs to the desired system, enable RPM Fusion as Finally, you may want to consider editing the rpmfusion repo file under /etc/yum.repos.d and placing an “exclude=zoneminder*” line into the config file. This will prevent your system from overwriting your manually built RPM with the ZoneMinder RPM found in the repo. -How to Modify the Source Prior to Build -*************************************** -In the previous section we described how to rebuild an existing ZoneMinder SRPM. The instructions which follow show how to build the ZoneMinder git source tree into an rpm. - -Before attempting this part of the instructions, make sure and follow the previous instructions `Build from SRPM`_. Knowing this part works will assist in troubleshooting later should something go wrong. +How to Create Your Own Source RPM +********************************* +In the previous section we described how to rebuild an existing ZoneMinder SRPM. The instructions which follow show how to build the ZoneMinder git source tree into a source rpm, which can be used in the previous section to build an rpm. Make sure git and rpmdevtools are installed: @@ -217,14 +215,12 @@ Get the crud submodule tarball: spectool -f -g -R -s 1 ~/ZoneMinder/distros/redhat/zoneminder.spec -At this point, you can make changes to the source code. Depending on what you want to do with those changes, you might want to create a new branch first: +At this point, you can make changes to the source code. Depending on what you want to do with those changes, you generally want to create a new branch first: :: cd ~\ZoneMinder git checkout -b mynewbranch - -When using git, you usually want to work out of a branch, rather than master. Again, depending on what you want to do with those changes, you may want to commit your changes: @@ -240,14 +236,14 @@ Once you have made your changes, it is time to turn your work into a new tarball less ~/ZoneMinder/distros/redhat/zoneminder.spec -Scroll down until you see the Version field. Note the value which will be in the format x.xx.x. Now create the tarball with the following command: +Scroll down until you see the Version field. Note the value, which will be in the format x.xx.x. Now create the tarball with the following command: :: cd ~\ZoneMinder git archive --prefix=ZoneMinder-1.31.1/ -o ~/rpmbuild/SOURCES/zoneminder-1.31.1.tar.gz HEAD -Replace "1.31.1" with the Version specified in the rpm specfile. +Replace "1.31.1" with the Version shown in the rpm specfile. From the root of the local ZoneMinder git repo, execute the following: @@ -263,5 +259,3 @@ This step will create a source rpm and it will tell you where it was saved. For Wrote: /home/abauer/rpmbuild/SRPMS/zoneminder-1.31.1-1.fc26.src.rpm Now follow the previous instructions `Build from SRPM`_ which describe how to build that source rpm into an rpm. - - From edd66dd0cf277a80bf221b867703707d87cd56d6 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Fri, 11 Aug 2017 12:41:12 -0500 Subject: [PATCH 053/114] Update redhat.rst --- docs/installationguide/redhat.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/installationguide/redhat.rst b/docs/installationguide/redhat.rst index 75158ffa6..93513fe08 100644 --- a/docs/installationguide/redhat.rst +++ b/docs/installationguide/redhat.rst @@ -132,27 +132,27 @@ Your build environment is now set up. Build from SRPM *************** -To continue, you need a ZoneMinder SRPM. If you wish to rebuild a ZoneMinder release, then browse the `RPM Fusion site `_. If instead you wish to rebuild the latest package from our master branch then browse the `Zmrepo site `_. +To continue, you need a ZoneMinder SRPM. If you wish to rebuild a ZoneMinder release, then browse the `RPM Fusion site `_. If instead you wish to rebuild the latest source rpm from our master branch then browse the `Zmrepo site `_. -For this example, I'll use one of the SRPMS from zmrepo: +For this example, I'll use one of the source rpms from zmrepo: :: - wget -P ~/rpmbuild/SRPMS http://zmrepo.zoneminder.com/el/7/SRPMS/zoneminder-1.28.1-2.el7.centos.src.rpm + wget -P ~/rpmbuild/SRPMS http://zmrepo.zoneminder.com/el/7/SRPMS/zoneminder-1.31.1-1.el7.centos.src.rpm Now comes the fun part. To build ZoneMinder, issue the following command: :: - mock -r epel-7-x86_64-rpmfusion_free ~/rpmbuild/SRPMS/zoneminder-1.28.1-2.el7.centos.src.rpm + mock -r epel-7-x86_64-rpmfusion_free ~/rpmbuild/SRPMS/zoneminder-1.31.1-1.el7.centos.src.rpm Want to build ZoneMinder for Fedora, instead of CentOS, from the same host? Once you download the Fedora SRPM, issue the following: :: - mock -r fedora-26-x86_64-rpmfusion_free ~/rpmbuild/SRPMS/zoneminder-1.28.1-1.fc21.src.rpm + mock -r fedora-26-x86_64-rpmfusion_free ~/rpmbuild/SRPMS/zoneminder-1.31.1-1.el7.centos.src.rpm Notice that the mock tool requires the following parameters: From c353d5d17b9fe7d713364883a2f8598c81c95014 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Mon, 14 Aug 2017 08:45:03 -0500 Subject: [PATCH 054/114] Update CMakeLists.txt fix erroneous creation of /etc/zm/conf.d/conf.d during an out-of-source build --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c104998a..834c2a1af 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -801,7 +801,7 @@ endif(ZM_PERL_SEARCH_PATH) # If this is an out-of-source build, copy the files we need to the binary directory if(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)) - file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/conf.d" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/conf.d" PATTERN "*.in" EXCLUDE) + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/conf.d" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}" PATTERN "*.in" EXCLUDE) endif(NOT (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)) # Generate files from the .in files From ecb7df0e8b5df7a2448090cf2d8275066653f53c Mon Sep 17 00:00:00 2001 From: ralimi Date: Mon, 14 Aug 2017 07:30:42 -0700 Subject: [PATCH 055/114] Support SSL for mysql connections (#1965) * Fix install location for config files when building to alternate directory. With the previous code, we ended up with a directory structure like the following: $ find /etc/zm/conf.d/ /etc/zm/conf.d/ /etc/zm/conf.d/01-system-paths.conf /etc/zm/conf.d/conf.d /etc/zm/conf.d/conf.d/README /etc/zm/conf.d/conf.d/02-multiserver.conf * Omitted README file that should have appeared in /etc/zm/conf.d * Fix location for configs when building to alternate directory. * Fix works, but this should go on a branch instead. * Fix works, but this should go on a branch instead. * Fix location for configs when building to alternate directory. With the previous code, we ended up with a directory structure like the following: $ find /etc/zm/conf.d/ /etc/zm/conf.d/ /etc/zm/conf.d/01-system-paths.conf /etc/zm/conf.d/conf.d /etc/zm/conf.d/conf.d/README /etc/zm/conf.d/conf.d/02-multiserver.conf * Remove double quotes. This is a list of paths. * Allow SSL database connection to be secured with SSL. * Fix incorrect variable name * Fix PHP syntax errors * SSL connection parameters must also be passed in API. * Revert fixes to build files; they should not be in this branch. --- INSTALL | 3 +++ cmakecacheimport.sh | 6 ++++++ scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in | 11 ++++++++++- scripts/ZoneMinder/lib/ZoneMinder/Database.pm | 13 ++++++++++++- scripts/ZoneMinder/lib/ZoneMinder/Logger.pm | 11 ++++++++++- src/zm_config.cpp | 6 ++++++ src/zm_config.h.in | 3 +++ src/zm_db.cpp | 2 ++ src/zm_logger.cpp | 2 ++ web/api/app/Config/database.php.default | 3 +++ web/includes/database.php | 7 ++++++- zm.conf.in | 9 +++++++++ 12 files changed, 72 insertions(+), 4 deletions(-) diff --git a/INSTALL b/INSTALL index 3b50f5b62..666105c40 100644 --- a/INSTALL +++ b/INSTALL @@ -45,6 +45,9 @@ Possible configuration options: ZM_DB_NAME Name of ZoneMinder database, default: zm ZM_DB_USER Name of ZoneMinder database user, default: zmuser ZM_DB_PASS Password of ZoneMinder database user, default: zmpass + ZM_DB_SSL_CA_CERT Path to SSL CA certificate, default: empty; SSL not enabled + ZM_DB_SSL_CLIENT_KEY Path to SSL client key, default: empty; SSL not enabled + ZM_DB_SSL_CLIENT_CERT Path to SSL client certificate, default: empty; SSL not enabled ZM_WEB_USER The user apache or the local web server runs on. Leave empty for automatic detection. If that fails, you can use this variable to force ZM_WEB_GROUP The group apache or the local web server runs on, Leave empty to be the same as the web user ZM_DIR_EVENTS Location where events are recorded to, default: ZM_CONTENTDIR/events diff --git a/cmakecacheimport.sh b/cmakecacheimport.sh index 79253f6ad..7bd44f311 100755 --- a/cmakecacheimport.sh +++ b/cmakecacheimport.sh @@ -55,6 +55,9 @@ echo "Database host : $ZM_DB_HOST" echo "Database name : $ZM_DB_NAME" echo "Database user : $ZM_DB_USER" echo "Database password : Not shown" +echo "Database SSL CA Cert : $ZM_DB_SSL_CA_CERT" +echo "Database SSL Client Key : $ZM_DB_SSL_CLIENT_KEY" +echo "Database SSL Client Cert : $ZM_DB_SSL_CLIENT_CERT" CMPATH="CACHE PATH \"Imported by cmakecacheimport.sh\" FORCE" @@ -72,6 +75,9 @@ echo "set(ZM_DB_HOST \"$ZM_DB_HOST\" $CMSTRING)">>zm_conf.cmake echo "set(ZM_DB_NAME \"$ZM_DB_NAME\" $CMSTRING)">>zm_conf.cmake echo "set(ZM_DB_USER \"$ZM_DB_USER\" $CMSTRING)">>zm_conf.cmake echo "set(ZM_DB_PASS \"$ZM_DB_PASS\" $CMSTRING)">>zm_conf.cmake +echo "set(ZM_DB_SSL_CA_CERT \"$ZM_DB_SSL_CA_CERT\" $CMSTRING)">>zm_conf.cmake +echo "set(ZM_DB_SSL_CLIENT_KEY \"$ZM_DB_SSL_CLIENT_KEY\" $CMSTRING)">>zm_conf.cmake +echo "set(ZM_DB_SSL_CLIENT_CERT \"$ZM_DB_SSL_CLIENT_CERT\" $CMSTRING)">>zm_conf.cmake echo "" echo "Wrote zm_conf.cmake" diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in index 60cdce658..d2b444ef4 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in @@ -101,8 +101,17 @@ BEGIN { } else { $socket = ";host=".$Config{ZM_DB_HOST}; } + my $sslOptions = ""; + if ( $Config{ZM_DB_SSL_CA_CERT} ) { + $sslOptions = ';'.join(';', + "mysql_ssl=1", + "mysql_ssl_ca_file=".$Config{ZM_DB_SSL_CA_CERT}, + "mysql_ssl_client_key=".$Config{ZM_DB_SSL_CLIENT_KEY}, + "mysql_ssl_client_cert=".$Config{ZM_DB_SSL_CLIENT_CERT} + ); + } my $dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME} - .$socket + .$socket.$sslOptions , $Config{ZM_DB_USER} , $Config{ZM_DB_PASS} ) or croak( "Can't connect to db" ); diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Database.pm b/scripts/ZoneMinder/lib/ZoneMinder/Database.pm index 19374543e..cf0f488e2 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Database.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Database.pm @@ -90,8 +90,19 @@ sub zmDbConnect { } else { $socket = ";host=".$Config{ZM_DB_HOST}; } + + my $sslOptions = ""; + if ( $Config{ZM_DB_SSL_CA_CERT} ) { + $sslOptions = ';'.join(';', + "mysql_ssl=1", + "mysql_ssl_ca_file=".$Config{ZM_DB_SSL_CA_CERT}, + "mysql_ssl_client_key=".$Config{ZM_DB_SSL_CLIENT_KEY}, + "mysql_ssl_client_cert=".$Config{ZM_DB_SSL_CLIENT_CERT} + ); + } + $dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME} - .$socket . ($options?';'.join(';', map { $_.'='.$$options{$_} } keys %{$options} ) : '' ) + .$socket . $sslOptions . ($options?';'.join(';', map { $_.'='.$$options{$_} } keys %{$options} ) : '' ) , $Config{ZM_DB_USER} , $Config{ZM_DB_PASS} ); diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm index 123033105..27a9fc1a8 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm @@ -434,8 +434,17 @@ sub databaseLevel { } else { $socket = ";host=".$Config{ZM_DB_HOST}; } + my $sslOptions = ""; + if ( $Config{ZM_DB_SSL_CA_CERT} ) { + $sslOptions = ';'.join(';', + "mysql_ssl=1", + "mysql_ssl_ca_file=".$Config{ZM_DB_SSL_CA_CERT}, + "mysql_ssl_client_key=".$Config{ZM_DB_SSL_CLIENT_KEY}, + "mysql_ssl_client_cert=".$Config{ZM_DB_SSL_CLIENT_CERT} + ); + } $this->{dbh} = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME} - .$socket + .$socket.$sslOptions , $Config{ZM_DB_USER} , $Config{ZM_DB_PASS} ); diff --git a/src/zm_config.cpp b/src/zm_config.cpp index 601a4a950..fdbcffe52 100644 --- a/src/zm_config.cpp +++ b/src/zm_config.cpp @@ -150,6 +150,12 @@ void process_configfile( char* configFile) { staticConfig.DB_USER = std::string(val_ptr); else if ( strcasecmp( name_ptr, "ZM_DB_PASS" ) == 0 ) staticConfig.DB_PASS = std::string(val_ptr); + else if ( strcasecmp( name_ptr, "ZM_DB_SSL_CA_CERT" ) == 0 ) + staticConfig.DB_SSL_CA_CERT = std::string(val_ptr); + else if ( strcasecmp( name_ptr, "ZM_DB_SSL_CLIENT_KEY" ) == 0 ) + staticConfig.DB_SSL_CLIENT_KEY = std::string(val_ptr); + else if ( strcasecmp( name_ptr, "ZM_DB_SSL_CLIENT_CERT" ) == 0 ) + staticConfig.DB_SSL_CLIENT_CERT = std::string(val_ptr); else if ( strcasecmp( name_ptr, "ZM_PATH_WEB" ) == 0 ) staticConfig.PATH_WEB = std::string(val_ptr); else if ( strcasecmp( name_ptr, "ZM_SERVER_HOST" ) == 0 ) diff --git a/src/zm_config.h.in b/src/zm_config.h.in index 461e4bb5e..3ecc70d7c 100644 --- a/src/zm_config.h.in +++ b/src/zm_config.h.in @@ -67,6 +67,9 @@ struct StaticConfig std::string DB_NAME; std::string DB_USER; std::string DB_PASS; + std::string DB_SSL_CA_CERT; + std::string DB_SSL_CLIENT_KEY; + std::string DB_SSL_CLIENT_CERT; std::string PATH_WEB; std::string SERVER_NAME; unsigned int SERVER_ID; diff --git a/src/zm_db.cpp b/src/zm_db.cpp index 8eed90569..568f9cd72 100644 --- a/src/zm_db.cpp +++ b/src/zm_db.cpp @@ -37,6 +37,8 @@ void zmDbConnect() my_bool reconnect = 1; if ( mysql_options( &dbconn, MYSQL_OPT_RECONNECT, &reconnect ) ) Fatal( "Can't set database auto reconnect option: %s", mysql_error( &dbconn ) ); + if ( !staticConfig.DB_SSL_CA_CERT.empty() ) + mysql_ssl_set( &dbconn, staticConfig.DB_SSL_CLIENT_KEY.c_str(), staticConfig.DB_SSL_CLIENT_CERT.c_str(), staticConfig.DB_SSL_CA_CERT.c_str(), NULL, NULL ); std::string::size_type colonIndex = staticConfig.DB_HOST.find( ":" ); if ( colonIndex == std::string::npos ) { diff --git a/src/zm_logger.cpp b/src/zm_logger.cpp index ee3a5a8b5..bc0d59c23 100644 --- a/src/zm_logger.cpp +++ b/src/zm_logger.cpp @@ -341,6 +341,8 @@ Logger::Level Logger::databaseLevel( Logger::Level databaseLevel ) { my_bool reconnect = 1; if ( mysql_options( &mDbConnection, MYSQL_OPT_RECONNECT, &reconnect ) ) Fatal( "Can't set database auto reconnect option: %s", mysql_error( &mDbConnection ) ); + if ( !staticConfig.DB_SSL_CA_CERT.empty() ) + mysql_ssl_set( &mDbConnection, staticConfig.DB_SSL_CLIENT_KEY.c_str(), staticConfig.DB_SSL_CLIENT_CERT.c_str(), staticConfig.DB_SSL_CA_CERT.c_str(), NULL, NULL ); std::string::size_type colonIndex = staticConfig.DB_HOST.find( ":" ); if ( colonIndex == std::string::npos ) { if ( !mysql_real_connect( &mDbConnection, staticConfig.DB_HOST.c_str(), staticConfig.DB_USER.c_str(), staticConfig.DB_PASS.c_str(), NULL, 0, NULL, 0 ) ) { diff --git a/web/api/app/Config/database.php.default b/web/api/app/Config/database.php.default index 55f2bc958..c06953ec7 100644 --- a/web/api/app/Config/database.php.default +++ b/web/api/app/Config/database.php.default @@ -70,6 +70,9 @@ class DATABASE_CONFIG { 'login' => ZM_DB_USER, 'password' => ZM_DB_PASS, 'database' => ZM_DB_NAME, + 'ssl_ca' => ZM_DB_SSL_CA_CERT, + 'ssl_key' => ZM_DB_SSL_CLIENT_KEY, + 'ssl_cert' => ZM_DB_SSL_CLIENT_CERT, 'prefix' => '', 'encoding' => 'utf8', ); diff --git a/web/includes/database.php b/web/includes/database.php index dea9e4b8c..bc1242029 100644 --- a/web/includes/database.php +++ b/web/includes/database.php @@ -42,7 +42,12 @@ function dbConnect() { } try { - $dbConn = new PDO( ZM_DB_TYPE . $socket . ';dbname='.ZM_DB_NAME, ZM_DB_USER, ZM_DB_PASS ); + $dbOptions = array( + PDO::MYSQL_ATTR_SSL_CA => ZM_DB_SSL_CA_CERT, + PDO::MYSQL_ATTR_SSL_KEY => ZM_DB_SSL_CLIENT_KEY, + PDO::MYSQL_ATTR_SSL_CERT => ZM_DB_SSL_CLIENT_CERT, + ); + $dbConn = new PDO( ZM_DB_TYPE . $socket . ';dbname='.ZM_DB_NAME, ZM_DB_USER, ZM_DB_PASS, $dbOptions ); $dbConn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); $dbConn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch(PDOException $ex ) { diff --git a/zm.conf.in b/zm.conf.in index bde068104..312c9aeae 100644 --- a/zm.conf.in +++ b/zm.conf.in @@ -49,6 +49,15 @@ ZM_DB_USER=@ZM_DB_USER@ # ZoneMinder database password ZM_DB_PASS=@ZM_DB_PASS@ +# SSL CA certificate for ZoneMinder database +ZM_DB_SSL_CA_CERT=@ZM_DB_SSL_CA_CERT@ + +# SSL client key for ZoneMinder database +ZM_DB_SSL_CLIENT_KEY=@ZM_DB_SSL_CLIENT_KEY@ + +# SSL client cert for ZoneMinder database +ZM_DB_SSL_CLIENT_CERT=@ZM_DB_SSL_CLIENT_CERT@ + # Do NOT set ZM_SERVER_HOST if you are not using Multi-Server # You have been warned # From 0f0ab6170b4bb06d5dd258a11993e9900247e8e8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 14 Aug 2017 11:15:09 -0400 Subject: [PATCH 056/114] Don't decode video until we have received a keyframe. --- src/zm_ffmpeg_camera.cpp | 137 +++++++++++++++++++++------------------ 1 file changed, 74 insertions(+), 63 deletions(-) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 12d3f4d19..f410ba9de 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -165,9 +165,14 @@ int FfmpegCamera::Capture( Image &image ) { Error( "Unable to read packet from stream %d: error %d \"%s\".", packet.stream_index, avResult, errbuf ); return( -1 ); } + + int keyframe = packet.flags & AV_PKT_FLAG_KEY; + if ( keyframe ) + have_video_keyframe = true; + Debug( 5, "Got packet from stream %d dts (%d) pts(%d)", packet.stream_index, packet.pts, packet.dts ); // What about audio stream? Maybe someday we could do sound detection... - if ( packet.stream_index == mVideoStreamId ) { + if ( ( packet.stream_index == mVideoStreamId ) && ( keyframe || have_video_keyframe ) ) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) ret = avcodec_send_packet( mVideoCodecContext, &packet ); if ( ret < 0 ) { @@ -257,6 +262,7 @@ int FfmpegCamera::OpenFfmpeg() { mOpenStart = time(NULL); mIsOpening = true; + have_video_keyframe = false; // Open the input, not necessarily a file #if !LIBAVFORMAT_VERSION_CHECK(53, 2, 0, 4, 0) @@ -614,11 +620,11 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event return( -1 ); } - int key_frame = packet.flags & AV_PKT_FLAG_KEY; + int keyframe = packet.flags & AV_PKT_FLAG_KEY; Debug( 4, "Got packet from stream %d packet pts (%d) dts(%d), key?(%d)", packet.stream_index, packet.pts, packet.dts, - key_frame + keyframe ); //Video recording @@ -725,7 +731,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event // Buffer video packets, since we are not recording. // All audio packets are keyframes, so only if it's a video keyframe if ( packet.stream_index == mVideoStreamId ) { - if ( key_frame ) { + if ( keyframe ) { Debug(3, "Clearing queue"); packetqueue.clearQueue( monitor->GetPreEventCount(), mVideoStreamId ); } @@ -748,81 +754,86 @@ else if ( packet.pts && video_last_pts > packet.pts ) { packetqueue.queuePacket( &packet ); } } else if ( packet.stream_index == mVideoStreamId ) { - if ( key_frame || packetqueue.size() ) // it's a keyframe or we already have something in the queue + if ( keyframe || packetqueue.size() ) // it's a keyframe or we already have something in the queue packetqueue.queuePacket( &packet ); } } // end if recording or not if ( packet.stream_index == mVideoStreamId ) { - if ( videoStore && ( have_video_keyframe || key_frame ) ) { - - //Write the packet to our video store - int ret = videoStore->writeVideoFramePacket( &packet ); - if ( ret < 0 ) { //Less than zero and we skipped a frame - zm_av_packet_unref( &packet ); - return 0; + // only do decode if we have had a keyframe, should save a few cycles. + if ( have_video_keyframe || keyframe ) { + + if ( videoStore ) { + + //Write the packet to our video store + int ret = videoStore->writeVideoFramePacket( &packet ); + if ( ret < 0 ) { //Less than zero and we skipped a frame + zm_av_packet_unref( &packet ); + return 0; + } + have_video_keyframe = true; } - have_video_keyframe = true; - } - Debug(4, "about to decode video" ); - + + Debug(4, "about to decode video" ); + #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - ret = avcodec_send_packet( mVideoCodecContext, &packet ); - if ( ret < 0 ) { - av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); - Error( "Unable to send packet at frame %d: %s, continuing", frameCount, errbuf ); - zm_av_packet_unref( &packet ); - continue; - } - ret = avcodec_receive_frame( mVideoCodecContext, mRawFrame ); - if ( ret < 0 ) { - av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); - Debug( 1, "Unable to send packet at frame %d: %s, continuing", frameCount, errbuf ); - zm_av_packet_unref( &packet ); - continue; - } - frameComplete = 1; -# else - ret = zm_avcodec_decode_video( mVideoCodecContext, mRawFrame, &frameComplete, &packet ); - if ( ret < 0 ) { - av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); - Error( "Unable to decode frame at frame %d: %s, continuing", frameCount, errbuf ); - zm_av_packet_unref( &packet ); - continue; - } -#endif - - Debug( 4, "Decoded video packet at frame %d", frameCount ); - - if ( frameComplete ) { - Debug( 4, "Got frame %d", frameCount ); - - uint8_t* directbuffer; - - /* Request a writeable buffer of the target image */ - directbuffer = image.WriteBuffer(width, height, colours, subpixelorder); - if ( directbuffer == NULL ) { - Error("Failed requesting writeable buffer for the captured image."); + ret = avcodec_send_packet( mVideoCodecContext, &packet ); + if ( ret < 0 ) { + av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); + Error( "Unable to send packet at frame %d: %s, continuing", frameCount, errbuf ); zm_av_packet_unref( &packet ); - return (-1); + continue; } + ret = avcodec_receive_frame( mVideoCodecContext, mRawFrame ); + if ( ret < 0 ) { + av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); + Debug( 1, "Unable to send packet at frame %d: %s, continuing", frameCount, errbuf ); + zm_av_packet_unref( &packet ); + continue; + } + frameComplete = 1; +# else + ret = zm_avcodec_decode_video( mVideoCodecContext, mRawFrame, &frameComplete, &packet ); + if ( ret < 0 ) { + av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); + Error( "Unable to decode frame at frame %d: %s, continuing", frameCount, errbuf ); + zm_av_packet_unref( &packet ); + continue; + } +#endif + + Debug( 4, "Decoded video packet at frame %d", frameCount ); + + if ( frameComplete ) { + Debug( 4, "Got frame %d", frameCount ); + + uint8_t* directbuffer; + + /* Request a writeable buffer of the target image */ + directbuffer = image.WriteBuffer(width, height, colours, subpixelorder); + if ( directbuffer == NULL ) { + Error("Failed requesting writeable buffer for the captured image."); + zm_av_packet_unref( &packet ); + return (-1); + } #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) - av_image_fill_arrays(mFrame->data, mFrame->linesize, directbuffer, imagePixFormat, width, height, 1); + av_image_fill_arrays(mFrame->data, mFrame->linesize, directbuffer, imagePixFormat, width, height, 1); #else - avpicture_fill( (AVPicture *)mFrame, directbuffer, imagePixFormat, width, height); + avpicture_fill( (AVPicture *)mFrame, directbuffer, imagePixFormat, width, height); #endif - if (sws_scale(mConvertContext, mRawFrame->data, mRawFrame->linesize, - 0, mVideoCodecContext->height, mFrame->data, mFrame->linesize) < 0) { - Fatal("Unable to convert raw format %u to target format %u at frame %d", + if (sws_scale(mConvertContext, mRawFrame->data, mRawFrame->linesize, + 0, mVideoCodecContext->height, mFrame->data, mFrame->linesize) < 0) { + Fatal("Unable to convert raw format %u to target format %u at frame %d", mVideoCodecContext->pix_fmt, imagePixFormat, frameCount); - } + } - frameCount++; - } else { - Debug( 3, "Not framecomplete after av_read_frame" ); - } // end if frameComplete + frameCount++; + } else { + Debug( 3, "Not framecomplete after av_read_frame" ); + } // end if frameComplete + } // end if keyframe or have_video_keyframe } else if ( packet.stream_index == mAudioStreamId ) { //FIXME best way to copy all other streams if ( videoStore ) { if ( record_audio ) { From b6965a2c3f05884bb47f65ab2df5321062919504 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 14 Aug 2017 11:38:21 -0400 Subject: [PATCH 057/114] fix spacing/braces --- web/includes/config.php.in | 163 ++++++++++++++++++------------------- 1 file changed, 79 insertions(+), 84 deletions(-) diff --git a/web/includes/config.php.in b/web/includes/config.php.in index 991414a56..40e3d7468 100644 --- a/web/includes/config.php.in +++ b/web/includes/config.php.in @@ -29,13 +29,12 @@ define( "ZM_DIR_TEMP", "@ZM_TMPDIR@" ); $configFile = ZM_CONFIG; $localConfigFile = basename($configFile); -if ( file_exists( $localConfigFile ) && filesize( $localConfigFile ) > 0 ) -{ - if ( php_sapi_name() == 'cli' && empty($_SERVER['REMOTE_ADDR']) ) - print( "Warning, overriding installed $localConfigFile file with local copy\n" ); - else - error_log( "Warning, overriding installed $localConfigFile file with local copy" ); - $configFile = $localConfigFile; +if ( file_exists( $localConfigFile ) && filesize( $localConfigFile ) > 0 ) { + if ( php_sapi_name() == 'cli' && empty($_SERVER['REMOTE_ADDR']) ) + print( "Warning, overriding installed $localConfigFile file with local copy\n" ); + else + error_log( "Warning, overriding installed $localConfigFile file with local copy" ); + $configFile = $localConfigFile; } # Process name, value pairs from the main config file first @@ -45,19 +44,19 @@ $configvals = process_configfile($configFile); # update our config value array with those values $configSubFolder = ZM_CONFIG_SUBDIR; if ( is_dir($configSubFolder) ) { - if ( is_readable($configSubFolder) ) { - foreach ( glob("$configSubFolder/*.conf") as $filename ) { - $configvals = array_replace($configvals, process_configfile($filename) ); - } - } else { - error_log( "WARNING: ZoneMinder configuration subfolder found but is not readable. Check folder permissions on $configSubFolder." ); + if ( is_readable($configSubFolder) ) { + foreach ( glob("$configSubFolder/*.conf") as $filename ) { + $configvals = array_replace($configvals, process_configfile($filename) ); } + } else { + error_log( "WARNING: ZoneMinder configuration subfolder found but is not readable. Check folder permissions on $configSubFolder." ); + } } # Now that our array our finalized, define each key => value # pair in the array as a constant foreach( $configvals as $key => $value) { - define( $key, $value ); + define( $key, $value ); } // @@ -135,91 +134,87 @@ require_once( 'database.php' ); loadConfig(); $GLOBALS['defaultUser'] = array( - "Username" => "admin", - "Password" => "", - "Language" => "", - "Enabled" => 1, - "Stream" => 'View', - "Events" => 'Edit', - "Control" => 'Edit', - "Monitors" => 'Edit', - "Groups" => 'Edit', - "Devices" => 'Edit', - "System" => 'Edit', - "MaxBandwidth" => "", - "MonitorIds" => false + "Username" => "admin", + "Password" => "", + "Language" => "", + "Enabled" => 1, + "Stream" => 'View', + "Events" => 'Edit', + "Control" => 'Edit', + "Monitors" => 'Edit', + "Groups" => 'Edit', + "Devices" => 'Edit', + "System" => 'Edit', + "MaxBandwidth" => "", + "MonitorIds" => false ); -function loadConfig( $defineConsts=true ) -{ - global $config; - global $configCats; - global $dbConn; +function loadConfig( $defineConsts=true ) { + global $config; + global $configCats; + global $dbConn; - $config = array(); - $configCat = array(); + $config = array(); + $configCat = array(); - $result = $dbConn->query( 'select * from Config order by Id asc' ); - if ( !$result ) - echo mysql_error(); - $monitors = array(); - while( $row = dbFetchNext( $result ) ) - { - if ( $defineConsts ) - define( $row['Name'], $row['Value'] ); - $config[$row['Name']] = $row; - if ( !($configCat = &$configCats[$row['Category']]) ) - { - $configCats[$row['Category']] = array(); - $configCat = &$configCats[$row['Category']]; - } - $configCat[$row['Name']] = $row; + $result = $dbConn->query( 'select * from Config order by Id asc' ); + if ( !$result ) + echo mysql_error(); + $monitors = array(); + while( $row = dbFetchNext( $result ) ) { + if ( $defineConsts ) + define( $row['Name'], $row['Value'] ); + $config[$row['Name']] = $row; + if ( !($configCat = &$configCats[$row['Category']]) ) { + $configCats[$row['Category']] = array(); + $configCat = &$configCats[$row['Category']]; } - //print_r( $config ); - //print_r( $configCats ); + $configCat[$row['Name']] = $row; + } + //print_r( $config ); + //print_r( $configCats ); } require_once( 'logger.php' ); // For Human-readability, user ZM_SERVER in zm.conf, and convert it here to a ZM_SERVER_ID if ( ! defined('ZM_SERVER_ID') ) { - if ( defined('ZM_SERVER_NAME') and ZM_SERVER_NAME ) { - $server_id = dbFetchOne('SELECT Id FROM Servers WHERE Name=?', 'Id', array(ZM_SERVER_NAME)); - if ( ! $server_id ) { - Error("Invalid Multi-Server configration detected. ZM_SERVER_NAME set to " . ZM_SERVER_NAME . " in zm.conf, but no corresponding entry found in Servers table."); - } else { - define( 'ZM_SERVER_ID', $server_id ); - } - } else if ( defined('ZM_SERVER_HOST') and ZM_SERVER_HOST ) { - $server_id = dbFetchOne('SELECT Id FROM Servers WHERE Name=?', 'Id', array(ZM_SERVER_HOST)); - if ( ! $server_id ) { - Error("Invalid Multi-Server configration detected. ZM_SERVER_HOST set to " . ZM_SERVER_HOST . " in zm.conf, but no corresponding entry found in Servers table."); - } else { - define( 'ZM_SERVER_ID', $server_id ); - } - } + if ( defined('ZM_SERVER_NAME') and ZM_SERVER_NAME ) { + $server_id = dbFetchOne('SELECT Id FROM Servers WHERE Name=?', 'Id', array(ZM_SERVER_NAME)); + if ( ! $server_id ) { + Error("Invalid Multi-Server configration detected. ZM_SERVER_NAME set to " . ZM_SERVER_NAME . " in zm.conf, but no corresponding entry found in Servers table."); + } else { + define( 'ZM_SERVER_ID', $server_id ); + } + } else if ( defined('ZM_SERVER_HOST') and ZM_SERVER_HOST ) { + $server_id = dbFetchOne('SELECT Id FROM Servers WHERE Name=?', 'Id', array(ZM_SERVER_HOST)); + if ( ! $server_id ) { + Error("Invalid Multi-Server configration detected. ZM_SERVER_HOST set to " . ZM_SERVER_HOST . " in zm.conf, but no corresponding entry found in Servers table."); + } else { + define( 'ZM_SERVER_ID', $server_id ); + } + } } function process_configfile($configFile) { - if ( is_readable( $configFile ) ) { - $configvals = array(); + if ( is_readable( $configFile ) ) { + $configvals = array(); - $cfg = fopen( $configFile, "r") or die("Could not open config file."); - while ( !feof($cfg) ) - { - $str = fgets( $cfg, 256 ); - if ( preg_match( '/^\s*$/', $str )) - continue; - elseif ( preg_match( '/^\s*#/', $str )) - continue; - elseif ( preg_match( '/^\s*([^=\s]+)\s*=\s*(.*?)\s*$/', $str, $matches )) - $configvals[$matches[1]] = $matches[2]; - } - fclose( $cfg ); - return( $configvals ); - } else { - error_log( "WARNING: ZoneMinder configuration file found but is not readable. Check file permissions on $configFile." ); - return( false ); + $cfg = fopen( $configFile, "r") or die("Could not open config file."); + while ( !feof($cfg) ) { + $str = fgets( $cfg, 256 ); + if ( preg_match( '/^\s*$/', $str )) + continue; + elseif ( preg_match( '/^\s*#/', $str )) + continue; + elseif ( preg_match( '/^\s*([^=\s]+)\s*=\s*(.*?)\s*$/', $str, $matches )) + $configvals[$matches[1]] = $matches[2]; } + fclose( $cfg ); + return( $configvals ); + } else { + error_log( "WARNING: ZoneMinder configuration file found but is not readable. Check file permissions on $configFile." ); + return( false ); + } } ?> From adab628af9fac0abe578f07c87c1e3840908c5b3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 14 Aug 2017 18:22:52 -0400 Subject: [PATCH 058/114] fix video speed, various other --- src/zm_ffmpeg_camera.cpp | 4 +- src/zm_videostore.cpp | 89 ++++++++++++++++++++------------------ web/includes/Event.php | 2 +- web/includes/config.php.in | 3 +- web/includes/database.php | 19 +++++--- 5 files changed, 64 insertions(+), 53 deletions(-) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 04eb0a835..d8826f998 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -643,7 +643,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event int keyframe = packet.flags & AV_PKT_FLAG_KEY; - Debug( 4, "Got packet from stream %d packet pts (%d) dts(%d), key?(%d)", + Debug( 4, "Got packet from stream %d packet pts (%u) dts(%u), key?(%d)", packet.stream_index, packet.pts, packet.dts, keyframe ); @@ -794,6 +794,7 @@ else if ( packet.pts && video_last_pts > packet.pts ) { } have_video_keyframe = true; } + } // end if keyframe or have_video_keyframe Debug(4, "about to decode video" ); @@ -854,7 +855,6 @@ else if ( packet.pts && video_last_pts > packet.pts ) { } else { Debug( 3, "Not framecomplete after av_read_frame" ); } // end if frameComplete - } // end if keyframe or have_video_keyframe } else if ( packet.stream_index == mAudioStreamId ) { //FIXME best way to copy all other streams if ( videoStore ) { if ( record_audio ) { diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 53ee3aef6..e8cadc353 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -397,6 +397,10 @@ VideoStore::~VideoStore(){ av_frame_free( &output_frame ); output_frame = NULL; } + if ( converted_input_samples ) { + av_free( converted_input_samples ); + converted_input_samples =NULL; + } #endif } @@ -481,16 +485,6 @@ bool VideoStore::setup_resampler() { audio_output_context->time_base = (AVRational){ 1, audio_output_context->sample_rate }; - - Debug(1, "Audio output bit_rate (%d) sample_rate(%d) channels(%d) fmt(%d) layout(%d) frame_size(%d)", - audio_output_context->bit_rate, - audio_output_context->sample_rate, - audio_output_context->channels, - audio_output_context->sample_fmt, - audio_output_context->channel_layout, - audio_output_context->frame_size - ); - // Now copy them to the output stream audio_output_stream = avformat_new_stream( oc, audio_output_codec ); @@ -624,7 +618,7 @@ bool VideoStore::setup_resampler() { Error("Not built with libavresample library. Cannot do audio conversion to AAC"); return false; #endif -} +} // end bool VideoStore::setup_resampler() void VideoStore::dumpPacket( AVPacket *pkt ){ @@ -650,14 +644,20 @@ int VideoStore::writeVideoFramePacket( AVPacket *ipkt ) { opkt.dts = video_next_dts; int duration; - if ( video_last_pts && ( ipkt->duration == AV_NOPTS_VALUE || ! ipkt->duration ) ) { + if ( ! video_last_pts ) { + duration = 0; + } else { duration = av_rescale_q( ipkt->pts - video_last_pts, video_input_stream->time_base, video_output_stream->time_base); + opkt.duration = 0; + } + +//#if ( 0 && video_last_pts && ( ipkt->duration == AV_NOPTS_VALUE || ! ipkt->duration ) ) { // Video packets don't really have a duration. Audio does. //opkt.duration = av_rescale_q(duration, video_input_stream->time_base, video_output_stream->time_base); - opkt.duration = 0; - } else { - duration = opkt.duration = av_rescale_q(ipkt->duration, video_input_stream->time_base, video_output_stream->time_base); - } + //opkt.duration = 0; + //} else { + //duration = opkt.duration = av_rescale_q(ipkt->duration, video_input_stream->time_base, video_output_stream->time_base); + //} video_last_pts = ipkt->pts; video_last_dts = ipkt->dts; @@ -745,7 +745,7 @@ int VideoStore::writeVideoFramePacket( AVPacket *ipkt ) { } else { - video_next_dts = opkt.dts + duration; // Unsure if av_interleaved_write_frame() clobbers opkt.dts when out of order, so storing in advance + video_next_dts = opkt.dts + duration; video_next_pts = opkt.pts + duration; ret = av_interleaved_write_frame(oc, &opkt); if ( ret < 0 ) { @@ -774,6 +774,7 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) { } if ( audio_output_codec ) { + Debug(3, "Have audio codec"); #ifdef HAVE_LIBAVRESAMPLE #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) @@ -788,12 +789,11 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) { Error("avcodec_receive_frame fail %s", av_make_error_string(ret).c_str()); return 0; } - Debug(2, "Frame: samples(%d), format(%d), sample_rate(%d), channel layout(%d) refd(%d)", + Debug(2, "Input Frame: samples(%d), format(%d), sample_rate(%d), channel layout(%d)", input_frame->nb_samples, input_frame->format, input_frame->sample_rate, - input_frame->channel_layout, - audio_output_context->refcounted_frames + input_frame->channel_layout ); #else /** @@ -815,8 +815,7 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) { return 0; } #endif - int frame_size = input_frame->nb_samples; - Debug(4, "Frame size: %d", frame_size ); + int frame_size = output_frame->nb_samples; // Resample the input into the audioSampleBuffer until we proceed the whole decoded data if ( (ret = avresample_convert( resample_context, @@ -833,31 +832,29 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) { } av_frame_unref( input_frame ); - if ( avresample_available( resample_context ) < output_frame->nb_samples ) { - Debug(1, "No enough samples yet"); + int samples_available = avresample_available( resample_context ); + + if ( samples_available < frame_size ) { + Debug(1, "Not enough samples yet (%d)", samples_available); return 0; } + Debug(3, "Output_frame samples (%d)", output_frame->nb_samples ); // Read a frame audio data from the resample fifo - if ( avresample_read( resample_context, output_frame->data, output_frame->nb_samples ) != output_frame->nb_samples ) { + if ( avresample_read( resample_context, output_frame->data, frame_size ) != frame_size ) { Warning( "Error reading resampled audio: " ); return 0; } + Debug(2, "Frame: samples(%d), format(%d), sample_rate(%d), channel layout(%d)", + output_frame->nb_samples, + output_frame->format, + output_frame->sample_rate, + output_frame->channel_layout + ); av_init_packet(&opkt); Debug(5, "after init packet" ); - /** Set a timestamp based on the sample rate for the container. */ - //output_frame->pts = av_rescale_q( opkt.pts, audio_output_context->time_base, audio_output_stream->time_base ); - - // convert the packet to the codec timebase from the stream timebase - //Debug(3, "output_frame->pts(%d) best effort(%d)", output_frame->pts, - //av_frame_get_best_effort_timestamp(output_frame) - //); - /** - * Encode the audio frame and store it in the temporary packet. - * The output audio stream encoder is used to do this. - */ #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) if (( ret = avcodec_send_frame( audio_output_context, output_frame ) ) < 0 ) { Error( "Could not send frame (error '%s')", @@ -865,9 +862,10 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) { zm_av_packet_unref(&opkt); return 0; } - av_frame_unref( output_frame ); - if (( ret = avcodec_receive_packet( audio_output_context, &opkt )) < 0 ) { + //av_frame_unref( output_frame ); + + if ( ( ret = avcodec_receive_packet( audio_output_context, &opkt ) ) < 0 ) { if ( EAGAIN == ret ) { // THe codec may need more samples than it has, perfectly valid Debug( 3, "Could not recieve packet (error '%s')", @@ -878,7 +876,7 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) { } zm_av_packet_unref(&opkt); av_frame_unref( input_frame ); - av_frame_unref( output_frame ); + //av_frame_unref( output_frame ); return 0; } #else @@ -928,9 +926,8 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) { } #else opkt.pts = audio_next_pts; -#endif - opkt.dts = audio_next_dts; +#endif #if 0 if ( ipkt->dts == AV_NOPTS_VALUE ) { @@ -955,14 +952,20 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) { } } #endif - audio_last_dts = ipkt->dts; +//audio_last_dts = ipkt->dts; if ( opkt.dts > opkt.pts ) { Debug(1,"opkt.dts(%d) must be <= opkt.pts(%d). Decompression must happen before presentation.", opkt.dts, opkt.pts ); opkt.dts = opkt.pts; } // I wonder if we could just use duration instead of all the hoop jumping above? - opkt.duration = av_rescale_q(ipkt->duration, audio_input_stream->time_base, audio_output_stream->time_base); + // + if ( output_frame ) { + opkt.duration = output_frame->nb_samples; + } else { + opkt.duration = ipkt->duration; + } + //opkt.duration = av_rescale_q(ipkt->duration, audio_input_stream->time_base, audio_output_stream->time_base); Debug( 2, "opkt.pts (%d), opkt.dts(%d) opkt.duration = (%d)", opkt.pts, opkt.dts, opkt.duration ); // pkt.pos: byte position in stream, -1 if unknown diff --git a/web/includes/Event.php b/web/includes/Event.php index ebc0c61f8..7bef5498f 100644 --- a/web/includes/Event.php +++ b/web/includes/Event.php @@ -202,7 +202,7 @@ class Event { // frame is an array representing the db row for a frame. function getImageSrc( $frame, $scale=SCALE_BASE, $captureOnly=false, $overwrite=false ) { - $Storage = new Storage( isset($this->{'StorageId'}) ? $this->{'StorageId'} : NULL ); + $Storage = new Storage( isset($this->{'StorageId'}) ? $this->{'StorageId'} : NULL ); $Event = $this; $eventPath = $Event->Path(); diff --git a/web/includes/config.php.in b/web/includes/config.php.in index 991414a56..9f71950c5 100644 --- a/web/includes/config.php.in +++ b/web/includes/config.php.in @@ -211,8 +211,9 @@ function process_configfile($configFile) { continue; elseif ( preg_match( '/^\s*#/', $str )) continue; - elseif ( preg_match( '/^\s*([^=\s]+)\s*=\s*(.*?)\s*$/', $str, $matches )) + elseif ( preg_match( '/^\s*([^=\s]+)\s*=\s*(.*?)\s*$/', $str, $matches )) { $configvals[$matches[1]] = $matches[2]; + } } fclose( $cfg ); return( $configvals ); diff --git a/web/includes/database.php b/web/includes/database.php index bc1242029..fa45decf3 100644 --- a/web/includes/database.php +++ b/web/includes/database.php @@ -42,16 +42,23 @@ function dbConnect() { } try { - $dbOptions = array( - PDO::MYSQL_ATTR_SSL_CA => ZM_DB_SSL_CA_CERT, - PDO::MYSQL_ATTR_SSL_KEY => ZM_DB_SSL_CLIENT_KEY, - PDO::MYSQL_ATTR_SSL_CERT => ZM_DB_SSL_CLIENT_CERT, - ); - $dbConn = new PDO( ZM_DB_TYPE . $socket . ';dbname='.ZM_DB_NAME, ZM_DB_USER, ZM_DB_PASS, $dbOptions ); + + $dbOptions = null; + if ( defined( 'ZM_DB_SSL_CA_CERT' ) and ZM_DB_SSL_CA_CERT ) { + $dbOptions = array( + PDO::MYSQL_ATTR_SSL_CA => ZM_DB_SSL_CA_CERT, + PDO::MYSQL_ATTR_SSL_KEY => ZM_DB_SSL_CLIENT_KEY, + PDO::MYSQL_ATTR_SSL_CERT => ZM_DB_SSL_CLIENT_CERT, + ); + $dbConn = new PDO( ZM_DB_TYPE . $socket . ';dbname='.ZM_DB_NAME, ZM_DB_USER, ZM_DB_PASS, $dbOptions ); + } else { + $dbConn = new PDO( ZM_DB_TYPE . $socket . ';dbname='.ZM_DB_NAME, ZM_DB_USER, ZM_DB_PASS ); + } $dbConn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); $dbConn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch(PDOException $ex ) { echo "Unable to connect to ZM db." . $ex->getMessage(); + error_log("Unable to connect to ZM DB " . $ex->getMessage() ); $dbConn = null; } } From ae579c96495b0b517966ef228bad56e64b2b9b5f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 15 Aug 2017 12:16:29 -0400 Subject: [PATCH 059/114] potentially fix a crash when camera sends aac --- src/zm_videostore.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index e8cadc353..c51740028 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -186,6 +186,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, } } + converted_input_samples = NULL; audio_output_codec = NULL; audio_input_context = NULL; audio_output_stream = NULL; @@ -324,16 +325,17 @@ VideoStore::~VideoStore(){ while ( 1 ) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) -#if 0 + // Put encoder into flushing mode ret = avcodec_send_frame( audio_output_context, NULL ); if ( ret < 0 ) { Error("Error sending flush to encoder (%d) (%s)", ret, av_err2str( ret )); break; } -#endif ret = avcodec_receive_packet( audio_output_context, &pkt ); if ( ret < 0 ) { - Error("ERror encoding audio while flushing (%d) (%s)", ret, av_err2str( ret )); + if ( EOF != ret ) { + Error("ERror encoding audio while flushing (%d) (%s)", ret, av_err2str( ret )); + } break; } #else @@ -380,6 +382,7 @@ VideoStore::~VideoStore(){ if ( video_output_stream ) { avcodec_close(video_output_context); video_output_context = NULL; + Debug(4, "Success freeing video_output_context"); } if (audio_output_stream) { avcodec_close(audio_output_context); From 85202a0bfdb291687416413385345091fb10ae31 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 15 Aug 2017 13:06:59 -0400 Subject: [PATCH 060/114] add test for when an event is deleted during audit --- scripts/zmaudit.pl.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/zmaudit.pl.in b/scripts/zmaudit.pl.in index db8ca5933..2d6e97297 100644 --- a/scripts/zmaudit.pl.in +++ b/scripts/zmaudit.pl.in @@ -351,6 +351,10 @@ MAIN: while( $loop ) { if ( ! defined( $fs_events->{$db_event} ) ) { Debug("Event $db_event is not in fs."); my $Event = new ZoneMinder::Event( $db_event ); + if ( ! $Event->Id() ) { + Debug("Event $db_event is no longer in db. Filter probably deleted it while we were auditing."); + next; + } if ( ! $Event->StartTime() ) { Debug("Event $$Event{Id} has no start time. deleting it."); if ( confirm() ) { From 38111e80a5048284ef5037908ae7c39477648c8b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 15 Aug 2017 13:17:51 -0400 Subject: [PATCH 061/114] use AVERROR_EOF instead of EOF --- src/zm_videostore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index c51740028..cafd6ddb2 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -333,7 +333,7 @@ VideoStore::~VideoStore(){ } ret = avcodec_receive_packet( audio_output_context, &pkt ); if ( ret < 0 ) { - if ( EOF != ret ) { + if ( AVERROR_EOF != ret ) { Error("ERror encoding audio while flushing (%d) (%s)", ret, av_err2str( ret )); } break; From 591fdfe68c9a3adb71ccc265945d6e6750257b7a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 15 Aug 2017 13:44:23 -0400 Subject: [PATCH 062/114] fix --- src/zm_ffmpeg_camera.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index d8826f998..3ce3eeaed 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -292,7 +292,7 @@ int FfmpegCamera::OpenFfmpeg() { } else if ( method == "rtpRtspHttp" ) { ret = av_dict_set(&opts, "rtsp_transport", "http", 0); } else { - Warning("Unknown method (%s)", method); + Warning("Unknown method (%s)", method.c_str() ); } if ( ret < 0 ) { From e24a2935d20d63c39587c8ffa45ba28251f66ca5 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 15 Aug 2017 13:49:11 -0400 Subject: [PATCH 063/114] remove unneeded error message --- src/zm_videostore.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index cafd6ddb2..852c3fbf6 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -326,11 +326,7 @@ VideoStore::~VideoStore(){ while ( 1 ) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) // Put encoder into flushing mode - ret = avcodec_send_frame( audio_output_context, NULL ); - if ( ret < 0 ) { - Error("Error sending flush to encoder (%d) (%s)", ret, av_err2str( ret )); - break; - } + avcodec_send_frame( audio_output_context, NULL ); ret = avcodec_receive_packet( audio_output_context, &pkt ); if ( ret < 0 ) { if ( AVERROR_EOF != ret ) { @@ -869,12 +865,12 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) { //av_frame_unref( output_frame ); if ( ( ret = avcodec_receive_packet( audio_output_context, &opkt ) ) < 0 ) { - if ( EAGAIN == ret ) { + if ( AVERROR(EAGAIN) == ret ) { // THe codec may need more samples than it has, perfectly valid Debug( 3, "Could not recieve packet (error '%s')", av_make_error_string(ret).c_str()); } else { - Error( "Could not recieve packet (error '%s')", + Error( "Could not recieve packet (error %d = '%s')", ret, av_make_error_string(ret).c_str()); } zm_av_packet_unref(&opkt); From f573158fbbe4eaa2f717f6f8b726cbf2762b2080 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 15 Aug 2017 19:40:02 -0400 Subject: [PATCH 064/114] fix breakage caused by empty SSL_CERT options --- web/includes/database.php | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/web/includes/database.php b/web/includes/database.php index bc1242029..713621685 100644 --- a/web/includes/database.php +++ b/web/includes/database.php @@ -42,12 +42,18 @@ function dbConnect() { } try { - $dbOptions = array( - PDO::MYSQL_ATTR_SSL_CA => ZM_DB_SSL_CA_CERT, - PDO::MYSQL_ATTR_SSL_KEY => ZM_DB_SSL_CLIENT_KEY, - PDO::MYSQL_ATTR_SSL_CERT => ZM_DB_SSL_CLIENT_CERT, - ); - $dbConn = new PDO( ZM_DB_TYPE . $socket . ';dbname='.ZM_DB_NAME, ZM_DB_USER, ZM_DB_PASS, $dbOptions ); + $dbOptions = null; + if ( defined( 'ZM_DB_SSL_CA_CERT' ) and ZM_DB_SSL_CA_CERT ) { + $dbOptions = array( + PDO::MYSQL_ATTR_SSL_CA => ZM_DB_SSL_CA_CERT, + PDO::MYSQL_ATTR_SSL_KEY => ZM_DB_SSL_CLIENT_KEY, + PDO::MYSQL_ATTR_SSL_CERT => ZM_DB_SSL_CLIENT_CERT, + ); + $dbConn = new PDO( ZM_DB_TYPE . $socket . ';dbname='.ZM_DB_NAME, ZM_DB_USER, ZM_DB_PASS, $dbOptions ); + } else { + $dbConn = new PDO( ZM_DB_TYPE . $socket . ';dbname='.ZM_DB_NAME, ZM_DB_USER, ZM_DB_PASS ); + } + $dbConn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); $dbConn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch(PDOException $ex ) { From 9e2aa941fcfa3fa6fff23e5165868a7cbac1dc80 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 16 Aug 2017 11:31:47 -0400 Subject: [PATCH 065/114] rough in vaapi and qsv decoders. More debugging --- src/zm_ffmpeg_camera.cpp | 153 ++++++++++++++++++++++++++++++++++----- src/zm_ffmpeg_camera.h | 8 +- src/zm_videostore.cpp | 5 +- 3 files changed, 146 insertions(+), 20 deletions(-) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 0396fc097..f0548498e 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -25,6 +25,8 @@ extern "C" { #include "libavutil/time.h" +#include "libavutil/hwcontext.h" +#include "libavutil/hwcontext_qsv.h" } #ifndef AV_ERROR_MAX_STRING_SIZE #define AV_ERROR_MAX_STRING_SIZE 64 @@ -36,6 +38,45 @@ extern "C" { #include #endif + +static AVPixelFormat get_format(AVCodecContext *avctx, const enum AVPixelFormat *pix_fmts) { + while (*pix_fmts != AV_PIX_FMT_NONE) { + if (*pix_fmts == AV_PIX_FMT_QSV) { + DecodeContext *decode = (DecodeContext *)avctx->opaque; + AVHWFramesContext *frames_ctx; + AVQSVFramesContext *frames_hwctx; + int ret; + + /* create a pool of surfaces to be used by the decoder */ + avctx->hw_frames_ctx = av_hwframe_ctx_alloc(decode->hw_device_ref); + if (!avctx->hw_frames_ctx) + return AV_PIX_FMT_NONE; + frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; + frames_hwctx = (AVQSVFramesContext*)frames_ctx->hwctx; + + frames_ctx->format = AV_PIX_FMT_QSV; + frames_ctx->sw_format = avctx->sw_pix_fmt; + frames_ctx->width = FFALIGN(avctx->coded_width, 32); + frames_ctx->height = FFALIGN(avctx->coded_height, 32); + frames_ctx->initial_pool_size = 32; + + frames_hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET; + + ret = av_hwframe_ctx_init(avctx->hw_frames_ctx); + if (ret < 0) + return AV_PIX_FMT_NONE; + + return AV_PIX_FMT_QSV; + } + + pix_fmts++; + } + + Error( "The QSV pixel format not offered in get_format()"); + + return AV_PIX_FMT_NONE; +} + FfmpegCamera::FfmpegCamera( int p_id, const std::string &p_path, const std::string &p_method, const std::string &p_options, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ) : Camera( p_id, FFMPEG_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio ), mPath( p_path ), @@ -46,6 +87,10 @@ FfmpegCamera::FfmpegCamera( int p_id, const std::string &p_path, const std::stri Initialise(); } + hwaccel = false; + decode = { NULL }; + hwFrame = NULL; + mFormatContext = NULL; mVideoStreamId = -1; mAudioStreamId = -1; @@ -188,13 +233,33 @@ int FfmpegCamera::Capture( Image &image ) { zm_av_packet_unref( &packet ); continue; } - ret = avcodec_receive_frame( mVideoCodecContext, mRawFrame ); - if ( ret < 0 ) { - av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); - Error( "Unable to send packet at frame %d: %s, continuing", frameCount, errbuf ); - zm_av_packet_unref( &packet ); - continue; + + if ( hwaccel ) { + ret = avcodec_receive_frame( mVideoCodecContext, hwFrame ); + if ( ret < 0 ) { + av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); + Error( "Unable to send packet at frame %d: %s, continuing", frameCount, errbuf ); + zm_av_packet_unref( &packet ); + continue; + } + ret = av_hwframe_transfer_data(mRawFrame, hwFrame, 0); + if (ret < 0) { + av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); + Error( "Unable to transfer frame at frame %d: %s, continuing", frameCount, errbuf ); + zm_av_packet_unref( &packet ); + continue; + } + } else { + ret = avcodec_receive_frame( mVideoCodecContext, mRawFrame ); + if ( ret < 0 ) { + av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); + Error( "Unable to send packet at frame %d: %s, continuing", frameCount, errbuf ); + zm_av_packet_unref( &packet ); + continue; + } + } + frameComplete = 1; # else ret = zm_avcodec_decode_video( mVideoCodecContext, mRawFrame, &frameComplete, &packet ); @@ -397,12 +462,40 @@ int FfmpegCamera::OpenFfmpeg() { mVideoCodecContext->flags2 |= CODEC_FLAG2_FAST | CODEC_FLAG_LOW_DELAY; if ( mVideoCodecContext->codec_id == AV_CODEC_ID_H264 ) { - // Try to open an hwaccel codec. - if ( (mVideoCodec = avcodec_find_decoder_by_name("h264_vaapi")) == NULL ) { - Debug(1, "Failed to find decoder (h264_vaapi)" ); - } else { - Debug(1, "Success finding decoder (h264_vaapi)" ); + + //vaapi_decoder = new VAAPIDecoder(); + //mVideoCodecContext->opaque = vaapi_decoder; + //mVideoCodec = vaapi_decoder->openCodec( mVideoCodecContext ); + + if ( ! mVideoCodec ) { + // Try to open an hwaccel codec. + if ( (mVideoCodec = avcodec_find_decoder_by_name("h264_vaapi")) == NULL ) { + Debug(1, "Failed to find decoder (h264_vaapi)" ); + } else { + Debug(1, "Success finding decoder (h264_vaapi)" ); + } } + if ( ! mVideoCodec ) { + // Try to open an hwaccel codec. + if ( (mVideoCodec = avcodec_find_decoder_by_name("h264_qsv")) == NULL ) { + Debug(1, "Failed to find decoder (h264_qsv)" ); + } else { + Debug(1, "Success finding decoder (h264_qsv)" ); + /* open the hardware device */ + ret = av_hwdevice_ctx_create(&decode.hw_device_ref, AV_HWDEVICE_TYPE_QSV, + "auto", NULL, 0); + if (ret < 0) { + Error("Failed to open the hardware device"); + mVideoCodec = NULL; + } else { + mVideoCodecContext->opaque = &decode; + mVideoCodecContext->get_format = get_format; + hwaccel = true; + hwFrame = zm_av_frame_alloc(); + } + } + } + } // end if h264 if ( (!mVideoCodec) and ( (mVideoCodec = avcodec_find_decoder(mVideoCodecContext->codec_id)) == NULL ) ) { @@ -433,6 +526,11 @@ int FfmpegCamera::OpenFfmpeg() { } } + if (mVideoCodecContext->hwaccel != NULL) { + Debug(1, "HWACCEL in use"); + } else { + Debug(1, "HWACCEL not in use"); + } if ( mAudioStreamId >= 0 ) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) mAudioCodecContext = avcodec_alloc_context3( NULL ); @@ -826,13 +924,32 @@ else if ( packet.pts && video_last_pts > packet.pts ) { zm_av_packet_unref( &packet ); continue; } - ret = avcodec_receive_frame( mVideoCodecContext, mRawFrame ); - if ( ret < 0 ) { - av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); - Debug( 1, "Unable to send packet at frame %d: %s, continuing", frameCount, errbuf ); - zm_av_packet_unref( &packet ); - continue; + if ( hwaccel ) { + ret = avcodec_receive_frame( mVideoCodecContext, hwFrame ); + if ( ret < 0 ) { + av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); + Error( "Unable to send packet at frame %d: %s, continuing", frameCount, errbuf ); + zm_av_packet_unref( &packet ); + continue; + } + ret = av_hwframe_transfer_data(mRawFrame, hwFrame, 0); + if (ret < 0) { + av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); + Error( "Unable to transfer frame at frame %d: %s, continuing", frameCount, errbuf ); + zm_av_packet_unref( &packet ); + continue; + } + } else { + ret = avcodec_receive_frame( mVideoCodecContext, mRawFrame ); + if ( ret < 0 ) { + av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); + Error( "Unable to send packet at frame %d: %s, continuing", frameCount, errbuf ); + zm_av_packet_unref( &packet ); + continue; + } + } + frameComplete = 1; # else ret = zm_avcodec_decode_video( mVideoCodecContext, mRawFrame, &frameComplete, &packet ); @@ -911,4 +1028,6 @@ else if ( packet.pts && video_last_pts > packet.pts ) { return (frameCount); } // end FfmpegCamera::CaptureAndRecord + + #endif // HAVE_LIBAVFORMAT diff --git a/src/zm_ffmpeg_camera.h b/src/zm_ffmpeg_camera.h index 06d22f9a5..085440974 100644 --- a/src/zm_ffmpeg_camera.h +++ b/src/zm_ffmpeg_camera.h @@ -23,11 +23,13 @@ #include "zm_camera.h" #include "zm_buffer.h" -//#include "zm_utils.h" #include "zm_ffmpeg.h" #include "zm_videostore.h" #include "zm_packetqueue.h" +typedef struct DecodeContext { + AVBufferRef *hw_device_ref; +} DecodeContext; // // Class representing 'ffmpeg' cameras, i.e. those which are // accessed using ffmpeg multimedia framework @@ -52,6 +54,10 @@ class FfmpegCamera : public Camera { AVFrame *mFrame; _AVPIXELFORMAT imagePixFormat; + bool hwaccel; + AVFrame *hwFrame; + DecodeContext decode; + // Need to keep track of these because apparently the stream can start with values for pts/dts and then subsequent packets start at zero. int64_t audio_last_pts; int64_t audio_last_dts; diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 852c3fbf6..b270649ca 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -641,13 +641,14 @@ int VideoStore::writeVideoFramePacket( AVPacket *ipkt ) { opkt.pts = video_next_pts; opkt.dts = video_next_dts; + opkt.duration = 0; - int duration; + unsigned int duration; if ( ! video_last_pts ) { duration = 0; } else { duration = av_rescale_q( ipkt->pts - video_last_pts, video_input_stream->time_base, video_output_stream->time_base); - opkt.duration = 0; + Debug(1, "duration calc: pts(%d) - last_pts(%d) = (%d)", ipkt->pts, video_last_pts, duration ); } //#if ( 0 && video_last_pts && ( ipkt->duration == AV_NOPTS_VALUE || ! ipkt->duration ) ) { From da5438a6ff69f9a2fea0662585d4207cc3636426 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 16 Aug 2017 12:16:15 -0400 Subject: [PATCH 066/114] detect hardware accel capabilities --- CMakeLists.txt | 1 + src/zm_ffmpeg_camera.cpp | 14 ++++++++++++-- src/zm_videostore.cpp | 8 ++++++-- zoneminder-config.cmake | 1 + 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ad65d1f7..d4c0bba2b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -557,6 +557,7 @@ if(NOT ZM_NO_FFMPEG) mark_as_advanced(FORCE AVUTIL_LIBRARIES AVUTIL_INCLUDE_DIR) check_include_file("libavutil/avutil.h" HAVE_LIBAVUTIL_AVUTIL_H) check_include_file("libavutil/mathematics.h" HAVE_LIBAVUTIL_MATHEMATICS_H) + check_include_file("libavutil/hwcontext.h" HAVE_LIBAVUTIL_HWCONTEXT_H) set(optlibsfound "${optlibsfound} AVUtil") else(AVUTIL_LIBRARIES) set(optlibsnotfound "${optlibsnotfound} AVUtil") diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index f0548498e..1edc00c83 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -25,8 +25,10 @@ extern "C" { #include "libavutil/time.h" -#include "libavutil/hwcontext.h" -#include "libavutil/hwcontext_qsv.h" +#if HAVE_AVUTIL_HWCONTEXT_H + #include "libavutil/hwcontext.h" + #include "libavutil/hwcontext_qsv.h" +#endif } #ifndef AV_ERROR_MAX_STRING_SIZE #define AV_ERROR_MAX_STRING_SIZE 64 @@ -39,6 +41,7 @@ extern "C" { #endif +#if HAVE_AVUTIL_HWCONTEXT_H static AVPixelFormat get_format(AVCodecContext *avctx, const enum AVPixelFormat *pix_fmts) { while (*pix_fmts != AV_PIX_FMT_NONE) { if (*pix_fmts == AV_PIX_FMT_QSV) { @@ -76,6 +79,7 @@ static AVPixelFormat get_format(AVCodecContext *avctx, const enum AVPixelFormat return AV_PIX_FMT_NONE; } +#endif FfmpegCamera::FfmpegCamera( int p_id, const std::string &p_path, const std::string &p_method, const std::string &p_options, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ) : Camera( p_id, FFMPEG_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio ), @@ -234,6 +238,7 @@ int FfmpegCamera::Capture( Image &image ) { continue; } +#if HAVE_AVUTIL_HWCONTEXT_H if ( hwaccel ) { ret = avcodec_receive_frame( mVideoCodecContext, hwFrame ); if ( ret < 0 ) { @@ -250,6 +255,7 @@ int FfmpegCamera::Capture( Image &image ) { continue; } } else { +#endif ret = avcodec_receive_frame( mVideoCodecContext, mRawFrame ); if ( ret < 0 ) { av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); @@ -258,7 +264,9 @@ int FfmpegCamera::Capture( Image &image ) { continue; } +#if HAVE_AVUTIL_HWCONTEXT_H } +#endif frameComplete = 1; # else @@ -461,6 +469,7 @@ int FfmpegCamera::OpenFfmpeg() { //mVideoCodecContext->flags2 |= CODEC_FLAG2_FAST | CODEC_FLAG2_CHUNKS | CODEC_FLAG_LOW_DELAY; // Enable faster H264 decode. mVideoCodecContext->flags2 |= CODEC_FLAG2_FAST | CODEC_FLAG_LOW_DELAY; +#if HAVE_AVUTIL_HWCONTEXT_H if ( mVideoCodecContext->codec_id == AV_CODEC_ID_H264 ) { //vaapi_decoder = new VAAPIDecoder(); @@ -497,6 +506,7 @@ int FfmpegCamera::OpenFfmpeg() { } } // end if h264 +#endif if ( (!mVideoCodec) and ( (mVideoCodec = avcodec_find_decoder(mVideoCodecContext->codec_id)) == NULL ) ) { // Try and get the codec from the codec context diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index b270649ca..cba27cef6 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -623,7 +623,7 @@ bool VideoStore::setup_resampler() { void VideoStore::dumpPacket( AVPacket *pkt ){ char b[10240]; - snprintf(b, sizeof(b), " pts: %" PRId64 ", dts: %" PRId64 ", data: %p, size: %d, sindex: %d, dflags: %04x, s-pos: %" PRId64 ", c-duration: %" PRId64 "\n" + snprintf(b, sizeof(b), " pts: %" PRId64 ", dts: %" PRId64 ", data: %p, size: %d, sindex: %d, dflags: %04x, s-pos: %" PRId64 ", c-duration: %d\n" , pkt->pts , pkt->dts , pkt->data @@ -643,12 +643,16 @@ int VideoStore::writeVideoFramePacket( AVPacket *ipkt ) { opkt.dts = video_next_dts; opkt.duration = 0; - unsigned int duration; + int duration; if ( ! video_last_pts ) { duration = 0; } else { duration = av_rescale_q( ipkt->pts - video_last_pts, video_input_stream->time_base, video_output_stream->time_base); Debug(1, "duration calc: pts(%d) - last_pts(%d) = (%d)", ipkt->pts, video_last_pts, duration ); + if ( duration < 0 ) { + + duration = ipkt->duration; + } } //#if ( 0 && video_last_pts && ( ipkt->duration == AV_NOPTS_VALUE || ! ipkt->duration ) ) { diff --git a/zoneminder-config.cmake b/zoneminder-config.cmake index 3b35684b5..8641bb4a8 100644 --- a/zoneminder-config.cmake +++ b/zoneminder-config.cmake @@ -51,6 +51,7 @@ #cmakedefine HAVE_LIBAVUTIL 1 #cmakedefine HAVE_LIBAVUTIL_AVUTIL_H 1 #cmakedefine HAVE_LIBAVUTIL_MATHEMATICS_H 1 +#cmakedefine HAVE_LIBAVUTIL_HWCONTEXT_H 0 #cmakedefine HAVE_LIBSWSCALE 1 #cmakedefine HAVE_LIBSWSCALE_SWSCALE_H 1 #cmakedefine HAVE_LIBAVRESAMPLE 1 From a63d0878b6ddffa31a5618677e36d69dd7c43109 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 16 Aug 2017 13:41:44 -0400 Subject: [PATCH 067/114] remove more hwaccel code --- src/zm_ffmpeg_camera.cpp | 2 ++ src/zm_ffmpeg_camera.h | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 1edc00c83..2a0ca36c2 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -92,8 +92,10 @@ FfmpegCamera::FfmpegCamera( int p_id, const std::string &p_path, const std::stri } hwaccel = false; +#if HAVE_AVUTIL_HWCONTEXT_H decode = { NULL }; hwFrame = NULL; +#endif mFormatContext = NULL; mVideoStreamId = -1; diff --git a/src/zm_ffmpeg_camera.h b/src/zm_ffmpeg_camera.h index 085440974..9e10b76bf 100644 --- a/src/zm_ffmpeg_camera.h +++ b/src/zm_ffmpeg_camera.h @@ -27,9 +27,11 @@ #include "zm_videostore.h" #include "zm_packetqueue.h" +#if HAVE_AVUTIL_HWCONTEXT_H typedef struct DecodeContext { AVBufferRef *hw_device_ref; } DecodeContext; +#endif // // Class representing 'ffmpeg' cameras, i.e. those which are // accessed using ffmpeg multimedia framework @@ -55,8 +57,10 @@ class FfmpegCamera : public Camera { _AVPIXELFORMAT imagePixFormat; bool hwaccel; +#if HAVE_AVUTIL_HWCONTEXT_H AVFrame *hwFrame; DecodeContext decode; +#endif // Need to keep track of these because apparently the stream can start with values for pts/dts and then subsequent packets start at zero. int64_t audio_last_pts; From d71b30aff31ceea23d24f8dc08fdcaef75dd404a Mon Sep 17 00:00:00 2001 From: peruchi Date: Wed, 16 Aug 2017 15:51:20 -0300 Subject: [PATCH 068/114] Images Gif to PNG (#1969) * Images Gif to PNG Extension change to PNG * Images Gif to PNG Extension change to PNG * Images Gif to PNG Extension change to PNG --- web/skins/classic/css/classic/views/zone.css | 6 +++--- web/skins/classic/css/dark/views/zone.css | 6 +++--- web/skins/classic/css/flat/views/zone.css | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/web/skins/classic/css/classic/views/zone.css b/web/skins/classic/css/classic/views/zone.css index 897ee50ee..a637787d5 100644 --- a/web/skins/classic/css/classic/views/zone.css +++ b/web/skins/classic/css/classic/views/zone.css @@ -52,15 +52,15 @@ } #imageFrame div { - background-image: url(../../../graphics/point-g.gif); + background-image: url(../../../graphics/point-g.png); } #imageFrame div.highlight { - background-image: url(../../../graphics/point-o.gif); + background-image: url(../../../graphics/point-o.png); } #imageFrame div.active { - background-image: url(../../../graphics/point-r.gif); + background-image: url(../../../graphics/point-r.png); } #zonePoints { diff --git a/web/skins/classic/css/dark/views/zone.css b/web/skins/classic/css/dark/views/zone.css index 884c8dbe0..7d81d731b 100644 --- a/web/skins/classic/css/dark/views/zone.css +++ b/web/skins/classic/css/dark/views/zone.css @@ -52,15 +52,15 @@ } #imageFrame div { - background-image: url(../../../graphics/point-g.gif); + background-image: url(../../../graphics/point-g.png); } #imageFrame div.highlight { - background-image: url(../../../graphics/point-o.gif); + background-image: url(../../../graphics/point-o.png); } #imageFrame div.active { - background-image: url(../../../graphics/point-r.gif); + background-image: url(../../../graphics/point-r.png); } #zonePoints { diff --git a/web/skins/classic/css/flat/views/zone.css b/web/skins/classic/css/flat/views/zone.css index 54ea4eabf..fbf85b1db 100644 --- a/web/skins/classic/css/flat/views/zone.css +++ b/web/skins/classic/css/flat/views/zone.css @@ -52,15 +52,15 @@ } #imageFrame div { - background-image: url(../../../graphics/point-g.gif); + background-image: url(../../../graphics/point-g.png); } #imageFrame div.highlight { - background-image: url(../../../graphics/point-o.gif); + background-image: url(../../../graphics/point-o.png); } #imageFrame div.active { - background-image: url(../../../graphics/point-r.gif); + background-image: url(../../../graphics/point-r.png); } #zonePoints { From 05b9b8bc51d8d6d4b5e81696277e9a185c44123b Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Wed, 16 Aug 2017 18:53:02 -0500 Subject: [PATCH 069/114] Update .travis.yml remove nightly build support for fedora 24 --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3afa0f02a..3ec7a200a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,7 +27,6 @@ env: matrix: - OS=el DIST=6 - OS=el DIST=7 - - OS=fedora DIST=24 - OS=fedora DIST=25 - OS=ubuntu DIST=trusty - OS=ubuntu DIST=xenial From f01adc6be5ff32f36130ff47e30654d0e88c49ef Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 17 Aug 2017 10:18:51 -0400 Subject: [PATCH 070/114] fixes --- web/includes/actions.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/includes/actions.php b/web/includes/actions.php index 836328829..281c2ac8f 100644 --- a/web/includes/actions.php +++ b/web/includes/actions.php @@ -435,7 +435,7 @@ Warning("Addterm"); # If we change anything that changes the shared mem size, zma can complain. So let's stop first. zmaControl( $monitor, 'stop' ); zmcControl( $monitor, 'stop' ); - dbQuery( 'UPDATE Monitors SET '.implode( ", ", $changes ).' WHERE Id =?', array($mid) ); + dbQuery( 'UPDATE Monitors SET '.implode( ', ', $changes ).' WHERE Id=?', array($mid) ); if ( isset($changes['Name']) ) { $saferOldName = basename( $monitor['Name'] ); $saferNewName = basename( $_REQUEST['newMonitor']['Name'] ); @@ -521,7 +521,7 @@ Warning("Addterm"); zmcControl( $new_monitor, 'start' ); zmaControl( $new_monitor, 'start' ); - if ( $monitor['Controllable'] ) { + if ( $new_monitor['Controllable'] ) { require_once( 'control_functions.php' ); sendControlCommand( $mid, 'quit' ); } From 6e24eb64627447a594424c361ad3197104c96c99 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 18 Aug 2017 09:28:14 -0400 Subject: [PATCH 071/114] use find_one ins tead of New when loading event to determine if event still exists in db --- scripts/zmaudit.pl.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/zmaudit.pl.in b/scripts/zmaudit.pl.in index 2d6e97297..deb1c7781 100644 --- a/scripts/zmaudit.pl.in +++ b/scripts/zmaudit.pl.in @@ -350,8 +350,8 @@ MAIN: while( $loop ) { while ( my ( $db_event, $age ) = each( %$db_events ) ) { if ( ! defined( $fs_events->{$db_event} ) ) { Debug("Event $db_event is not in fs."); - my $Event = new ZoneMinder::Event( $db_event ); - if ( ! $Event->Id() ) { + my $Event = ZoneMinder::Event->find_one( Id=>$db_event ); + if ( $Event ) { Debug("Event $db_event is no longer in db. Filter probably deleted it while we were auditing."); next; } From 76b9a9dc01fdc6ba51683380c695ec4083c707e5 Mon Sep 17 00:00:00 2001 From: Andy Bauer Date: Sat, 19 Aug 2017 09:07:32 -0500 Subject: [PATCH 072/114] build non-el6 rpms from rpm fusion rather than zmrepo --- utils/packpack/redhat_package.mk | 2 +- utils/packpack/startpackpack.sh | 20 ++++++++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/utils/packpack/redhat_package.mk b/utils/packpack/redhat_package.mk index c15e03528..34974e1b0 100644 --- a/utils/packpack/redhat_package.mk +++ b/utils/packpack/redhat_package.mk @@ -4,5 +4,5 @@ redhat_package: redhat_bootstrap package redhat_bootstrap: - sudo yum install -y --nogpgcheck build/zmrepo.noarch.rpm + sudo yum install -y --nogpgcheck build/external-repo.noarch.rpm diff --git a/utils/packpack/startpackpack.sh b/utils/packpack/startpackpack.sh index 4e32671fd..566ef0555 100755 --- a/utils/packpack/startpackpack.sh +++ b/utils/packpack/startpackpack.sh @@ -235,20 +235,24 @@ if [ "${TRAVIS_EVENT_TYPE}" == "cron" ] || [ "${TRAVIS}" != "true" ]; then rm -rf web/api/app/Plugin/Crud mkdir web/api/app/Plugin/Crud - if [ "${OS}" == "el" ]; then - zmrepodistro=${OS} + # We use zmrepo to build el6 only. All other redhat distros use rpm fusion + if [ "${OS}" == "el" ] && [ "${DIST}" == "6" ]; then + baseurl="https://zmrepo.zoneminder.com/el/${DIST}/x86_64/" + reporpm="zmrepo" else - zmrepodistro="f" + baseurl="http://download1.rpmfusion.org/free/${OS}/updates/${DIST}/x86_64/" + reporpm="rpmfusion-free-release" fi - # Let repoquery determine the full url and filename of the zmrepo rpm we are interested in - result=`repoquery --repofrompath=zmpackpack,https://zmrepo.zoneminder.com/${zmrepodistro}/"${DIST}"/x86_64/ --repoid=zmpackpack --qf="%{location}" zmrepo 2> /dev/null` + # Let repoquery determine the full url and filename of the external repo rpm we are interested in + result=`repoquery --archlist=noarch --repofrompath=zmpackpack,${baseurl} --repoid=zmpackpack --qf="%{location}" ${reporpm} 2> /dev/null` + # Give our downloaded repo rpm a common name so redhat_package.mk can find it if [ -n "$result" ] && [ $? -eq 0 ]; then - echo "Retrieving ZMREPO rpm..." - curl $result > build/zmrepo.noarch.rpm + echo "Retrieving ${reporpm} repo rpm..." + curl $result > build/external-repo.noarch.rpm else - echo "ERROR: Failed to retrieve zmrepo rpm..." + echo "ERROR: Failed to retrieve ${reporpm} repo rpm..." exit 1 fi From dafe125ed5f4e8c24b3e84e0ed018cf5bcd3d276 Mon Sep 17 00:00:00 2001 From: Andy Bauer Date: Sat, 19 Aug 2017 12:39:54 -0500 Subject: [PATCH 073/114] initial commit to add packpack build instructions --- docs/installationguide/index.rst | 1 + docs/installationguide/packpack.rst | 93 +++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 docs/installationguide/packpack.rst diff --git a/docs/installationguide/index.rst b/docs/installationguide/index.rst index e030ed7cf..8b8a7c376 100644 --- a/docs/installationguide/index.rst +++ b/docs/installationguide/index.rst @@ -6,6 +6,7 @@ Contents: .. toctree:: :maxdepth: 2 + packpack ubuntu debian redhat diff --git a/docs/installationguide/packpack.rst b/docs/installationguide/packpack.rst new file mode 100644 index 000000000..dff411848 --- /dev/null +++ b/docs/installationguide/packpack.rst @@ -0,0 +1,93 @@ +All Distros - A Simpler Way to Build ZoneMinder +============================================== + +.. contents:: + +These instructions represent an alternative way to build ZoneMinder for any supported distro. + +Advantages: +- Fewer steps and therefore much simpler +- Target distro agnostic - the steps are the same regardless of the target distro +- Host distro agnostic - the steps described here should work on an host Linux distro + +Background +------------------------------------ + +These instructions leverage the power of the automated build system recently implemented in the ZoneMinder project. Behind the scenes, a project called `packpack `_ is utilized, to build ZoneMinder inside a Docker container. + +Procedure +------------------------------------ + +**Step 1:** Verify the target distro. + +Open the project's `.travis.yml file `_ and verify the distro you want to build ZoneMinder for appears in the build matrix. The distros shown in the matrix are those known to build on ZoneMinder. If the distro you desire is in the list then continue to step two. If the desried distro is not in the list then open the `packpack project README `_ and check if the desired distro is supported. If it is, then continue to step 2 with the understanding that you are heading out into uncharted territory. There could be problems. If the desired distro does not appear in this list, then unfortuantely you cannot use the procedure described here. + +**Step 2:** Install Docker. + +You need to have a working installation of Docker so head over to the `Docker site `_ and get it working. Before continuing to the next step, verify you can run the Docker "Hello World" container as a normal user. + +**Step 3:** Git clone the ZoneMinder project. + +Clone the ZoneMinder project if you have not done so already. + +:: + + git clone ZoneMinder + cd ZoneMinder + +Alternatively, if you have already cloned the repo and wish to update it, do the following. + +:: + + cd ZoneMinder + git checkout master + git pull origin master + +**Step 4:** Checkout the revision of ZoneMinder you wish to build + +A freshly cloned ZoneMinder git repo already points to the lastest master branch. If this is what you desire to build then continue to the next step. If instead, you want to build a release then perform the following step. + +:: + + git checkout + +Where is one of the official ZoneMinder releases, such as 1.30.4. + +**Step 5:** Build ZoneMinder + +To start the build, simply execute the following command from the root folder of the local git repo: + +:: + + OS= DIST= utils/packpack/startpackpack.sh + +Where is the name of the distro you wish to build on, such as fedora, and is release name or number of the distro you wish to build on. Redhat distros expect a number for while Debian and Ubuntu distros expect a name. For example: + +:: + + OS=fedora DIST=25 utils/packpack/startpackpack.sh + +:: + + OS=ubuntu DIST=xenial utils/packpack/startpackpack.sh + +Once you enter the appropriate command, go get a coffee while a ZoneMinder package is built. When the build finished, you can find the resulting packages under a subfolder called "build". + +Note that this will build packages with x86_64 architecture. Some distros (debian & ubuntu only at the moment) also supported on i386 architecture. You can do that by adding "ARCH=i386" parameter. + +:: + + OS=ubuntu DIST=xenial ARCH=i386 utils/packpack/startpackpack.sh + +For advanced users who really want to go out into uncharted waters, it is theoretically possible to build arm packages as well, as long as the host architecture is compatible. + +:: + + OS=ubuntu DIST=xenial ARCH=armhfp utils/packpack/startpackpack.sh + +Building arm packages in this manner has not been tested by us, however. + + + + + From 4adad745d0f25afd378ca4a0cc94714da43ca677 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 19 Aug 2017 12:42:44 -0500 Subject: [PATCH 074/114] Update packpack.rst fix bullets --- docs/installationguide/packpack.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/installationguide/packpack.rst b/docs/installationguide/packpack.rst index dff411848..0a3e4738b 100644 --- a/docs/installationguide/packpack.rst +++ b/docs/installationguide/packpack.rst @@ -6,6 +6,7 @@ All Distros - A Simpler Way to Build ZoneMinder These instructions represent an alternative way to build ZoneMinder for any supported distro. Advantages: + - Fewer steps and therefore much simpler - Target distro agnostic - the steps are the same regardless of the target distro - Host distro agnostic - the steps described here should work on an host Linux distro From 7a1208daaa796bada99b0bf34b11f619229f52e3 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 19 Aug 2017 12:43:28 -0500 Subject: [PATCH 075/114] Update packpack.rst --- docs/installationguide/packpack.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installationguide/packpack.rst b/docs/installationguide/packpack.rst index 0a3e4738b..2b3aa6634 100644 --- a/docs/installationguide/packpack.rst +++ b/docs/installationguide/packpack.rst @@ -9,7 +9,7 @@ Advantages: - Fewer steps and therefore much simpler - Target distro agnostic - the steps are the same regardless of the target distro -- Host distro agnostic - the steps described here should work on an host Linux distro +- Host distro agnostic - the steps described here should work on any host Linux distro capable of running Bash and Docker Background ------------------------------------ From 7ed53f766e348a68d9f29f4abe6a64d90740f59c Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 19 Aug 2017 12:45:39 -0500 Subject: [PATCH 076/114] Update packpack.rst --- docs/installationguide/packpack.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/installationguide/packpack.rst b/docs/installationguide/packpack.rst index 2b3aa6634..85aca5bc8 100644 --- a/docs/installationguide/packpack.rst +++ b/docs/installationguide/packpack.rst @@ -21,7 +21,11 @@ Procedure **Step 1:** Verify the target distro. -Open the project's `.travis.yml file `_ and verify the distro you want to build ZoneMinder for appears in the build matrix. The distros shown in the matrix are those known to build on ZoneMinder. If the distro you desire is in the list then continue to step two. If the desried distro is not in the list then open the `packpack project README `_ and check if the desired distro is supported. If it is, then continue to step 2 with the understanding that you are heading out into uncharted territory. There could be problems. If the desired distro does not appear in this list, then unfortuantely you cannot use the procedure described here. +- Open the project's `.travis.yml file `_ and verify the distro you want to build ZoneMinder for appears in the build matrix. The distros shown in the matrix are those known to build on ZoneMinder. If the distro you desire is in the list then continue to step two. + +- If the desried distro is not in the list, then open the `packpack project README `_ and check if the desired distro is theoretically supported. If it is, then continue to step 2 with the understanding that you are heading out into uncharted territory. There could be problems. + +- If the desired distro does not appear in either list, then unfortuantely you cannot use the procedure described here. **Step 2:** Install Docker. From 65f03ce6134b7302f1552b7ba64a3fd7b1e0df51 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 19 Aug 2017 12:46:00 -0500 Subject: [PATCH 077/114] Update packpack.rst --- docs/installationguide/packpack.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installationguide/packpack.rst b/docs/installationguide/packpack.rst index 85aca5bc8..668df84eb 100644 --- a/docs/installationguide/packpack.rst +++ b/docs/installationguide/packpack.rst @@ -23,7 +23,7 @@ Procedure - Open the project's `.travis.yml file `_ and verify the distro you want to build ZoneMinder for appears in the build matrix. The distros shown in the matrix are those known to build on ZoneMinder. If the distro you desire is in the list then continue to step two. -- If the desried distro is not in the list, then open the `packpack project README `_ and check if the desired distro is theoretically supported. If it is, then continue to step 2 with the understanding that you are heading out into uncharted territory. There could be problems. +- If the desired distro is not in the list, then open the `packpack project README `_ and check if the desired distro is theoretically supported. If it is, then continue to step 2 with the understanding that you are heading out into uncharted territory. There could be problems. - If the desired distro does not appear in either list, then unfortuantely you cannot use the procedure described here. From 8bf395465f64dd50d8c42c3c039a0691605c0652 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 19 Aug 2017 12:46:38 -0500 Subject: [PATCH 078/114] Update packpack.rst --- docs/installationguide/packpack.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installationguide/packpack.rst b/docs/installationguide/packpack.rst index 668df84eb..dbdd1a959 100644 --- a/docs/installationguide/packpack.rst +++ b/docs/installationguide/packpack.rst @@ -23,7 +23,7 @@ Procedure - Open the project's `.travis.yml file `_ and verify the distro you want to build ZoneMinder for appears in the build matrix. The distros shown in the matrix are those known to build on ZoneMinder. If the distro you desire is in the list then continue to step two. -- If the desired distro is not in the list, then open the `packpack project README `_ and check if the desired distro is theoretically supported. If it is, then continue to step 2 with the understanding that you are heading out into uncharted territory. There could be problems. +- If the desired distro is not in the first list, then open the `packpack project README `_ and check if the desired distro is theoretically supported. If it is, then continue to step 2 with the understanding that you are heading out into uncharted territory. There could be problems. - If the desired distro does not appear in either list, then unfortuantely you cannot use the procedure described here. From e473806fff033455b9ce3a19e40c55c7689f8e94 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 19 Aug 2017 12:47:41 -0500 Subject: [PATCH 079/114] Update packpack.rst --- docs/installationguide/packpack.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installationguide/packpack.rst b/docs/installationguide/packpack.rst index dbdd1a959..453d7d3d6 100644 --- a/docs/installationguide/packpack.rst +++ b/docs/installationguide/packpack.rst @@ -48,7 +48,7 @@ Alternatively, if you have already cloned the repo and wish to update it, do the git checkout master git pull origin master -**Step 4:** Checkout the revision of ZoneMinder you wish to build +**Step 4:** Checkout the revision of ZoneMinder you wish to build. A freshly cloned ZoneMinder git repo already points to the lastest master branch. If this is what you desire to build then continue to the next step. If instead, you want to build a release then perform the following step. From 9172a1bc4213187f503812da2bb1d21f1be8409a Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 19 Aug 2017 12:48:57 -0500 Subject: [PATCH 080/114] Update packpack.rst --- docs/installationguide/packpack.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installationguide/packpack.rst b/docs/installationguide/packpack.rst index 453d7d3d6..f0c928652 100644 --- a/docs/installationguide/packpack.rst +++ b/docs/installationguide/packpack.rst @@ -50,7 +50,7 @@ Alternatively, if you have already cloned the repo and wish to update it, do the **Step 4:** Checkout the revision of ZoneMinder you wish to build. -A freshly cloned ZoneMinder git repo already points to the lastest master branch. If this is what you desire to build then continue to the next step. If instead, you want to build a release then perform the following step. +A freshly cloned ZoneMinder git repo already points to the most recent commit in the master branch. If you want the latest development code then continue to the next step. If instead, you want to build a stable release then perform the following step. :: From 52accd7ff5ea15d090a291c746f8333381a20bc9 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 19 Aug 2017 12:50:07 -0500 Subject: [PATCH 081/114] Update packpack.rst --- docs/installationguide/packpack.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installationguide/packpack.rst b/docs/installationguide/packpack.rst index f0c928652..67bc525d5 100644 --- a/docs/installationguide/packpack.rst +++ b/docs/installationguide/packpack.rst @@ -56,7 +56,7 @@ A freshly cloned ZoneMinder git repo already points to the most recent commit in git checkout -Where is one of the official ZoneMinder releases, such as 1.30.4. +Where is one of the official ZoneMinder releases shown on the `releases page `_, such as 1.30.4. **Step 5:** Build ZoneMinder From 4ccca556e1f5d9e8e7e2bea32b067b07446c12e0 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 19 Aug 2017 12:52:21 -0500 Subject: [PATCH 082/114] Update packpack.rst --- docs/installationguide/packpack.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installationguide/packpack.rst b/docs/installationguide/packpack.rst index 67bc525d5..70319becf 100644 --- a/docs/installationguide/packpack.rst +++ b/docs/installationguide/packpack.rst @@ -78,7 +78,7 @@ Where is the name of the distro you wish to build on, such as fedor Once you enter the appropriate command, go get a coffee while a ZoneMinder package is built. When the build finished, you can find the resulting packages under a subfolder called "build". -Note that this will build packages with x86_64 architecture. Some distros (debian & ubuntu only at the moment) also supported on i386 architecture. You can do that by adding "ARCH=i386" parameter. +Note that this will build packages with x86_64 architecture. This build method can also build on some distros (debian & ubuntu only at the moment) using i386 architecture. You can do that by adding "ARCH=i386" parameter. :: From 54f780e2d391130d4e291400fafac30bcce67711 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 19 Aug 2017 13:15:11 -0500 Subject: [PATCH 083/114] Update redhat.rst --- docs/installationguide/redhat.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installationguide/redhat.rst b/docs/installationguide/redhat.rst index 93513fe08..63a307e21 100644 --- a/docs/installationguide/redhat.rst +++ b/docs/installationguide/redhat.rst @@ -86,7 +86,7 @@ As mentioned above, the place to get the latest ZoneMinder release is now `RPM F Note that RHEL/CentOS 7 users should use yum instead of dnf. -How to Build a Your Own ZoneMinder Package +How to Build Your Own ZoneMinder Package ------------------------------------------ If you are looking to do development or the available packages just don't suit you, then you can follow these steps to build your own ZoneMinder RPM. From a191486c18b2d43c0ec149c29cb077bf1372640e Mon Sep 17 00:00:00 2001 From: Andy Bauer Date: Sat, 19 Aug 2017 16:56:17 -0500 Subject: [PATCH 084/114] packpack - update rpm fusion download url --- utils/packpack/startpackpack.sh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/utils/packpack/startpackpack.sh b/utils/packpack/startpackpack.sh index 566ef0555..3593c1697 100755 --- a/utils/packpack/startpackpack.sh +++ b/utils/packpack/startpackpack.sh @@ -239,16 +239,15 @@ if [ "${TRAVIS_EVENT_TYPE}" == "cron" ] || [ "${TRAVIS}" != "true" ]; then if [ "${OS}" == "el" ] && [ "${DIST}" == "6" ]; then baseurl="https://zmrepo.zoneminder.com/el/${DIST}/x86_64/" reporpm="zmrepo" + # Let repoquery determine the full url and filename to the latest zmrepo package + dlurl=`repoquery --archlist=noarch --repofrompath=zmpackpack,${baseurl} --repoid=zmpackpack --qf="%{location}" ${reporpm} 2> /dev/null` else - baseurl="http://download1.rpmfusion.org/free/${OS}/updates/${DIST}/x86_64/" reporpm="rpmfusion-free-release" + dlurl="https://download1.rpmfusion.org/free/${OS}/${reporpm}-${DIST}.noarch.rpm" fi - # Let repoquery determine the full url and filename of the external repo rpm we are interested in - result=`repoquery --archlist=noarch --repofrompath=zmpackpack,${baseurl} --repoid=zmpackpack --qf="%{location}" ${reporpm} 2> /dev/null` - # Give our downloaded repo rpm a common name so redhat_package.mk can find it - if [ -n "$result" ] && [ $? -eq 0 ]; then + if [ -n "$dlurl" ] && [ $? -eq 0 ]; then echo "Retrieving ${reporpm} repo rpm..." curl $result > build/external-repo.noarch.rpm else From 4e61f2f55abc1a6b9e7a8ad1e7963ac4f91824e3 Mon Sep 17 00:00:00 2001 From: Andy Bauer Date: Sat, 19 Aug 2017 17:17:18 -0500 Subject: [PATCH 085/114] packpack - don't filter output when we aren't in travis --- utils/packpack/startpackpack.sh | 34 +++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/utils/packpack/startpackpack.sh b/utils/packpack/startpackpack.sh index 3593c1697..23bf3f512 100755 --- a/utils/packpack/startpackpack.sh +++ b/utils/packpack/startpackpack.sh @@ -211,6 +211,19 @@ zoneminder ($VERSION-${DIST}-1) unstable; urgency=low EOF } +# start packpack, filter the output if we are running in travis +execpackpack () { + if [ "${TRAVIS}" == "true" ]; then + utils/packpack/heartbeat.sh & + mypid=$! + packpack/packpack > buildlog.txt 2>&1 + kill $mypid + tail -n 3000 buildlog.txt | grep -v ONVIF + else + packpack/packpack + fi +} + ################ # MAIN PROGRAM # ################ @@ -249,20 +262,17 @@ if [ "${TRAVIS_EVENT_TYPE}" == "cron" ] || [ "${TRAVIS}" != "true" ]; then # Give our downloaded repo rpm a common name so redhat_package.mk can find it if [ -n "$dlurl" ] && [ $? -eq 0 ]; then echo "Retrieving ${reporpm} repo rpm..." - curl $result > build/external-repo.noarch.rpm + curl $dlurl > build/external-repo.noarch.rpm else echo "ERROR: Failed to retrieve ${reporpm} repo rpm..." + echo "Download url was: $dlurl" exit 1 fi setrpmchangelog echo "Starting packpack..." - utils/packpack/heartbeat.sh & - mypid=$! - packpack/packpack -f utils/packpack/redhat_package.mk redhat_package > buildlog.txt 2>&1 - kill $mypid - tail -n 3000 buildlog.txt | grep -v ONVIF + execpackpack # Steps common to Debian based distros elif [ "${OS}" == "debian" ] || [ "${OS}" == "ubuntu" ]; then @@ -282,11 +292,7 @@ if [ "${TRAVIS_EVENT_TYPE}" == "cron" ] || [ "${TRAVIS}" != "true" ]; then setdebchangelog echo "Starting packpack..." - utils/packpack/heartbeat.sh & - mypid=$! - packpack/packpack > buildlog.txt 2>&1 - kill $mypid - tail -n 3000 buildlog.txt | grep -v ONVIF + execpackpack if [ "${OS}" == "ubuntu" ] && [ "${DIST}" == "trusty" ] && [ "${ARCH}" == "x86_64" ] && [ "${TRAVIS}" == "true" ]; then installtrusty @@ -306,11 +312,7 @@ elif [ "${OS}" == "ubuntu" ] && [ "${DIST}" == "trusty" ] && [ "${ARCH}" == "x86 setdebchangelog echo "Starting packpack..." - utils/packpack/heartbeat.sh & - mypid=$! - packpack/packpack > buildlog.txt 2>&1 - kill $mypid - tail -n 3000 buildlog.txt | grep -v ONVIF + execpackpack # If we are running inside Travis then attempt to install the deb we just built if [ "${TRAVIS}" == "true" ]; then From 7ceb88866c3511c93417fb5aa4185c3257de3a37 Mon Sep 17 00:00:00 2001 From: Andy Bauer Date: Sat, 19 Aug 2017 17:47:06 -0500 Subject: [PATCH 086/114] packpack - put pack redhat specific packpack parms --- utils/packpack/startpackpack.sh | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/utils/packpack/startpackpack.sh b/utils/packpack/startpackpack.sh index 23bf3f512..bb38a809c 100755 --- a/utils/packpack/startpackpack.sh +++ b/utils/packpack/startpackpack.sh @@ -213,6 +213,13 @@ EOF # start packpack, filter the output if we are running in travis execpackpack () { + + if [ "${OS}" == "el" ] || [ "${OS}" == "fedora" ]; then + parms="-f utils/packpack/redhat_package.mk redhat_package" + else + parms="" + fi + if [ "${TRAVIS}" == "true" ]; then utils/packpack/heartbeat.sh & mypid=$! @@ -220,7 +227,7 @@ execpackpack () { kill $mypid tail -n 3000 buildlog.txt | grep -v ONVIF else - packpack/packpack + packpack/packpack $parms fi } @@ -261,7 +268,7 @@ if [ "${TRAVIS_EVENT_TYPE}" == "cron" ] || [ "${TRAVIS}" != "true" ]; then # Give our downloaded repo rpm a common name so redhat_package.mk can find it if [ -n "$dlurl" ] && [ $? -eq 0 ]; then - echo "Retrieving ${reporpm} repo rpm..." + echo "Retrieving ${reporpm} repo rpm..."gd curl $dlurl > build/external-repo.noarch.rpm else echo "ERROR: Failed to retrieve ${reporpm} repo rpm..." From 25c19198f6dea3f3e1075e1b623d2bbd01e15a85 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 19 Aug 2017 20:57:41 -0500 Subject: [PATCH 087/114] packpack - relax the requirements for repoquery --- utils/packpack/startpackpack.sh | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/utils/packpack/startpackpack.sh b/utils/packpack/startpackpack.sh index bb38a809c..0feb4b135 100755 --- a/utils/packpack/startpackpack.sh +++ b/utils/packpack/startpackpack.sh @@ -9,7 +9,7 @@ # General sanity checks checksanity () { # Check to see if this script has access to all the commands it needs - for CMD in set echo curl repoquery git ln mkdir rmdir cat patch; do + for CMD in set echo curl git ln mkdir rmdir cat patch; do type $CMD 2>&1 > /dev/null if [ $? -ne 0 ]; then @@ -20,6 +20,19 @@ checksanity () { fi done + if [ "${OS}" == "el" ] && [ "${DIST}" == "6" ]; then + type repoquery 2>&1 > /dev/null + + if [ $? -ne 0 ]; then + echo + echo "ERROR: The script cannot find the required command \"reqoquery\"." + echo "This command is required in order to build ZoneMinder on el6." + echo "Please install the \"yum-utils\" then try again." + echo + exit 1 + fi + fi + # Verify OS & DIST environment variables have been set before calling this script if [ -z "${OS}" ] || [ -z "${DIST}" ]; then echo "ERROR: both OS and DIST environment variables must be set" From ccb7e08aaea11a179332e5246815254cf17fc718 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 19 Aug 2017 20:58:26 -0500 Subject: [PATCH 088/114] remove extra whitespace --- utils/packpack/startpackpack.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/packpack/startpackpack.sh b/utils/packpack/startpackpack.sh index 0feb4b135..1cac64ad4 100755 --- a/utils/packpack/startpackpack.sh +++ b/utils/packpack/startpackpack.sh @@ -21,7 +21,7 @@ checksanity () { done if [ "${OS}" == "el" ] && [ "${DIST}" == "6" ]; then - type repoquery 2>&1 > /dev/null + type repoquery 2>&1 > /dev/null if [ $? -ne 0 ]; then echo From 20b0a26bc5fd9a0e35769e783c5dd90067cf25cf Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 19 Aug 2017 20:59:30 -0500 Subject: [PATCH 089/114] Update startpackpack.sh --- utils/packpack/startpackpack.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/packpack/startpackpack.sh b/utils/packpack/startpackpack.sh index 1cac64ad4..e911630ab 100755 --- a/utils/packpack/startpackpack.sh +++ b/utils/packpack/startpackpack.sh @@ -27,7 +27,7 @@ checksanity () { echo echo "ERROR: The script cannot find the required command \"reqoquery\"." echo "This command is required in order to build ZoneMinder on el6." - echo "Please install the \"yum-utils\" then try again." + echo "Please install the \"yum-utils\" package then try again." echo exit 1 fi From e7498661013409bb39f7284106fed9a0b23f2d5d Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 19 Aug 2017 21:17:06 -0500 Subject: [PATCH 090/114] Update packpack.rst --- docs/installationguide/packpack.rst | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/installationguide/packpack.rst b/docs/installationguide/packpack.rst index 70319becf..deabf400a 100644 --- a/docs/installationguide/packpack.rst +++ b/docs/installationguide/packpack.rst @@ -29,7 +29,14 @@ Procedure **Step 2:** Install Docker. -You need to have a working installation of Docker so head over to the `Docker site `_ and get it working. Before continuing to the next step, verify you can run the Docker "Hello World" container as a normal user. +You need to have a working installation of Docker so head over to the `Docker site `_ and get it working. Before continuing to the next step, verify you can run the Docker "Hello World" container as a normal user. To run a Docker container as a normal user, issue the following: + +:: + + sudo gpasswd -a docker + newgrp docker + +Where is, you guessed it, the user name you log in with. **Step 3:** Git clone the ZoneMinder project. From 7d0531ccdde8c9284528c6db5710fb288cd9f8fa Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 19 Aug 2017 21:37:04 -0500 Subject: [PATCH 091/114] Update packpack.rst --- docs/installationguide/packpack.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installationguide/packpack.rst b/docs/installationguide/packpack.rst index deabf400a..c1f20261d 100644 --- a/docs/installationguide/packpack.rst +++ b/docs/installationguide/packpack.rst @@ -1,5 +1,5 @@ All Distros - A Simpler Way to Build ZoneMinder -============================================== +=============================================== .. contents:: From dc1aa2b670990a2f77fb2204ce0f3d587d4b69b4 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sat, 19 Aug 2017 21:41:19 -0500 Subject: [PATCH 092/114] Update redhat.rst --- docs/installationguide/redhat.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installationguide/redhat.rst b/docs/installationguide/redhat.rst index 63a307e21..fbbb7a5d8 100644 --- a/docs/installationguide/redhat.rst +++ b/docs/installationguide/redhat.rst @@ -132,7 +132,7 @@ Your build environment is now set up. Build from SRPM *************** -To continue, you need a ZoneMinder SRPM. If you wish to rebuild a ZoneMinder release, then browse the `RPM Fusion site `_. If instead you wish to rebuild the latest source rpm from our master branch then browse the `Zmrepo site `_. +To continue, you need a ZoneMinder SRPM. If you wish to rebuild a ZoneMinder release, then browse the `RPM Fusion site `_. If instead you wish to rebuild the latest source rpm from our master branch then browse the `Zmrepo site `_. For this example, I'll use one of the source rpms from zmrepo: From 5030254ba053e557172c1a87982c370314671b4a Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sun, 20 Aug 2017 20:12:18 -0500 Subject: [PATCH 093/114] build f26 packages with my docker repo The packpack project does not provide a fedora 26 docker image so I made my own. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 3ec7a200a..4967483a2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,6 +28,7 @@ env: - OS=el DIST=6 - OS=el DIST=7 - OS=fedora DIST=25 + - OS=fedora DIST=26 DOCKER_REPO=knnniggett/packpack - OS=ubuntu DIST=trusty - OS=ubuntu DIST=xenial - OS=ubuntu DIST=trusty ARCH=i386 From cf8560b64805b5867c04144e0ea517c02a5a658a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 21 Aug 2017 10:15:56 -0400 Subject: [PATCH 094/114] fix duration if it's negative --- src/zm_videostore.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index cba27cef6..dc943291a 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -650,7 +650,6 @@ int VideoStore::writeVideoFramePacket( AVPacket *ipkt ) { duration = av_rescale_q( ipkt->pts - video_last_pts, video_input_stream->time_base, video_output_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; } } From 431ec3ea7560741a16864634c42d1646685dbd21 Mon Sep 17 00:00:00 2001 From: jethornton Date: Mon, 21 Aug 2017 10:25:44 -0500 Subject: [PATCH 095/114] Update faq.rst (#1970) The memory math is confusing and incorrect. Original posted added a 5th camera but did not update the final memory size or explain how they arrived at that value. --- docs/faq.rst | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/docs/faq.rst b/docs/faq.rst index 9228274d7..87421ddb9 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -61,7 +61,7 @@ In *general* a good estimate of memory required would be: :: - Min Memory = 1.2 * ((image-width*image-height*image buffer size*target color space*number of cameras/8/1024/1024 ) + Min Bits of Memory = 20% overhead * (image-width*image-height*image buffer size*target color space*number of cameras) Where: * image-width and image-height are the width and height of images that your camera is configured for (in my case, 1280x960). This value is in the Source tab for each monitor @@ -69,11 +69,18 @@ Where: * target color space is the color depth - 8bit, 24bit or 32bit. It's again in the source tab of each monitor The 1.2 at the start is basically adding 20% on top of the calculation to account for image/stream overheads (this is an estimate) -So let's do the math. If we have 4 cameras running at 1280x960 with 32bit color space and one camera running at 640x480 with 8bit greyscale color space, the system would require: +The math breakdown for 4 cameras running at 1280x960 capture, 50 frame buffer, 24 bit color space: +:: + 1280*960 = 1,228,800 (bits) + 1,228,800 * 24 = 2,359,296,000 (bits) + 2,359,296,000 * 50 = 5,898,240,000 (bits) + 5,898,240,000 * 4 = 7,077,888,000 (bits) + 7,077,888,000 / 8 = 884,736,000 (bytes) + 884,736,000 / 1000 = 884,736 (Kilobytes) + 884,736 / 1000 = 864 (Megabytes) + 864 / 1000 = 0.9 (Gigabyte) -``1.2 * ((1280*960*50*32*4/8/1024/1024 ) + (640 *480 *50*8/8 /1024/1024))`` - -Or, around 900MB of memory. +Around 900MB of memory. So if you have 2GB of memory, you should be all set. Right? **Not, really**: From ac5d1738eaec2ff5ac0e74bf371aab5f8e799eb6 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Mon, 21 Aug 2017 10:27:11 -0500 Subject: [PATCH 096/114] allow changing of the timestamp char code delimeter (#1972) --- .../lib/ZoneMinder/ConfigData.pm.in | 19 +++++++++++++++++++ src/zm_monitor.cpp | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in index 43ff70eea..6df8a9927 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/ConfigData.pm.in @@ -700,6 +700,25 @@ our @options = ( type => $types{boolean}, category => 'config', }, + { + name => 'ZM_TIMESTAMP_CODE_CHAR', + default => '%', + description => 'Character to used to identify timestamp codes', + help => q` + There are a few codes one can use to tell ZoneMinder to insert + data into the timestamp of each image. Traditionally, the + percent (%) character has been used to identify these codes since + the current character codes do not conflict with the strftime + codes, which can also be used in the timestamp. While this works + well for Linux, this does not work well for BSD operating systems. + Changing the default character to something else, such as an + exclamation point (!), resolves the issue. Note this only affects + the timestamp codes built into ZoneMinder. It has no effect on + the family of strftime codes one can use. + `, + type => $types{string}, + category => 'config', + }, { name => 'ZM_CPU_EXTENSIONS', default => 'yes', diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 56b4be9d1..47cda3cbd 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -2941,7 +2941,7 @@ void Monitor::TimestampImage( Image *ts_image, const struct timeval *ts_time ) c const char *s_ptr = label_time_text; char *d_ptr = label_text; while ( *s_ptr && ((d_ptr-label_text) < (unsigned int)sizeof(label_text)) ) { - if ( *s_ptr == '%' ) { + if ( *s_ptr == config.timestamp_code_char[0] ) { bool found_macro = false; switch ( *(s_ptr+1) ) { case 'N' : From 613bbfb65bb18206542f5dba50e618d70d5e94c3 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Mon, 21 Aug 2017 11:02:28 -0500 Subject: [PATCH 097/114] arm neon-check "uname -m" if CMAKE_SYSTEM_PROCESSOR is not what we expect (#1966) * arm neon - check "uname -m" if CMAKE_SYSTEM_PROCESSOR is not what we expect * skip arm neon check it not on linux --- CMakeLists.txt | 46 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 834c2a1af..e6fea0e6d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,20 +69,38 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/") # GCC below 6.0 doesn't support __target__("fpu=neon") attribute, required for compiling ARM Neon code, otherwise compilation fails. # Must use -mfpu=neon compiler flag instead, but only do that for processors that support neon, otherwise strip the neon code alltogether, # because passing -fmpu=neon is unsafe to processors that don't support neon -IF(CMAKE_SYSTEM_PROCESSOR MATCHES "^arm" AND CMAKE_SYSTEM_NAME MATCHES "Linux") - IF(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0) - EXEC_PROGRAM(grep ARGS " neon " "/proc/cpuinfo" OUTPUT_VARIABLE neonoutput RETURN_VALUE neonresult) - IF(neonresult EQUAL 0) - set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -mfpu=neon") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -mfpu=neon") - set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -mfpu=neon") - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -mfpu=neon") - ELSE(neonresult EQUAL 0) - add_definitions(-DZM_STRIP_NEON=1) - message(STATUS "ARM Neon is not available on this processor. Neon functions will be absent") - ENDIF(neonresult EQUAL 0) - ENDIF(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0) -ENDIF(CMAKE_SYSTEM_PROCESSOR MATCHES "^arm" AND CMAKE_SYSTEM_NAME MATCHES "Linux") + +# Arm neon support only tested on Linux. If your arm hardware is running a non-Linux distro and is using gcc then contact us. +IF (CMAKE_SYSTEM_NAME MATCHES "Linux") + string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" ZM_SYSTEM_PROC) + IF((ZM_SYSTEM_PROC STREQUAL "") OR (ZM_SYSTEM_PROC STREQUAL "unknown")) + execute_process(COMMAND uname -m OUTPUT_VARIABLE ZM_SYSTEM_PROC ERROR_VARIABLE ZM_SYSTEM_PROC_ERR) + + # maybe make the following error checks fatal + IF(ZM_SYSTEM_PROC_ERR) + message(WARNING "\nAn error occurred while attempting to determine the system processor:\n${ZM_SYSTEM_PROC_ERR}") + ENDIF(ZM_SYSTEM_PROC_ERR) + IF(NOT ZM_SYSTEM_PROC) + message(WARNING "\nUnable to determine the system processor. This may cause a build failure.\n") + ENDIF(ZM_SYSTEM_PROC) + + ENDIF((ZM_SYSTEM_PROC STREQUAL "") OR (ZM_SYSTEM_PROC STREQUAL "unknown")) + + IF(ZM_SYSTEM_PROC MATCHES "^arm") + IF(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0) + EXEC_PROGRAM(grep ARGS " neon " "/proc/cpuinfo" OUTPUT_VARIABLE neonoutput RETURN_VALUE neonresult) + IF(neonresult EQUAL 0) + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -mfpu=neon") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -mfpu=neon") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -mfpu=neon") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -mfpu=neon") + ELSE(neonresult EQUAL 0) + add_definitions(-DZM_STRIP_NEON=1) + message(STATUS "ARM Neon is not available on this processor. Neon functions will be absent") + ENDIF(neonresult EQUAL 0) + ENDIF(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0) + ENDIF(ZM_SYSTEM_PROC MATCHES "^arm") +ENDIF (CMAKE_SYSTEM_NAME MATCHES "Linux") # Modules that we need: include (GNUInstallDirs) From 52603b24c097f02c9abd58527405aa21e86dffab Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Mon, 21 Aug 2017 13:35:57 -0500 Subject: [PATCH 098/114] Update .travis.yml Add 32bit centos builds using my docker repo --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 4967483a2..08e086955 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,6 +26,7 @@ addons: env: matrix: - OS=el DIST=6 + - OS=el DIST=6 ARCH=i386 DOCKER_REPO=knnniggett/packpack - OS=el DIST=7 - OS=fedora DIST=25 - OS=fedora DIST=26 DOCKER_REPO=knnniggett/packpack From 160641563fc9f423b44e8ac988bd6adf6008a6eb Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Mon, 21 Aug 2017 18:50:30 -0500 Subject: [PATCH 099/114] packpack - add missing $parms var --- utils/packpack/startpackpack.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/packpack/startpackpack.sh b/utils/packpack/startpackpack.sh index e911630ab..4bf9e9ff6 100755 --- a/utils/packpack/startpackpack.sh +++ b/utils/packpack/startpackpack.sh @@ -236,7 +236,7 @@ execpackpack () { if [ "${TRAVIS}" == "true" ]; then utils/packpack/heartbeat.sh & mypid=$! - packpack/packpack > buildlog.txt 2>&1 + packpack/packpack $parms > buildlog.txt 2>&1 kill $mypid tail -n 3000 buildlog.txt | grep -v ONVIF else From 9b952595679100d05408ddd8aad64ade9f5edddb Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 22 Aug 2017 09:33:51 -0400 Subject: [PATCH 100/114] fix deleting monitor, but passing an event Id to deleteEvent instead of a hash consisting of just the Id --- web/includes/actions.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/web/includes/actions.php b/web/includes/actions.php index 281c2ac8f..374f852a2 100644 --- a/web/includes/actions.php +++ b/web/includes/actions.php @@ -439,7 +439,7 @@ Warning("Addterm"); if ( isset($changes['Name']) ) { $saferOldName = basename( $monitor['Name'] ); $saferNewName = basename( $_REQUEST['newMonitor']['Name'] ); - rename( ZM_DIR_EVENTS."/".$saferOldName, ZM_DIR_EVENTS."/".$saferNewName); + rename( ZM_DIR_EVENTS.'/'.$saferOldName, ZM_DIR_EVENTS.'/'.$saferNewName); } if ( isset($changes['Width']) || isset($changes['Height']) ) { $newW = $_REQUEST['newMonitor']['Width']; @@ -493,7 +493,7 @@ Warning("Addterm"); Error("Users with Monitors restrictions cannot create new monitors."); } $restart = true; - } + } # end if count(changes) if ( ZM_OPT_X10 ) { $x10Changes = getFormChanges( $x10Monitor, $_REQUEST['newX10Monitor'] ); @@ -530,8 +530,7 @@ Warning("Addterm"); $refreshParent = true; } // end if restart $view = 'none'; - } - if ( $action == 'delete' ) { + } elseif ( $action == 'delete' ) { if ( isset($_REQUEST['markMids']) && !$user['MonitorIds'] ) { foreach( $_REQUEST['markMids'] as $markMid ) { if ( canEdit( 'Monitors', $markMid ) ) { @@ -545,7 +544,7 @@ Warning("Addterm"); // If fast deletes are off and there are lots of events then this step may // well time out before completing, in which case zmaudit will still tidy up if ( !ZM_OPT_FAST_DELETE ) { - $markEids = dbFetchAll( 'SELECT Id FROM Events WHERE MonitorId=?', NULL, array($markMid) ); + $markEids = dbFetchAll( 'SELECT Id FROM Events WHERE MonitorId=?', 'Id', array($markMid) ); foreach( $markEids as $markEid ) deleteEvent( $markEid ); From 40cc13a903048da43062cfd04b493d7749150b37 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 22 Aug 2017 09:34:02 -0400 Subject: [PATCH 101/114] fix whitespace --- scripts/ZoneMinder/lib/ZoneMinder/Event.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm index e9af77479..32d4fba85 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm @@ -239,7 +239,7 @@ sub GenerateVideo { sub delete { my $event = $_[0]; if ( ! ( $event->{Id} and $event->{MonitorId} and $event->{StartTime} ) ) { - my ( $caller, undef, $line ) = caller; + my ( $caller, undef, $line ) = caller; Warning( "Can't Delete event $event->{Id} from Monitor $event->{MonitorId} $event->{StartTime} from $caller:$line\n" ); return; } From 9a6bfb2d0246c50d654d400c86d3c81a1b1ce51b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 22 Aug 2017 09:44:45 -0400 Subject: [PATCH 102/114] fix some quotes, double to single --- web/skins/classic/views/video.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/web/skins/classic/views/video.php b/web/skins/classic/views/video.php index 75cc8c8ed..0c7c4e153 100644 --- a/web/skins/classic/views/video.php +++ b/web/skins/classic/views/video.php @@ -83,15 +83,15 @@ if ( isset($_REQUEST['deleteIndex']) ) { if ( isset($_REQUEST['downloadIndex']) ) { $downloadIndex = validInt($_REQUEST['downloadIndex']); - header( "Pragma: public" ); - header( "Expires: 0" ); - header( "Cache-Control: must-revalidate, post-check=0, pre-check=0" ); - header( "Cache-Control: private", false ); // required by certain browsers - header( "Content-Description: File Transfer" ); + header( 'Pragma: public' ); + header( 'Expires: 0' ); + header( 'Cache-Control: must-revalidate, post-check=0, pre-check=0' ); + header( 'Cache-Control: private', false ); // required by certain browsers + header( 'Content-Description: File Transfer' ); header( 'Content-disposition: attachment; filename="'.basename($videoFiles[$downloadIndex]).'"' ); // basename is required because the video index contains the path and firefox doesn't strip the path but simply replaces the slashes with an underscore. - header( "Content-Transfer-Encoding: binary" ); - header( "Content-Type: application/force-download" ); - header( "Content-Length: ".filesize($videoFiles[$downloadIndex]) ); + header( 'Content-Transfer-Encoding: binary' ); + header( 'Content-Type: application/force-download' ); + header( 'Content-Length: '.filesize($videoFiles[$downloadIndex]) ); readfile( $videoFiles[$downloadIndex] ); exit; } From e98ea0b8916375459886732dd9f80fea8c7c9da7 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 22 Aug 2017 10:47:37 -0400 Subject: [PATCH 103/114] fix non hwaccel build --- src/zm_ffmpeg_camera.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 2a0ca36c2..49e36d232 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -747,7 +747,11 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event } if ( mVideoCodecContext->codec_id != AV_CODEC_ID_H264 ) { - Error( "Input stream is not h264. The stored event file may not be viewable in browser." ); + if ( mVideoCodecContext->codec_id == AV_CODEC_ID_H265 ) { + Debug( 1, "Input stream appears to be h265. The stored event file may not be viewable in browser." ); + } else { + Error( "Input stream is not h264. The stored event file may not be viewable in browser." ); + } } int frameComplete = false; @@ -936,6 +940,7 @@ else if ( packet.pts && video_last_pts > packet.pts ) { zm_av_packet_unref( &packet ); continue; } +#if HAVE_AVUTIL_HWCONTEXT_H if ( hwaccel ) { ret = avcodec_receive_frame( mVideoCodecContext, hwFrame ); if ( ret < 0 ) { @@ -952,6 +957,7 @@ else if ( packet.pts && video_last_pts > packet.pts ) { continue; } } else { +#endif ret = avcodec_receive_frame( mVideoCodecContext, mRawFrame ); if ( ret < 0 ) { av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); @@ -960,7 +966,9 @@ else if ( packet.pts && video_last_pts > packet.pts ) { continue; } +#if HAVE_AVUTIL_HWCONTEXT_H } +#endif frameComplete = 1; # else From eb5cee7f3e8c5e0f363b451511c3d44318ce525c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 23 Aug 2017 10:14:06 -0400 Subject: [PATCH 104/114] use ifdef around uses of AV_CODEC_ID_H265 and fix google code style --- src/zm_ffmpeg_camera.cpp | 4 +++ src/zm_videostore.cpp | 56 ++++++++++++++++++++-------------------- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 49e36d232..259d65fa6 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -747,11 +747,15 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event } if ( mVideoCodecContext->codec_id != AV_CODEC_ID_H264 ) { +#ifdef AV_CODEC_ID_H265 if ( mVideoCodecContext->codec_id == AV_CODEC_ID_H265 ) { Debug( 1, "Input stream appears to be h265. The stored event file may not be viewable in browser." ); } else { +#endif Error( "Input stream is not h264. The stored event file may not be viewable in browser." ); +#ifdef AV_CODEC_ID_H265 } +#endif } int frameComplete = false; diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index dc943291a..90876c064 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -43,7 +43,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) video_input_context = avcodec_alloc_context3( NULL ); - avcodec_parameters_to_context( video_input_context, video_input_stream->codecpar ); + avcodec_parameters_to_context(video_input_context, video_input_stream->codecpar); //zm_dump_codecpar( video_input_stream->codecpar ); #else video_input_context = video_input_stream->codec; @@ -91,7 +91,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, video_output_context = avcodec_alloc_context3( NULL ); // Copy params from inputstream to context - ret = avcodec_parameters_to_context( video_output_context, video_input_stream->codecpar ); + ret = avcodec_parameters_to_context(video_output_context, video_input_stream->codecpar); if ( ret < 0 ) { Error( "Could not initialize context parameteres"); return; @@ -809,8 +809,8 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) { &data_present, ipkt)) < 0 ) { Error( "Could not decode frame (error '%s')\n", av_make_error_string(ret).c_str()); - dumpPacket( ipkt ); - av_frame_free( &input_frame ); + dumpPacket(ipkt); + av_frame_free(&input_frame); return 0; } if ( ! data_present ) { @@ -828,14 +828,14 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) { input_frame->data, 0, input_frame->nb_samples )) < 0 ) { - Error( "Could not resample frame (error '%s')\n", + Error("Could not resample frame (error '%s')\n", av_make_error_string(ret).c_str()); - av_frame_unref( input_frame ); + av_frame_unref(input_frame); return 0; } - av_frame_unref( input_frame ); + av_frame_unref(input_frame); - int samples_available = avresample_available( resample_context ); + int samples_available = avresample_available(resample_context); if ( samples_available < frame_size ) { Debug(1, "Not enough samples yet (%d)", samples_available); @@ -844,11 +844,11 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) { Debug(3, "Output_frame samples (%d)", output_frame->nb_samples ); // Read a frame audio data from the resample fifo - if ( avresample_read( resample_context, output_frame->data, frame_size ) != frame_size ) { + if ( avresample_read(resample_context, output_frame->data, frame_size) != frame_size ) { Warning( "Error reading resampled audio: " ); return 0; } - Debug(2, "Frame: samples(%d), format(%d), sample_rate(%d), channel layout(%d)", + Debug(2, "Frame: samples(%d), format(%d), sample_rate(%d), channel layout(%d)", output_frame->nb_samples, output_frame->format, output_frame->sample_rate, @@ -859,8 +859,8 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) { Debug(5, "after init packet" ); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - if (( ret = avcodec_send_frame( audio_output_context, output_frame ) ) < 0 ) { - Error( "Could not send frame (error '%s')", + if ( (ret = avcodec_send_frame(audio_output_context, output_frame)) < 0 ) { + Error("Could not send frame (error '%s')", av_make_error_string(ret).c_str()); zm_av_packet_unref(&opkt); return 0; @@ -868,28 +868,28 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) { //av_frame_unref( output_frame ); - if ( ( ret = avcodec_receive_packet( audio_output_context, &opkt ) ) < 0 ) { + if ( (ret = avcodec_receive_packet( audio_output_context, &opkt )) < 0 ) { if ( AVERROR(EAGAIN) == ret ) { - // THe codec may need more samples than it has, perfectly valid - Debug( 3, "Could not recieve packet (error '%s')", - av_make_error_string(ret).c_str()); + // THe codec may need more samples than it has, perfectly valid + Debug(3, "Could not recieve packet (error '%s')", + av_make_error_string(ret).c_str()); } else { - Error( "Could not recieve packet (error %d = '%s')", ret, - av_make_error_string(ret).c_str()); + Error("Could not recieve packet (error %d = '%s')", ret, + av_make_error_string(ret).c_str()); } zm_av_packet_unref(&opkt); - av_frame_unref( input_frame ); + av_frame_unref(input_frame); //av_frame_unref( output_frame ); return 0; } #else - if (( ret = avcodec_encode_audio2( audio_output_context, &opkt, output_frame, &data_present )) < 0) { - Error( "Could not encode frame (error '%s')", + if ( (ret = avcodec_encode_audio2(audio_output_context, &opkt, output_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 output a frame yet."); zm_av_packet_unref(&opkt); return 0; @@ -899,7 +899,7 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) { #endif } else { av_init_packet(&opkt); - Debug(5, "after init packet" ); + Debug(5, "after init packet"); opkt.data = ipkt->data; opkt.size = ipkt->size; } @@ -957,7 +957,7 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) { #endif //audio_last_dts = ipkt->dts; if ( opkt.dts > opkt.pts ) { - Debug(1,"opkt.dts(%d) must be <= opkt.pts(%d). Decompression must happen before presentation.", opkt.dts, opkt.pts ); + Debug(1, "opkt.dts(%d) must be <= opkt.pts(%d). Decompression must happen before presentation.", opkt.dts, opkt.pts); opkt.dts = opkt.pts; } @@ -969,11 +969,11 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) { opkt.duration = ipkt->duration; } //opkt.duration = av_rescale_q(ipkt->duration, audio_input_stream->time_base, audio_output_stream->time_base); - Debug( 2, "opkt.pts (%d), opkt.dts(%d) opkt.duration = (%d)", opkt.pts, opkt.dts, opkt.duration ); + Debug(2, "opkt.pts (%d), opkt.dts(%d) opkt.duration = (%d)", opkt.pts, opkt.dts, opkt.duration); // pkt.pos: byte position in stream, -1 if unknown opkt.pos = -1; - opkt.stream_index = audio_output_stream->index;//ipkt->stream_index; + opkt.stream_index = audio_output_stream->index; audio_next_dts = opkt.dts + opkt.duration; audio_next_pts = opkt.pts + opkt.duration; @@ -984,8 +984,8 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) { Error("Error writing audio frame packet: %s\n", av_make_error_string(ret).c_str()); dumpPacket(&safepkt); } else { - Debug(2,"Success writing audio frame" ); + Debug(2,"Success writing audio frame"); } zm_av_packet_unref(&opkt); return 0; -} // end int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) +} // end int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) From 732ebf6df4c42e5dd192dd93832a037c652af6c3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 23 Aug 2017 10:37:32 -0400 Subject: [PATCH 105/114] shorted some variable names and correct spacing --- src/zm_videostore.cpp | 1022 ++++++++++++++++++++++------------------- src/zm_videostore.h | 42 +- 2 files changed, 561 insertions(+), 503 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 90876c064..af5c187df 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -20,277 +20,287 @@ #define __STDC_FORMAT_MACROS 1 +#include #include #include -#include #include "zm.h" #include "zm_videostore.h" extern "C" { - #include "libavutil/time.h" +#include "libavutil/time.h" } VideoStore::VideoStore(const char *filename_in, const char *format_in, - AVStream *p_video_input_stream, - AVStream *p_audio_input_stream, - int64_t nStartTime, - Monitor * monitor - ) { - - video_input_stream = p_video_input_stream; - audio_input_stream = p_audio_input_stream; + AVStream *p_video_in_stream, + AVStream *p_audio_in_stream, int64_t nStartTime, + Monitor *monitor) { + video_in_stream = p_video_in_stream; + audio_in_stream = p_audio_in_stream; #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - video_input_context = avcodec_alloc_context3( NULL ); - avcodec_parameters_to_context(video_input_context, video_input_stream->codecpar); - //zm_dump_codecpar( video_input_stream->codecpar ); + video_in_ctx = avcodec_alloc_ctx3(NULL); + avcodec_parameters_to_ctx(video_in_ctx, + video_in_stream->codecpar); +// zm_dump_codecpar( video_in_stream->codecpar ); #else - video_input_context = video_input_stream->codec; + video_in_ctx = video_in_stream->codec; #endif - //store inputs in variables local to class + // store ins in variables local to class filename = filename_in; format = format_in; Info("Opening video storage stream %s format: %s", filename, format); - ret = avformat_alloc_output_context2(&oc, NULL, NULL, filename); - if ( ret < 0 ) { - Warning("Could not create video storage stream %s as no output context" + ret = avformat_alloc_out_ctx2(&oc, NULL, NULL, filename); + if (ret < 0) { + Warning( + "Could not create video storage stream %s as no out ctx" " could be assigned based on filename: %s", - filename, - av_make_error_string(ret).c_str() - ); + filename, av_make_error_string(ret).c_str()); } else { - Debug(4, "Success allocating output format context"); + Debug(4, "Success allocating out format ctx"); } - //Couldn't deduce format from filename, trying from format name - if ( !oc ) { - avformat_alloc_output_context2(&oc, NULL, format, filename); - if ( !oc ) { - Fatal("Could not create video storage stream %s as no output context" + // Couldn't deduce format from filename, trying from format name + if (!oc) { + avformat_alloc_out_ctx2(&oc, NULL, format, filename); + if (!oc) { + Fatal( + "Could not create video storage stream %s as no out ctx" " could not be assigned based on filename or format %s", filename, format); } else { - Debug(4, "Success alocateing output context"); + Debug(4, "Success alocateing out ctx"); } - } // end if ! oc + } // end if ! oc AVDictionary *pmetadata = NULL; - int dsr = av_dict_set(&pmetadata, "title", "Zoneminder Security Recording", 0); - if ( dsr < 0 ) Warning("%s:%d: title set failed", __FILE__, __LINE__ ); + int dsr = + av_dict_set(&pmetadata, "title", "Zoneminder Security Recording", 0); + if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__); oc->metadata = pmetadata; - output_format = oc->oformat; + out_format = oc->oformat; #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) // Since we are not re-encoding, all we have to do is copy the parameters - video_output_context = avcodec_alloc_context3( NULL ); + video_out_ctx = avcodec_alloc_ctx3(NULL); - // Copy params from inputstream to context - ret = avcodec_parameters_to_context(video_output_context, video_input_stream->codecpar); - if ( ret < 0 ) { - Error( "Could not initialize context parameteres"); + // Copy params from instream to ctx + ret = avcodec_parameters_to_ctx(video_out_ctx, + video_in_stream->codecpar); + if (ret < 0) { + Error("Could not initialize ctx parameteres"); return; } else { - zm_dump_codec( video_output_context ); + zm_dump_codec(video_out_ctx); } - - video_output_stream = avformat_new_stream( oc, NULL ); - if ( ! video_output_stream ) { + + video_out_stream = avformat_new_stream(oc, NULL); + if (!video_out_stream) { Fatal("Unable to create video out stream\n"); } else { - Debug(2, "Success creating video out stream" ); + Debug(2, "Success creating video out stream"); } - if ( ! video_output_context->codec_tag ) { - video_output_context->codec_tag = av_codec_get_tag(oc->oformat->codec_tag, video_input_context->codec_id); - Debug(2, "No codec_tag, setting to %d", video_output_context->codec_tag ); + if (!video_out_ctx->codec_tag) { + video_out_ctx->codec_tag = + av_codec_get_tag(oc->oformat->codec_tag, video_in_ctx->codec_id); + Debug(2, "No codec_tag, setting to %d", video_out_ctx->codec_tag); } - // Now copy them to the output stream - ret = avcodec_parameters_from_context( video_output_stream->codecpar, video_output_context ); - if ( ret < 0 ) { - Error( "Could not initialize stream parameteres"); + // Now copy them to the out stream + ret = avcodec_parameters_from_ctx(video_out_stream->codecpar, + video_out_ctx); + if (ret < 0) { + Error("Could not initialize stream parameteres"); return; } else { Debug(2, "Success setting parameters"); } - zm_dump_codecpar( video_output_stream->codecpar ); + zm_dump_codecpar(video_out_stream->codecpar); #else - video_output_stream = avformat_new_stream(oc, (AVCodec*)video_input_context->codec ); - if ( ! video_output_stream ) { + video_out_stream = + avformat_new_stream(oc, reinterpret_castvideo_in_ctx->codec); + if (!video_out_stream) { Fatal("Unable to create video out stream\n"); } else { - Debug(2, "Success creating video out stream" ); + Debug(2, "Success creating video out stream"); } - video_output_context = video_output_stream->codec; - ret = avcodec_copy_context( video_output_context, video_input_context ); - if (ret < 0) { - Fatal("Unable to copy input video context to output video context %s\n", - av_make_error_string(ret).c_str()); + video_out_ctx = video_out_stream->codec; + ret = avcodec_copy_ctx(video_out_ctx, video_in_ctx); + if (ret < 0) { + Fatal("Unable to copy in video ctx to out video ctx %s\n", + av_make_error_string(ret).c_str()); } else { - Debug(3, "Success copying context" ); + Debug(3, "Success copying ctx"); } - if ( ! video_output_context->codec_tag ) { + if (!video_out_ctx->codec_tag) { Debug(2, "No codec_tag"); - if (! oc->oformat->codec_tag - || av_codec_get_id (oc->oformat->codec_tag, video_input_context->codec_tag) == video_output_context->codec_id - || av_codec_get_tag(oc->oformat->codec_tag, video_input_context->codec_id) <= 0) { + if (!oc->oformat->codec_tag || + av_codec_get_id(oc->oformat->codec_tag, + video_in_ctx->codec_tag) == + video_out_ctx->codec_id || + av_codec_get_tag(oc->oformat->codec_tag, + video_in_ctx->codec_id) <= 0) { Warning("Setting codec tag"); - video_output_context->codec_tag = video_input_context->codec_tag; + video_out_ctx->codec_tag = video_in_ctx->codec_tag; } } #endif - // Just copy them from the input, no reason to choose different - video_output_context->time_base = video_input_context->time_base; - video_output_stream->time_base = video_input_stream->time_base; - - Debug(3, "Time bases: VIDEO input stream (%d/%d) input codec: (%d/%d) output stream: (%d/%d) output codec (%d/%d)", - video_input_stream->time_base.num, - video_input_stream->time_base.den, - video_input_context->time_base.num, - video_input_context->time_base.den, - video_output_stream->time_base.num, - video_output_stream->time_base.den, - video_output_context->time_base.num, - video_output_context->time_base.den - ); + // Just copy them from the in, no reason to choose different + video_out_ctx->time_base = video_in_ctx->time_base; + video_out_stream->time_base = video_in_stream->time_base; + Debug(3, + "Time bases: VIDEO in stream (%d/%d) in codec: (%d/%d) out " + "stream: (%d/%d) out codec (%d/%d)", + video_in_stream->time_base.num, video_in_stream->time_base.den, + video_in_ctx->time_base.num, video_in_ctx->time_base.den, + video_out_stream->time_base.num, video_out_stream->time_base.den, + video_out_ctx->time_base.num, + video_out_ctx->time_base.den); if (oc->oformat->flags & AVFMT_GLOBALHEADER) { - video_output_context->flags |= CODEC_FLAG_GLOBAL_HEADER; + video_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; } - Monitor::Orientation orientation = monitor->getOrientation(); - Debug(3, "Have orientation" ); - if ( orientation ) { - if ( orientation == Monitor::ROTATE_0 ) { - - } else if ( orientation == Monitor::ROTATE_90 ) { - dsr = av_dict_set( &video_output_stream->metadata, "rotate", "90", 0); - if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__ ); - } else if ( orientation == Monitor::ROTATE_180 ) { - dsr = av_dict_set( &video_output_stream->metadata, "rotate", "180", 0); - if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__ ); - } else if ( orientation == Monitor::ROTATE_270 ) { - dsr = av_dict_set( &video_output_stream->metadata, "rotate", "270", 0); - if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__ ); + Monitor::Orientation orientation = monitor->getOrientation(); + Debug(3, "Have orientation"); + if (orientation) { + if (orientation == Monitor::ROTATE_0) { + } else if (orientation == Monitor::ROTATE_90) { + dsr = av_dict_set(&video_out_stream->metadata, "rotate", "90", 0); + if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__); + } else if (orientation == Monitor::ROTATE_180) { + dsr = av_dict_set(&video_out_stream->metadata, "rotate", "180", 0); + if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__); + } else if (orientation == Monitor::ROTATE_270) { + dsr = av_dict_set(&video_out_stream->metadata, "rotate", "270", 0); + if (dsr < 0) Warning("%s:%d: title set failed", __FILE__, __LINE__); } else { - Warning( "Unsupported Orientation(%d)", orientation ); + Warning("Unsupported Orientation(%d)", orientation); } } - converted_input_samples = NULL; - audio_output_codec = NULL; - audio_input_context = NULL; - audio_output_stream = NULL; - input_frame = NULL; - output_frame = NULL; + converted_in_samples = NULL; + audio_out_codec = NULL; + audio_in_ctx = NULL; + audio_out_stream = NULL; + in_frame = NULL; + out_frame = NULL; #ifdef HAVE_LIBAVRESAMPLE - resample_context = NULL; + resample_ctx = NULL; #endif - if ( audio_input_stream ) { - Debug(3, "Have audio stream" ); + if (audio_in_stream) { + Debug(3, "Have audio stream"); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - audio_input_context = avcodec_alloc_context3( NULL ); - ret = avcodec_parameters_to_context( audio_input_context, audio_input_stream->codecpar ); + audio_in_ctx = avcodec_alloc_ctx3(NULL); + ret = avcodec_parameters_to_ctx(audio_in_ctx, + audio_in_stream->codecpar); #else - audio_input_context = audio_input_stream->codec; + audio_in_ctx = audio_in_stream->codec; #endif - if ( audio_input_context->codec_id != AV_CODEC_ID_AAC ) { - static char error_buffer[256]; - avcodec_string(error_buffer, sizeof(error_buffer), audio_input_context, 0 ); - Debug(2, "Got something other than AAC (%s)", error_buffer ); + 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); + Debug(2, "Got something other than AAC (%s)", error_buffer); - - if ( ! setup_resampler() ) { + if (!setup_resampler()) { return; } } else { - Debug(3, "Got AAC" ); + Debug(3, "Got AAC"); - audio_output_stream = avformat_new_stream(oc, (AVCodec*)audio_input_context->codec); - if ( ! audio_output_stream ) { + audio_out_stream = + avformat_new_stream(oc, reinterpret_castaudio_in_ctx->codec); + if (!audio_out_stream) { Error("Unable to create audio out stream\n"); - audio_output_stream = NULL; + audio_out_stream = NULL; } else { Debug(2, "setting parameters"); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - audio_output_context = avcodec_alloc_context3( audio_output_codec ); - // Copy params from inputstream to context - ret = avcodec_parameters_to_context( audio_output_context, audio_input_stream->codecpar ); - if ( ret < 0 ) { - Error("Unable to copy audio params to context %s\n", av_make_error_string(ret).c_str()); + audio_out_ctx = avcodec_alloc_ctx3(audio_out_codec); + // Copy params from instream to ctx + ret = avcodec_parameters_to_ctx(audio_out_ctx, + audio_in_stream->codecpar); + if (ret < 0) { + Error("Unable to copy audio params to ctx %s\n", + av_make_error_string(ret).c_str()); } - ret = avcodec_parameters_from_context( audio_output_stream->codecpar, audio_output_context ); - if ( ret < 0 ) { - Error("Unable to copy audio params to stream %s\n", av_make_error_string(ret).c_str()); + ret = avcodec_parameters_from_ctx(audio_out_stream->codecpar, + audio_out_ctx); + if (ret < 0) { + Error("Unable to copy audio params to stream %s\n", + av_make_error_string(ret).c_str()); } - if ( ! audio_output_context->codec_tag ) { - audio_output_context->codec_tag = av_codec_get_tag(oc->oformat->codec_tag, audio_input_context->codec_id); - Debug(2, "Setting audio codec tag to %d", audio_output_context->codec_tag ); + if (!audio_out_ctx->codec_tag) { + audio_out_ctx->codec_tag = av_codec_get_tag( + oc->oformat->codec_tag, audio_in_ctx->codec_id); + Debug(2, "Setting audio codec tag to %d", + audio_out_ctx->codec_tag); } #else - audio_output_context = audio_output_stream->codec; - ret = avcodec_copy_context(audio_output_context, audio_input_context); - audio_output_context->codec_tag = 0; + audio_out_ctx = audio_out_stream->codec; + ret = avcodec_copy_ctx(audio_out_ctx, audio_in_ctx); + audio_out_ctx->codec_tag = 0; #endif if (ret < 0) { - Error("Unable to copy audio context %s\n", av_make_error_string(ret).c_str()); - audio_output_stream = NULL; + Error("Unable to copy audio ctx %s\n", + av_make_error_string(ret).c_str()); + audio_out_stream = NULL; } else { - if ( audio_output_context->channels > 1 ) { + if (audio_out_ctx->channels > 1) { Warning("Audio isn't mono, changing it."); - audio_output_context->channels = 1; + audio_out_ctx->channels = 1; } else { Debug(3, "Audio is mono"); } - } - } // end if audio_output_stream - } // end if is AAC + } + } // end if audio_out_stream + } // end if is AAC - if ( audio_output_stream ) { + if (audio_out_stream) { if (oc->oformat->flags & AVFMT_GLOBALHEADER) { - audio_output_context->flags |= CODEC_FLAG_GLOBAL_HEADER; + audio_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; } } + } // end if audio_in_stream - } // end if audio_input_stream - - /* open the output file, if needed */ - if (!(output_format->flags & AVFMT_NOFILE)) { - ret = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE,NULL,NULL); + /* open the out file, if needed */ + if (!(out_format->flags & AVFMT_NOFILE)) { + ret = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE, NULL, NULL); if (ret < 0) { - Fatal("Could not open output file '%s': %s\n", filename, - av_make_error_string(ret).c_str()); + Fatal("Could not open out file '%s': %s\n", filename, + av_make_error_string(ret).c_str()); } } - //os->ctx_inited = 1; - //avio_flush(ctx->pb); - //av_dict_free(&opts); - zm_dump_stream_format( oc, 0, 0, 1 ); - if ( audio_output_stream ) - zm_dump_stream_format( oc, 1, 0, 1 ); + // os->ctx_inited = 1; + // avio_flush(ctx->pb); + // av_dict_free(&opts); + zm_dump_stream_format(oc, 0, 0, 1); + if (audio_out_stream) zm_dump_stream_format(oc, 1, 0, 1); - AVDictionary * opts = NULL; - //av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0); - //av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0); - //av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov+default_base_moof", 0); - if ((ret = avformat_write_header( oc, &opts )) < 0) { - //if ((ret = avformat_write_header(oc, &opts)) < 0) { + AVDictionary *opts = NULL; + // av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0); + // av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0); + // av_dict_set(&opts, "movflags", + // "frag_keyframe+empty_moov+default_base_moof", 0); + if ((ret = avformat_write_header(oc, &opts)) < 0) { + // if ((ret = avformat_write_header(oc, &opts)) < 0) { Warning("Unable to set movflags to frag_custom+dash+delay_moov"); /* Write the stream header, if any. */ ret = avformat_write_header(oc, NULL); @@ -298,12 +308,10 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, Warning("some options not set\n"); } if (ret < 0) { - Error("Error occurred when writing output file header to %s: %s\n", - filename, - av_make_error_string(ret).c_str()); + Error("Error occurred when writing out file header to %s: %s\n", + filename, av_make_error_string(ret).c_str()); } - if ( opts ) - av_dict_free(&opts); + if (opts) av_dict_free(&opts); video_last_pts = 0; video_last_dts = 0; @@ -313,108 +321,116 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, video_next_dts = 0; audio_next_pts = 0; audio_next_dts = 0; +} // VideoStore::VideoStore -} // VideoStore::VideoStore - - -VideoStore::~VideoStore(){ - if ( audio_output_codec ) { - // The codec queues data. We need to send a flush command and output whatever we get. Failures are not fatal. +VideoStore::~VideoStore() { + if (audio_out_codec) { + // The codec queues data. We need to send a flush command and out + // whatever we get. Failures are not fatal. AVPacket pkt; av_init_packet(&pkt); - while ( 1 ) { + while (1) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) // Put encoder into flushing mode - avcodec_send_frame( audio_output_context, NULL ); - ret = avcodec_receive_packet( audio_output_context, &pkt ); - if ( ret < 0 ) { - if ( AVERROR_EOF != ret ) { - Error("ERror encoding audio while flushing (%d) (%s)", ret, av_err2str( ret )); + avcodec_send_frame(audio_out_ctx, NULL); + ret = avcodec_receive_packet(audio_out_ctx, &pkt); + if (ret < 0) { + if (AVERROR_EOF != ret) { + Error("ERror encoding audio while flushing (%d) (%s)", ret, + av_err2str(ret)); } break; } #else int got_packet = 0; - ret = avcodec_encode_audio2( audio_output_context, &pkt, NULL, &got_packet ); - if ( ret < 0 ) { - Error("ERror encoding audio while flushing (%d) (%s)", ret, av_err2str( ret )); + ret = + avcodec_encode_audio2(audio_out_ctx, &pkt, NULL, &got_packet); + if (ret < 0) { + Error("ERror encoding audio while flushing (%d) (%s)", ret, + av_err2str(ret)); break; } - Debug(1, "Have audio encoder, need to flush it's output"); - if ( ! got_packet ) { + Debug(1, "Have audio encoder, need to flush it's out"); + if (!got_packet) { break; } #endif - Debug(2, "writing flushed packet pts(%d) dts(%d) duration(%d)", pkt.pts, pkt.dts, pkt.duration); + Debug(2, "writing flushed packet pts(%d) dts(%d) duration(%d)", pkt.pts, + pkt.dts, pkt.duration); pkt.pts = audio_next_pts; pkt.dts = audio_next_dts; - if ( pkt.duration > 0 ) - pkt.duration = av_rescale_q(pkt.duration, audio_output_context->time_base, audio_output_stream->time_base); + if (pkt.duration > 0) + pkt.duration = + av_rescale_q(pkt.duration, audio_out_ctx->time_base, + audio_out_stream->time_base); audio_next_pts += pkt.duration; audio_next_dts += pkt.duration; - Debug(2, "writing flushed packet pts(%d) dts(%d) duration(%d)", pkt.pts, pkt.dts, pkt.duration); - pkt.stream_index = audio_output_stream->index; - av_interleaved_write_frame( oc, &pkt ); - zm_av_packet_unref( &pkt ); - } // while have buffered frames - } // end if audio_output_codec + Debug(2, "writing flushed packet pts(%d) dts(%d) duration(%d)", pkt.pts, + pkt.dts, pkt.duration); + pkt.stream_index = audio_out_stream->index; + av_interleaved_write_frame(oc, &pkt); + zm_av_packet_unref(&pkt); + } // while have buffered frames + } // end if audio_out_codec // Flush Queues - av_interleaved_write_frame( oc, NULL ); + av_interleaved_write_frame(oc, NULL); /* Write the trailer before close */ - if ( int rc = av_write_trailer(oc) ) { - Error("Error writing trailer %s", av_err2str( rc ) ); + if (int rc = av_write_trailer(oc)) { + Error("Error writing trailer %s", av_err2str(rc)); } else { Debug(3, "Sucess Writing trailer"); } // I wonder if we should be closing the file first. - // I also wonder if we really need to be doing all the context allocation/de-allocation constantly, or whether we can just re-use it. Just do a file open/close/writeheader/etc. + // I also wonder if we really need to be doing all the ctx + // allocation/de-allocation constantly, or whether we can just re-use it. + // Just do a file open/close/writeheader/etc. // What if we were only doing audio recording? - if ( video_output_stream ) { - avcodec_close(video_output_context); - video_output_context = NULL; - Debug(4, "Success freeing video_output_context"); + if (video_out_stream) { + avcodec_close(video_out_ctx); + video_out_ctx = NULL; + Debug(4, "Success freeing video_out_ctx"); } - if (audio_output_stream) { - avcodec_close(audio_output_context); - audio_output_context = NULL; + if (audio_out_stream) { + avcodec_close(audio_out_ctx); + audio_out_ctx = NULL; #ifdef HAVE_LIBAVRESAMPLE - if ( resample_context ) { - avresample_close( resample_context ); - avresample_free( &resample_context ); + if (resample_ctx) { + avresample_close(resample_ctx); + avresample_free(&resample_ctx); } - if ( input_frame ) { - av_frame_free( &input_frame ); - input_frame = NULL; + if (in_frame) { + av_frame_free(&in_frame); + in_frame = NULL; } - if ( output_frame ) { - av_frame_free( &output_frame ); - output_frame = NULL; + if (out_frame) { + av_frame_free(&out_frame); + out_frame = NULL; } - if ( converted_input_samples ) { - av_free( converted_input_samples ); - converted_input_samples =NULL; + if (converted_in_samples) { + av_free(converted_in_samples); + converted_in_samples = NULL; } #endif } // WHen will be not using a file ? - if (!(output_format->flags & AVFMT_NOFILE)) { - /* Close the output file. */ - if ( int rc = avio_close(oc->pb) ) { - Error("Error closing avio %s", av_err2str( rc ) ); + if (!(out_format->flags & AVFMT_NOFILE)) { + /* Close the out file. */ + if (int rc = avio_close(oc->pb)) { + Error("Error closing avio %s", av_err2str(rc)); } } else { Debug(3, "Not closing avio because we are not writing to a file."); } /* free the stream */ - avformat_free_context(oc); + avformat_free_ctx(oc); } bool VideoStore::setup_resampler() { @@ -422,142 +438,159 @@ bool VideoStore::setup_resampler() { 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_input_codec = avcodec_find_decoder(audio_input_stream->codecpar->codec_id); + // 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); #else - AVCodec *audio_input_codec = avcodec_find_decoder(audio_input_context->codec_id); + AVCodec *audio_in_codec = + avcodec_find_decoder(audio_in_ctx->codec_id); #endif - ret = avcodec_open2( audio_input_context, audio_input_codec, NULL ); - if ( ret < 0 ) { - Error("Can't open input codec!"); + ret = avcodec_open2(audio_in_ctx, audio_in_codec, NULL); + if (ret < 0) { + Error("Can't open in codec!"); return false; } - audio_output_codec = avcodec_find_encoder(AV_CODEC_ID_AAC); - if ( ! audio_output_codec ) { + audio_out_codec = avcodec_find_encoder(AV_CODEC_ID_AAC); + if (!audio_out_codec) { Error("Could not find codec for AAC"); return false; } - Debug(2, "Have audio output codec"); + Debug(2, "Have audio out codec"); - //audio_output_context = audio_output_stream->codec; - audio_output_context = avcodec_alloc_context3( audio_output_codec ); + // audio_out_ctx = audio_out_stream->codec; + audio_out_ctx = avcodec_alloc_ctx3(audio_out_codec); - if ( ! audio_output_context ) { - Error( "could not allocate codec context for AAC\n"); - audio_output_stream = NULL; + if (!audio_out_ctx) { + Error("could not allocate codec ctx for AAC\n"); + audio_out_stream = NULL; return false; } - Debug(2, "Have audio_output_context"); + Debug(2, "Have audio_out_ctx"); /* put sample parameters */ - audio_output_context->bit_rate = audio_input_context->bit_rate; - audio_output_context->sample_rate = audio_input_context->sample_rate; - audio_output_context->channels = audio_input_context->channels; - audio_output_context->channel_layout = audio_input_context->channel_layout; - audio_output_context->sample_fmt = audio_input_context->sample_fmt; - audio_output_context->refcounted_frames = 1; + audio_out_ctx->bit_rate = audio_in_ctx->bit_rate; + audio_out_ctx->sample_rate = audio_in_ctx->sample_rate; + audio_out_ctx->channels = audio_in_ctx->channels; + audio_out_ctx->channel_layout = audio_in_ctx->channel_layout; + audio_out_ctx->sample_fmt = audio_in_ctx->sample_fmt; + audio_out_ctx->refcounted_frames = 1; - if ( audio_output_codec->supported_samplerates ) { + if (audio_out_codec->supported_samplerates) { int found = 0; - for ( unsigned int i = 0; audio_output_codec->supported_samplerates[i]; i++) { - if ( audio_output_context->sample_rate == audio_output_codec->supported_samplerates[i] ) { + for (unsigned 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_output_context->sample_rate = audio_output_codec->supported_samplerates[0]; - Debug(1, "Sampel rate is no good, setting to (%d)", audio_output_codec->supported_samplerates[0] ); + audio_out_ctx->sample_rate = + audio_out_codec->supported_samplerates[0]; + Debug(1, "Sampel rate is no good, setting to (%d)", + audio_out_codec->supported_samplerates[0]); } } - /* check that the encoder supports s16 pcm input */ - if ( ! check_sample_fmt( audio_output_codec, audio_output_context->sample_fmt ) ) { - Debug( 3, "Encoder does not support sample format %s, setting to FLTP", - av_get_sample_fmt_name( audio_output_context->sample_fmt)); - audio_output_context->sample_fmt = AV_SAMPLE_FMT_FLTP; + /* check that the encoder supports s16 pcm in */ + if (!check_sample_fmt(audio_out_codec, audio_out_ctx->sample_fmt)) { + Debug(3, "Encoder does not support sample format %s, setting to FLTP", + av_get_sample_fmt_name(audio_out_ctx->sample_fmt)); + audio_out_ctx->sample_fmt = AV_SAMPLE_FMT_FLTP; } - audio_output_context->time_base = (AVRational){ 1, audio_output_context->sample_rate }; + audio_out_ctx->time_base = + (AVRational){1, audio_out_ctx->sample_rate}; - // Now copy them to the output stream - audio_output_stream = avformat_new_stream( oc, audio_output_codec ); + // Now copy them to the out stream + audio_out_stream = avformat_new_stream(oc, audio_out_codec); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - ret = avcodec_parameters_from_context( audio_output_stream->codecpar, audio_output_context ); - if ( ret < 0 ) { - Error( "Could not initialize stream parameteres"); + ret = avcodec_parameters_from_ctx(audio_out_stream->codecpar, + audio_out_ctx); + if (ret < 0) { + Error("Could not initialize stream parameteres"); return false; - } + } #endif AVDictionary *opts = NULL; - av_dict_set( &opts, "strict", "experimental", 0); - ret = avcodec_open2( audio_output_context, audio_output_codec, &opts ); + av_dict_set(&opts, "strict", "experimental", 0); + ret = avcodec_open2(audio_out_ctx, audio_out_codec, &opts); av_dict_free(&opts); - if ( ret < 0 ) { + if (ret < 0) { av_strerror(ret, error_buffer, sizeof(error_buffer)); - Fatal( "could not open codec (%d) (%s)\n", ret, error_buffer ); - audio_output_codec = NULL; - audio_output_context = NULL; - audio_output_stream = NULL; + Fatal("could not open codec (%d) (%s)\n", ret, error_buffer); + audio_out_codec = NULL; + audio_out_ctx = NULL; + audio_out_stream = NULL; return false; - } + } - Debug(1, "Audio output bit_rate (%d) sample_rate(%d) channels(%d) fmt(%d) layout(%d) frame_size(%d)", - audio_output_context->bit_rate, - audio_output_context->sample_rate, - audio_output_context->channels, - audio_output_context->sample_fmt, - audio_output_context->channel_layout, - audio_output_context->frame_size - ); + Debug(1, + "Audio out bit_rate (%d) sample_rate(%d) channels(%d) fmt(%d) " + "layout(%d) frame_size(%d)", + audio_out_ctx->bit_rate, audio_out_ctx->sample_rate, + audio_out_ctx->channels, audio_out_ctx->sample_fmt, + audio_out_ctx->channel_layout, audio_out_ctx->frame_size); /** Create a new frame to store the audio samples. */ - if ( !(input_frame = zm_av_frame_alloc()) ) { - Error("Could not allocate input frame"); + if (!(in_frame = zm_av_frame_alloc())) { + Error("Could not allocate in frame"); return false; } /** Create a new frame to store the audio samples. */ - if ( !(output_frame = zm_av_frame_alloc()) ) { - Error("Could not allocate output frame"); - av_frame_free( &input_frame ); + if (!(out_frame = zm_av_frame_alloc())) { + Error("Could not allocate out frame"); + av_frame_free(&in_frame); return false; } // Setup the audio resampler - resample_context = avresample_alloc_context(); - if ( ! resample_context ) { - Error( "Could not allocate resample context\n"); + resample_ctx = avresample_alloc_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_input_context->channel_layout == 0 ) { - uint64_t layout = av_get_channel_layout( "mono" ); - av_opt_set_int( resample_context, "in_channel_layout", av_get_channel_layout( "mono" ), 0 ); - Debug( 1, "Bad channel layout. Need to set it to mono (%d).", layout ); + if (audio_in_ctx->channel_layout == 0) { + uint64_t layout = av_get_channel_layout("mono"); + av_opt_set_int(resample_ctx, "in_channel_layout", + av_get_channel_layout("mono"), 0); + Debug(1, "Bad channel layout. Need to set it to mono (%d).", layout); } else { - av_opt_set_int( resample_context, "in_channel_layout", audio_input_context->channel_layout, 0 ); + av_opt_set_int(resample_ctx, "in_channel_layout", + audio_in_ctx->channel_layout, 0); } - av_opt_set_int( resample_context, "in_sample_fmt", audio_input_context->sample_fmt, 0); - av_opt_set_int( resample_context, "in_sample_rate", audio_input_context->sample_rate, 0); - av_opt_set_int( resample_context, "in_channels", audio_input_context->channels,0); - //av_opt_set_int( resample_context, "out_channel_layout", audio_output_context->channel_layout, 0); - av_opt_set_int( resample_context, "out_channel_layout", av_get_channel_layout( "mono" ), 0 ); - av_opt_set_int( resample_context, "out_sample_fmt", audio_output_context->sample_fmt, 0); - av_opt_set_int( resample_context, "out_sample_rate", audio_output_context->sample_rate, 0); - av_opt_set_int( resample_context, "out_channels", audio_output_context->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", + av_get_channel_layout("mono"), 0); + av_opt_set_int(resample_ctx, "out_sample_fmt", + audio_out_ctx->sample_fmt, 0); + av_opt_set_int(resample_ctx, "out_sample_rate", + audio_out_ctx->sample_rate, 0); + av_opt_set_int(resample_ctx, "out_channels", + audio_out_ctx->channels, 0); - ret = avresample_open( resample_context ); - if ( ret < 0 ) { - Error( "Could not open resample context\n"); + ret = avresample_open(resample_ctx); + if (ret < 0) { + Error("Could not open resample ctx\n"); return false; } @@ -567,76 +600,74 @@ bool VideoStore::setup_resampler() { * Each pointer will later point to the audio samples of the corresponding * channels (although it may be NULL for interleaved formats). */ - if (!( converted_input_samples = (uint8_t *)calloc( audio_output_context->channels, sizeof(*converted_input_samples))) ) { - Error( "Could not allocate converted input sample pointers\n"); + 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_input_samples, NULL, - audio_output_context->channels, - audio_output_context->frame_size, - audio_output_context->sample_fmt, 0)) < 0) { - Error( "Could not allocate converted input samples (error '%s')\n", - av_make_error_string(ret).c_str() ); + 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_input_samples); - free(converted_input_samples); + av_freep(converted_in_samples); + free(converted_in_samples); return; } #endif - output_frame->nb_samples = audio_output_context->frame_size; - output_frame->format = audio_output_context->sample_fmt; - output_frame->channel_layout = audio_output_context->channel_layout; + out_frame->nb_samples = audio_out_ctx->frame_size; + out_frame->format = audio_out_ctx->sample_fmt; + out_frame->channel_layout = audio_out_ctx->channel_layout; - // The codec gives us the frame size, in samples, we calculate the size of the samples buffer in bytes - unsigned int audioSampleBuffer_size = av_samples_get_buffer_size( NULL, audio_output_context->channels, audio_output_context->frame_size, audio_output_context->sample_fmt, 0 ); - converted_input_samples = (uint8_t*) av_malloc( audioSampleBuffer_size ); + // The codec gives us the frame size, in samples, we calculate the size of the + // samples buffer in bytes + unsigned int audioSampleBuffer_size = av_samples_get_buffer_size( + NULL, audio_out_ctx->channels, audio_out_ctx->frame_size, + audio_out_ctx->sample_fmt, 0); + converted_in_samples = (uint8_t *)av_malloc(audioSampleBuffer_size); - if ( !converted_input_samples ) { - Error( "Could not allocate converted input sample pointers\n"); - return false; - } - - // Setup the data pointers in the AVFrame - if ( avcodec_fill_audio_frame( - output_frame, - audio_output_context->channels, - audio_output_context->sample_fmt, - (const uint8_t*) converted_input_samples, - audioSampleBuffer_size, 0 ) < 0 ) { - Error( "Could not allocate converted input sample pointers\n"); - return false; - } - - return true; -#else - Error("Not built with libavresample library. Cannot do audio conversion to AAC"); + if (!converted_in_samples) { + Error("Could not allocate converted in sample pointers\n"); return false; + } + + // Setup the data pointers in the AVFrame + if (avcodec_fill_audio_frame(out_frame, audio_out_ctx->channels, + audio_out_ctx->sample_fmt, + (const uint8_t *)converted_in_samples, + audioSampleBuffer_size, 0) < 0) { + Error("Could not allocate converted in sample pointers\n"); + return false; + } + + return true; +#else + Error( + "Not built with libavresample library. Cannot do audio conversion to " + "AAC"); + return false; #endif -} // end bool VideoStore::setup_resampler() +} // end bool VideoStore::setup_resampler() - -void VideoStore::dumpPacket( AVPacket *pkt ){ +void VideoStore::dumpPacket(AVPacket *pkt) { char b[10240]; - snprintf(b, sizeof(b), " pts: %" PRId64 ", dts: %" PRId64 ", data: %p, size: %d, sindex: %d, dflags: %04x, s-pos: %" PRId64 ", c-duration: %d\n" - , pkt->pts - , pkt->dts - , pkt->data - , pkt->size - , pkt->stream_index - , pkt->flags - , pkt->pos - , pkt->duration - ); + snprintf(b, sizeof(b), + " pts: %" PRId64 ", dts: %" PRId64 + ", data: %p, size: %d, sindex: %d, dflags: %04x, s-pos: %" PRId64 + ", c-duration: %d\n", + pkt->pts, pkt->dts, pkt->data, pkt->size, pkt->stream_index, + pkt->flags, pkt->pos, pkt->duration); Debug(1, "%s:%d:DEBUG: %s", __FILE__, __LINE__, b); } -int VideoStore::writeVideoFramePacket( AVPacket *ipkt ) { +int VideoStore::writeVideoFramePacket(AVPacket *ipkt) { av_init_packet(&opkt); opkt.pts = video_next_pts; @@ -644,22 +675,28 @@ int VideoStore::writeVideoFramePacket( AVPacket *ipkt ) { opkt.duration = 0; int duration; - if ( ! video_last_pts ) { + if (!video_last_pts) { duration = 0; } else { - duration = av_rescale_q( ipkt->pts - video_last_pts, video_input_stream->time_base, video_output_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; - } + duration = + av_rescale_q(ipkt->pts - video_last_pts, video_in_stream->time_base, + video_out_stream->time_base); + Debug(1, "duration calc: pts(%d) - last_pts(%d) = (%d)", ipkt->pts, + video_last_pts, duration); + if (duration < 0) { + duration = ipkt->duration; + } } - -//#if ( 0 && video_last_pts && ( ipkt->duration == AV_NOPTS_VALUE || ! ipkt->duration ) ) { - // Video packets don't really have a duration. Audio does. - //opkt.duration = av_rescale_q(duration, video_input_stream->time_base, video_output_stream->time_base); - //opkt.duration = 0; + + //#if ( 0 && video_last_pts && ( ipkt->duration == AV_NOPTS_VALUE || ! + //ipkt->duration ) ) { + // Video packets don't really have a duration. Audio does. + // opkt.duration = av_rescale_q(duration, video_in_stream->time_base, + // video_out_stream->time_base); + // opkt.duration = 0; //} else { - //duration = opkt.duration = av_rescale_q(ipkt->duration, video_input_stream->time_base, video_output_stream->time_base); + // duration = opkt.duration = av_rescale_q(ipkt->duration, + // video_in_stream->time_base, video_out_stream->time_base); //} video_last_pts = ipkt->pts; video_last_dts = ipkt->dts; @@ -671,14 +708,14 @@ int VideoStore::writeVideoFramePacket( AVPacket *ipkt ) { if ( ! video_last_pts ) { // This is the first packet. opkt.pts = 0; - Debug(2, "Starting video video_last_pts will become (%d)", ipkt->pts ); + Debug(2, "Starting video video_last_pts will become (%d)", ipkt->pts); } else { if ( ipkt->pts < video_last_pts ) { Debug(1, "Resetting video_last_pts from (%d) to (%d)", video_last_pts, ipkt->pts); // wrap around, need to figure out the distance FIXME having this wrong should cause a jump, but then play ok? - opkt.pts = video_next_pts + av_rescale_q( ipkt->pts, video_input_stream->time_base, video_output_stream->time_base); + opkt.pts = video_next_pts + av_rescale_q( ipkt->pts, video_in_stream->time_base, video_out_stream->time_base); } else { - opkt.pts = video_next_pts + av_rescale_q( ipkt->pts - video_last_pts, video_input_stream->time_base, video_output_stream->time_base); + opkt.pts = video_next_pts + av_rescale_q( ipkt->pts - video_last_pts, video_in_stream->time_base, video_out_stream->time_base); } } Debug(3, "opkt.pts = %d from ipkt->pts(%d) - last_pts(%d)", opkt.pts, ipkt->pts, video_last_pts); @@ -687,39 +724,42 @@ int VideoStore::writeVideoFramePacket( AVPacket *ipkt ) { Debug(3, "opkt.pts = undef"); opkt.pts = AV_NOPTS_VALUE; } - // Just because the input stream wraps, doesn't mean the output needs to. Really, if we are limiting ourselves to 10min segments I can't imagine every wrapping in the output. So need to handle input wrap, without causing output wrap. - if ( ! video_last_dts ) { + // Just because the in stream wraps, doesn't mean the out needs to. Really, if we are limiting ourselves to 10min segments I can't imagine every wrapping in the out. So need to handle in wrap, without causing out wrap. + if ( !video_last_dts ) { // This is the first packet. opkt.dts = 0; - Debug(1, "Starting video video_last_dts will become (%lu)", ipkt->dts ); + Debug(1, "Starting video video_last_dts will become (%lu)", ipkt->dts); video_last_dts = ipkt->dts; } else { - //Scale the DTS of the outgoing packet to be the correct time base + // Scale the DTS of the outgoing packet to be the correct time base if ( ipkt->dts == AV_NOPTS_VALUE ) { - // why are we using cur_dts instead of packet.dts? I think cur_dts is in AV_TIME_BASE_Q, but ipkt.dts is in video_input_stream->time_base - if ( video_input_stream->cur_dts < video_last_dts ) { - Debug(1, "Resetting video_last_dts from (%d) to (%d) p.dts was (%d)", video_last_dts, video_input_stream->cur_dts, ipkt->dts ); - opkt.dts = video_next_dts + av_rescale_q(video_input_stream->cur_dts, AV_TIME_BASE_Q, video_output_stream->time_base); + // why are we using cur_dts instead of packet.dts? I think cur_dts is in AV_TIME_BASE_Q, but ipkt.dts is in video_in_stream->time_base + if ( video_in_stream->cur_dts < video_last_dts ) { + Debug(1, "Resetting video_last_dts from (%d) to (%d) p.dts was (%d)", video_last_dts, video_in_stream->cur_dts, ipkt->dts); + opkt.dts = video_next_dts + av_rescale_q(video_in_stream->cur_dts, AV_TIME_BASE_Q, video_out_stream->time_base); } else { - opkt.dts = video_next_dts + av_rescale_q(video_input_stream->cur_dts - video_last_dts, AV_TIME_BASE_Q, video_output_stream->time_base); + opkt.dts = video_next_dts + av_rescale_q(video_in_stream->cur_dts - video_last_dts, AV_TIME_BASE_Q, video_out_stream->time_base); } - Debug(3, "opkt.dts = %d from video_input_stream->cur_dts(%d) - previus_dts(%d)", opkt.dts, video_input_stream->cur_dts, video_last_dts ); - video_last_dts = video_input_stream->cur_dts; + Debug(3, "opkt.dts = %d from video_in_stream->cur_dts(%d) - previus_dts(%d)", opkt.dts, video_in_stream->cur_dts, video_last_dts); + video_last_dts = video_in_stream->cur_dts; } else { if ( ipkt->dts < video_last_dts ) { - Debug(1, "Resetting video_last_dts from (%d) to (%d)", video_last_dts, ipkt->dts ); - opkt.dts = video_next_dts + av_rescale_q( ipkt->dts, video_input_stream->time_base, video_output_stream->time_base); + Debug(1, "Resetting video_last_dts from (%d) to (%d)", video_last_dts, ipkt->dts); + opkt.dts = video_next_dts + av_rescale_q( ipkt->dts, video_in_stream->time_base, video_out_stream->time_base); } else { - opkt.dts = video_next_dts + av_rescale_q( ipkt->dts - video_last_dts, video_input_stream->time_base, video_output_stream->time_base); + opkt.dts = video_next_dts + av_rescale_q( ipkt->dts - video_last_dts, video_in_stream->time_base, video_out_stream->time_base); } - Debug(3, "opkt.dts = %d from ipkt.dts(%d) - previus_dts(%d)", opkt.dts, ipkt->dts, video_last_dts ); + Debug(3, "opkt.dts = %d from ipkt.dts(%d) - previus_dts(%d)", opkt.dts, ipkt->dts, video_last_dts); video_last_dts = ipkt->dts; } } #endif - if ( opkt.dts > opkt.pts ) { - Debug( 1, "opkt.dts(%d) must be <= opkt.pts(%d). Decompression must happen before presentation.", opkt.dts, opkt.pts ); + if (opkt.dts > opkt.pts) { + Debug(1, + "opkt.dts(%d) must be <= opkt.pts(%d). Decompression must happen " + "before presentation.", + opkt.dts, opkt.pts); opkt.dts = opkt.pts; } @@ -730,167 +770,170 @@ int VideoStore::writeVideoFramePacket( AVPacket *ipkt ) { opkt.data = ipkt->data; opkt.size = ipkt->size; - opkt.stream_index = video_output_stream->index; + opkt.stream_index = video_out_stream->index; AVPacket safepkt; - memcpy( &safepkt, &opkt, sizeof(AVPacket) ); + memcpy(&safepkt, &opkt, sizeof(AVPacket)); - Debug(1, "writing video packet keyframe(%d) pts(%d) dts(%d) duration(%d) ipkt.duration(%d)", keyframe, opkt.pts, opkt.dts, duration, ipkt->duration); - if ( (opkt.data == NULL) || (opkt.size < 1) ) { - Warning("%s:%d: Mangled AVPacket: discarding frame", __FILE__, __LINE__ ); + Debug(1, + "writing video packet keyframe(%d) pts(%d) dts(%d) duration(%d) " + "ipkt.duration(%d)", + keyframe, opkt.pts, opkt.dts, duration, ipkt->duration); + if ((opkt.data == NULL) || (opkt.size < 1)) { + Warning("%s:%d: Mangled AVPacket: discarding frame", __FILE__, __LINE__); dumpPacket(ipkt); dumpPacket(&opkt); - } else if ( (video_next_dts > 0) && (video_next_dts > opkt.dts) ) { - Warning("%s:%d: DTS out of order: %lld \u226E %lld; discarding frame", __FILE__, __LINE__, video_next_dts, opkt.dts); - video_next_dts = opkt.dts; + } else if ((video_next_dts > 0) && (video_next_dts > opkt.dts)) { + Warning("%s:%d: DTS out of order: %lld \u226E %lld; discarding frame", + __FILE__, __LINE__, video_next_dts, opkt.dts); + video_next_dts = opkt.dts; dumpPacket(&opkt); } else { - video_next_dts = opkt.dts + duration; video_next_pts = opkt.pts + duration; ret = av_interleaved_write_frame(oc, &opkt); - if ( ret < 0 ) { - // There's nothing we can really do if the frame is rejected, just drop it and get on with the next - Warning("%s:%d: Writing frame [av_interleaved_write_frame()] failed: %s(%d) ", __FILE__, __LINE__, av_make_error_string(ret).c_str(), (ret)); + if (ret < 0) { + // There's nothing we can really do if the frame is rejected, just drop it + // and get on with the next + Warning( + "%s:%d: Writing frame [av_interleaved_write_frame()] failed: %s(%d) " + " ", + __FILE__, __LINE__, av_make_error_string(ret).c_str(), (ret)); dumpPacket(&safepkt); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - zm_dump_codecpar( video_input_stream->codecpar ); - zm_dump_codecpar( video_output_stream->codecpar ); + zm_dump_codecpar(video_in_stream->codecpar); + zm_dump_codecpar(video_out_stream->codecpar); #endif } } - zm_av_packet_unref(&opkt); + zm_av_packet_unref(&opkt); return 0; +} // end int VideoStore::writeVideoFramePacket( AVPacket *ipkt ) -} // end int VideoStore::writeVideoFramePacket( AVPacket *ipkt ) - -int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) { +int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { Debug(4, "writeAudioFrame"); - if ( ! audio_output_stream ) { - Debug(1, "Called writeAudioFramePacket when no audio_output_stream"); - return 0;//FIXME -ve return codes do not free packet in ffmpeg_camera at the moment + if (!audio_out_stream) { + Debug(1, "Called writeAudioFramePacket when no audio_out_stream"); + return 0; // FIXME -ve return codes do not free packet in ffmpeg_camera at + // the moment } - if ( audio_output_codec ) { + if (audio_out_codec) { Debug(3, "Have audio codec"); #ifdef HAVE_LIBAVRESAMPLE #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - ret = avcodec_send_packet( audio_input_context, ipkt ); - if ( ret < 0 ) { + ret = avcodec_send_packet(audio_in_ctx, ipkt); + if (ret < 0) { Error("avcodec_send_packet fail %s", av_make_error_string(ret).c_str()); return 0; } - ret = avcodec_receive_frame( audio_input_context, input_frame ); - if ( ret < 0 ) { + ret = avcodec_receive_frame(audio_in_ctx, in_frame); + if (ret < 0) { Error("avcodec_receive_frame fail %s", av_make_error_string(ret).c_str()); return 0; } - Debug(2, "Input Frame: samples(%d), format(%d), sample_rate(%d), channel layout(%d)", - input_frame->nb_samples, - input_frame->format, - input_frame->sample_rate, - input_frame->channel_layout - ); + Debug(2, + "Input Frame: samples(%d), format(%d), sample_rate(%d), channel " + "layout(%d)", + in_frame->nb_samples, in_frame->format, + in_frame->sample_rate, in_frame->channel_layout); #else /** * Decode the audio frame stored in the packet. - * The input audio stream decoder is used to do this. + * The in audio stream decoder is used to do this. * If we are at the end of the file, pass an empty packet to the decoder * to flush it. */ - if ( (ret = avcodec_decode_audio4(audio_input_context, input_frame, - &data_present, ipkt)) < 0 ) { - Error( "Could not decode frame (error '%s')\n", - av_make_error_string(ret).c_str()); + 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(&input_frame); + av_frame_free(&in_frame); return 0; } - if ( ! data_present ) { + if (!data_present) { Debug(2, "Not ready to transcode a frame yet."); return 0; } #endif - int frame_size = output_frame->nb_samples; + int frame_size = out_frame->nb_samples; - // Resample the input into the audioSampleBuffer until we proceed the whole decoded data - if ( (ret = avresample_convert( resample_context, - NULL, - 0, - 0, - input_frame->data, - 0, - input_frame->nb_samples )) < 0 ) { + // Resample the in into the audioSampleBuffer until we proceed the whole + // decoded data + if ((ret = + avresample_convert(resample_ctx, NULL, 0, 0, in_frame->data, + 0, in_frame->nb_samples)) < 0) { Error("Could not resample frame (error '%s')\n", - av_make_error_string(ret).c_str()); - av_frame_unref(input_frame); + av_make_error_string(ret).c_str()); + av_frame_unref(in_frame); return 0; } - av_frame_unref(input_frame); + av_frame_unref(in_frame); - int samples_available = avresample_available(resample_context); + int samples_available = avresample_available(resample_ctx); - if ( samples_available < frame_size ) { + if (samples_available < frame_size) { Debug(1, "Not enough samples yet (%d)", samples_available); return 0; } - Debug(3, "Output_frame samples (%d)", output_frame->nb_samples ); + Debug(3, "Output_frame samples (%d)", out_frame->nb_samples); // Read a frame audio data from the resample fifo - if ( avresample_read(resample_context, output_frame->data, frame_size) != frame_size ) { - Warning( "Error reading resampled audio: " ); + if (avresample_read(resample_ctx, out_frame->data, frame_size) != + frame_size) { + Warning("Error reading resampled audio: "); return 0; } - Debug(2, "Frame: samples(%d), format(%d), sample_rate(%d), channel layout(%d)", - output_frame->nb_samples, - output_frame->format, - output_frame->sample_rate, - output_frame->channel_layout - ); + Debug(2, + "Frame: samples(%d), format(%d), sample_rate(%d), channel layout(%d)", + out_frame->nb_samples, out_frame->format, + out_frame->sample_rate, out_frame->channel_layout); av_init_packet(&opkt); - Debug(5, "after init packet" ); + Debug(5, "after init packet"); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - if ( (ret = avcodec_send_frame(audio_output_context, output_frame)) < 0 ) { + if ((ret = avcodec_send_frame(audio_out_ctx, out_frame)) < 0) { Error("Could not send frame (error '%s')", - av_make_error_string(ret).c_str()); + av_make_error_string(ret).c_str()); zm_av_packet_unref(&opkt); return 0; } - //av_frame_unref( output_frame ); + // av_frame_unref( out_frame ); - if ( (ret = avcodec_receive_packet( audio_output_context, &opkt )) < 0 ) { - if ( AVERROR(EAGAIN) == ret ) { + if ((ret = avcodec_receive_packet(audio_out_ctx, &opkt)) < 0) { + if (AVERROR(EAGAIN) == ret) { // THe codec may need more samples than it has, perfectly valid Debug(3, "Could not recieve packet (error '%s')", - av_make_error_string(ret).c_str()); + av_make_error_string(ret).c_str()); } else { Error("Could not recieve packet (error %d = '%s')", ret, - av_make_error_string(ret).c_str()); + av_make_error_string(ret).c_str()); } zm_av_packet_unref(&opkt); - av_frame_unref(input_frame); - //av_frame_unref( output_frame ); + av_frame_unref(in_frame); + // av_frame_unref( out_frame ); return 0; } #else - if ( (ret = avcodec_encode_audio2(audio_output_context, &opkt, output_frame, &data_present)) < 0 ) { + if ((ret = avcodec_encode_audio2(audio_out_ctx, &opkt, out_frame, + &data_present)) < 0) { Error("Could not encode frame (error '%s')", - av_make_error_string(ret).c_str()); + av_make_error_string(ret).c_str()); zm_av_packet_unref(&opkt); return 0; } - if ( !data_present ) { - Debug(2, "Not ready to output a frame yet."); + if (!data_present) { + Debug(2, "Not ready to out a frame yet."); zm_av_packet_unref(&opkt); return 0; } @@ -904,23 +947,25 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) { opkt.size = ipkt->size; } - // PTS is difficult, because of the buffering of the audio packets in the resampler. So we have to do it once we actually have a packet... - // audio_last_pts is the pts of ipkt, audio_next_pts is the last pts of the output +// PTS is difficult, because of the buffering of the audio packets in the +// resampler. So we have to do it once we actually have a packet... +// audio_last_pts is the pts of ipkt, audio_next_pts is the last pts of the +// out - //Scale the PTS of the outgoing packet to be the correct time base +// Scale the PTS of the outgoing packet to be the correct time base #if 0 if ( ipkt->pts != AV_NOPTS_VALUE ) { - if ( ! audio_last_pts ) { + if ( !audio_last_pts ) { opkt.pts = 0; Debug(1, "No audio_last_pts"); } else { if ( audio_last_pts > ipkt->pts ) { - Debug(1, "Resetting audio_start_pts from (%d) to (%d)", audio_last_pts, ipkt->pts ); - opkt.pts = audio_next_pts + av_rescale_q(ipkt->pts, audio_input_stream->time_base, audio_output_stream->time_base); + Debug(1, "Resetting audio_start_pts from (%d) to (%d)", audio_last_pts, ipkt->pts); + opkt.pts = audio_next_pts + av_rescale_q(ipkt->pts, audio_in_stream->time_base, audio_out_stream->time_base); } else { - opkt.pts = audio_next_pts + av_rescale_q(ipkt->pts - audio_last_pts, audio_input_stream->time_base, audio_output_stream->time_base); + opkt.pts = audio_next_pts + av_rescale_q(ipkt->pts - audio_last_pts, audio_in_stream->time_base, audio_out_stream->time_base); } - Debug(2, "audio opkt.pts = %d from ipkt->pts(%d) - last_pts(%d)", opkt.pts, ipkt->pts, audio_last_pts ); + Debug(2, "audio opkt.pts = %d from ipkt->pts(%d) - last_pts(%d)", opkt.pts, ipkt->pts, audio_last_pts); } audio_last_pts = ipkt->pts; } else { @@ -928,63 +973,70 @@ int VideoStore::writeAudioFramePacket( AVPacket *ipkt ) { opkt.pts = AV_NOPTS_VALUE; } #else - opkt.pts = audio_next_pts; - opkt.dts = audio_next_dts; + opkt.pts = audio_next_pts; + opkt.dts = audio_next_dts; #endif #if 0 if ( ipkt->dts == AV_NOPTS_VALUE ) { - // So if the input has no dts assigned... still need an output dts... so we use cur_dts? + // So if the in has no dts assigned... still need an out dts... so we use cur_dts? - if ( audio_last_dts >= audio_input_stream->cur_dts ) { - Debug(1, "Resetting audio_last_dts from (%d) to cur_dts (%d)", audio_last_dts, audio_input_stream->cur_dts ); - opkt.dts = audio_next_dts + av_rescale_q( audio_input_stream->cur_dts, AV_TIME_BASE_Q, audio_output_stream->time_base); + if ( audio_last_dts >= audio_in_stream->cur_dts ) { + Debug(1, "Resetting audio_last_dts from (%d) to cur_dts (%d)", audio_last_dts, audio_in_stream->cur_dts); + opkt.dts = audio_next_dts + av_rescale_q( audio_in_stream->cur_dts, AV_TIME_BASE_Q, audio_out_stream->time_base); } else { - opkt.dts = audio_next_dts + av_rescale_q( audio_input_stream->cur_dts - audio_last_dts, AV_TIME_BASE_Q, audio_output_stream->time_base); + opkt.dts = audio_next_dts + av_rescale_q( audio_in_stream->cur_dts - audio_last_dts, AV_TIME_BASE_Q, audio_out_stream->time_base); } - audio_last_dts = audio_input_stream->cur_dts; - Debug(2, "opkt.dts = %d from video_input_stream->cur_dts(%d) - last_dts(%d)", opkt.dts, audio_input_stream->cur_dts, audio_last_dts ); + audio_last_dts = audio_in_stream->cur_dts; + Debug(2, "opkt.dts = %d from video_in_stream->cur_dts(%d) - last_dts(%d)", opkt.dts, audio_in_stream->cur_dts, audio_last_dts); } else { if ( audio_last_dts >= ipkt->dts ) { Debug(1, "Resetting audio_last_dts from (%d) to (%d)", audio_last_dts, ipkt->dts ); - opkt.dts = audio_next_dts + av_rescale_q(ipkt->dts, audio_input_stream->time_base, audio_output_stream->time_base); + opkt.dts = audio_next_dts + av_rescale_q(ipkt->dts, audio_in_stream->time_base, audio_out_stream->time_base); } else { - opkt.dts = audio_next_dts + av_rescale_q(ipkt->dts - audio_last_dts, audio_input_stream->time_base, audio_output_stream->time_base); + opkt.dts = audio_next_dts + av_rescale_q(ipkt->dts - audio_last_dts, audio_in_stream->time_base, audio_out_stream->time_base); Debug(2, "opkt.dts = %d from previous(%d) + ( ipkt->dts(%d) - last_dts(%d) )", opkt.dts, audio_next_dts, ipkt->dts, audio_last_dts ); } } } #endif -//audio_last_dts = ipkt->dts; - if ( opkt.dts > opkt.pts ) { - Debug(1, "opkt.dts(%d) must be <= opkt.pts(%d). Decompression must happen before presentation.", opkt.dts, opkt.pts); + // audio_last_dts = ipkt->dts; + if (opkt.dts > opkt.pts) { + Debug(1, + "opkt.dts(%d) must be <= opkt.pts(%d). Decompression must happen " + "before presentation.", + opkt.dts, opkt.pts); opkt.dts = opkt.pts; } - // I wonder if we could just use duration instead of all the hoop jumping above? + // I wonder if we could just use duration instead of all the hoop jumping + // above? // - if ( output_frame ) { - opkt.duration = output_frame->nb_samples; + if (out_frame) { + opkt.duration = out_frame->nb_samples; } else { opkt.duration = ipkt->duration; } - //opkt.duration = av_rescale_q(ipkt->duration, audio_input_stream->time_base, audio_output_stream->time_base); - Debug(2, "opkt.pts (%d), opkt.dts(%d) opkt.duration = (%d)", opkt.pts, opkt.dts, opkt.duration); + // opkt.duration = av_rescale_q(ipkt->duration, audio_in_stream->time_base, + // audio_out_stream->time_base); + Debug(2, "opkt.pts (%d), opkt.dts(%d) opkt.duration = (%d)", opkt.pts, + opkt.dts, opkt.duration); - // pkt.pos: byte position in stream, -1 if unknown + // pkt.pos: byte position in stream, -1 if unknown opkt.pos = -1; - opkt.stream_index = audio_output_stream->index; + opkt.stream_index = audio_out_stream->index; audio_next_dts = opkt.dts + opkt.duration; audio_next_pts = opkt.pts + opkt.duration; AVPacket safepkt; memcpy(&safepkt, &opkt, sizeof(AVPacket)); ret = av_interleaved_write_frame(oc, &opkt); - if ( ret != 0 ) { - Error("Error writing audio frame packet: %s\n", av_make_error_string(ret).c_str()); + if (ret != 0) { + Error("Error writing audio frame packet: %s\n", + av_make_error_string(ret).c_str()); dumpPacket(&safepkt); } else { - Debug(2,"Success writing audio frame"); + Debug(2, "Success writing audio frame"); } zm_av_packet_unref(&opkt); return 0; diff --git a/src/zm_videostore.h b/src/zm_videostore.h index bf91415e7..c33b4c2ff 100644 --- a/src/zm_videostore.h +++ b/src/zm_videostore.h @@ -18,35 +18,35 @@ class VideoStore { private: unsigned int packets_written; - AVOutputFormat *output_format; + AVOutputFormat *out_format; AVFormatContext *oc; - AVStream *video_output_stream; - AVStream *audio_output_stream; - AVCodecContext *video_output_context; + AVStream *video_out_stream; + AVStream *audio_out_stream; + AVCodecContext *video_out_ctx; - AVStream *video_input_stream; - AVStream *audio_input_stream; + AVStream *video_in_stream; + AVStream *audio_in_stream; // Move this into the object so that we aren't constantly allocating/deallocating it on the stack AVPacket opkt; // we are transcoding - AVFrame *input_frame; - AVFrame *output_frame; + AVFrame *in_frame; + AVFrame *out_frame; - AVCodecContext *video_input_context; - AVCodecContext *audio_input_context; + AVCodecContext *video_in_ctx; + AVCodecContext *audio_in_ctx; int ret; // The following are used when encoding the audio stream to AAC - AVCodec *audio_output_codec; - AVCodecContext *audio_output_context; + AVCodec *audio_out_codec; + AVCodecContext *audio_out_ctx; int data_present; AVAudioFifo *fifo; - int output_frame_size; + int out_frame_size; #ifdef HAVE_LIBAVRESAMPLE -AVAudioResampleContext* resample_context; +AVAudioResampleContext* resample_ctx; #endif - uint8_t *converted_input_samples; + uint8_t *converted_in_samples; const char *filename; const char *format; @@ -54,13 +54,13 @@ AVAudioResampleContext* resample_context; bool keyframeMessage; int keyframeSkipNumber; - // These are for input + // These are for in int64_t video_last_pts; int64_t video_last_dts; int64_t audio_last_pts; int64_t audio_last_dts; - // These are for output, should start at zero. We assume they do not wrap because we just aren't going to save files that big. + // These are for out, should start at zero. We assume they do not wrap because we just aren't going to save files that big. int64_t video_next_pts; int64_t video_next_dts; int64_t audio_next_pts; @@ -71,7 +71,13 @@ AVAudioResampleContext* resample_context; bool setup_resampler(); public: - VideoStore(const char *filename_in, const char *format_in, AVStream *video_input_stream, AVStream *audio_input_stream, int64_t nStartTime, Monitor * p_monitor ); + VideoStore( + const char *filename_in, + const char *format_in, + AVStream *video_in_stream, + AVStream *audio_in_stream, + int64_t nStartTime,xi + Monitor * p_monitor); ~VideoStore(); int writeVideoFramePacket( AVPacket *pkt ); From a81ff85fbbfc6774f4e18d62c30b379e6a1eac37 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 23 Aug 2017 15:05:44 -0400 Subject: [PATCH 106/114] add ffmpeg decoding of a .mp4 to get the frames --- src/CMakeLists.txt | 2 +- src/zm_eventstream.cpp | 45 ++++++++-- src/zm_ffmpeg.cpp | 177 --------------------------------------- src/zm_ffmpeg.h | 28 ------- src/zm_ffmpeg_camera.cpp | 13 +-- src/zm_ffmpeg_input.cpp | 114 ++++++++++++++++++++++--- src/zm_ffmpeg_input.h | 8 ++ src/zm_image.cpp | 41 +++++++++ src/zm_image.h | 8 +- src/zm_packet.cpp | 2 + src/zm_packetqueue.cpp | 7 +- src/zm_video.h | 1 + src/zm_videostore.cpp | 34 ++++---- src/zm_videostore.h | 2 +- src/zms.cpp | 8 +- web/includes/Event.php | 2 +- 16 files changed, 228 insertions(+), 264 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 496b7da9c..b35c66316 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_input.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_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_input.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) # A fix for cmake recompiling the source files for every target. add_library(zm STATIC ${ZM_BIN_SRC_FILES}) diff --git a/src/zm_eventstream.cpp b/src/zm_eventstream.cpp index a1159fb4f..594901ad5 100644 --- a/src/zm_eventstream.cpp +++ b/src/zm_eventstream.cpp @@ -206,6 +206,7 @@ bool EventStream::loadEventData( int event_id ) { exit( mysql_errno( &dbconn ) ); } + mysql_free_result( result ); //for ( int i = 0; i < 250; i++ ) //{ //Info( "%d -> %d @ %f (%d)", i+1, event_data->frames[i].timestamp, event_data->frames[i].delta, event_data->frames[i].in_db ); @@ -215,13 +216,13 @@ bool EventStream::loadEventData( int event_id ) { char filepath[PATH_MAX]; snprintf( filepath, sizeof(filepath), "%s/%s", event_data->path, event_data->video_file ); ffmpeg_input = new FFmpeg_Input(); - if ( ! ffmpeg_input->Open( filepath ) ) { + if ( 0 > ffmpeg_input->Open( filepath ) ) { + Warning("Unable to open ffmpeg_input %s/%s", event_data->path, event_data->video_file ); delete ffmpeg_input; ffmpeg_input = NULL; } } - mysql_free_result( result ); if ( forceEventChange || mode == MODE_ALL_GAPLESS ) { if ( replay_rate > 0 ) @@ -232,7 +233,7 @@ bool EventStream::loadEventData( int event_id ) { Debug( 2, "Event:%ld, Frames:%ld, Duration: %.2f", event_data->event_id, event_data->frame_count, event_data->duration ); return( true ); -} +} // bool EventStream::loadEventData( int event_id ) void EventStream::processCommand( const CmdMsg *msg ) { Debug( 2, "Got message, type %d, msg %d", msg->msg_type, msg->msg_data[0] ); @@ -599,11 +600,12 @@ bool EventStream::sendFrame( int delta_us ) { } else if ( monitor->GetOptSaveJPEGs() & 2 ) { snprintf( filepath, sizeof(filepath), Event::analyse_file_format, event_data->path, curr_frame_id ); if ( stat( filepath, &filestat ) < 0 ) { - Debug(1, "%s not found, dalling back to capture"); + Debug(1, "analyze file %s not found will try to stream from other", filepath); snprintf( filepath, sizeof(filepath), Event::capture_file_format, event_data->path, curr_frame_id ); + filepath[0] = 0; } - } else { + } else if ( ! ffmpeg_input ) { Fatal("JPEGS not saved.zms is not capable of streaming jpegs from mp4 yet"); return false; } @@ -628,7 +630,7 @@ bool EventStream::sendFrame( int delta_us ) { int img_buffer_size = 0; uint8_t *img_buffer = temp_img_buffer; - bool send_raw = ((scale>=ZM_SCALE_BASE)&&(zoom==ZM_SCALE_BASE)); + bool send_raw = ((scale>=ZM_SCALE_BASE)&&(zoom==ZM_SCALE_BASE)) && filepath[0]; fprintf( stdout, "--ZoneMinderFrame\r\n" ); @@ -650,9 +652,27 @@ bool EventStream::sendFrame( int delta_us ) { img_buffer_size = fread( img_buffer, 1, sizeof(temp_img_buffer), fdj ); #endif } else { - Image image( filepath ); + Image *image = NULL; - Image *send_image = prepareImage( &image ); + if ( filepath[0] ) { + image = new Image( filepath ); + } else if ( ffmpeg_input ) { + // Get the frame from the mp4 input + Debug(1,"Getting frame from ffmpeg"); + AVFrame *frame = ffmpeg_input->get_frame( ffmpeg_input->get_video_stream_id() ); + if ( frame ) { + image = new Image( frame ); + av_frame_free(&frame); + } else { + Error("Failed getting a frame."); + return false; + } + } else { + Error("Unable to get a frame"); + return false; + } + + Image *send_image = prepareImage( image ); switch( type ) { case STREAM_JPEG : @@ -676,6 +696,8 @@ bool EventStream::sendFrame( int delta_us ) { Fatal( "Unexpected frame type %d", type ); break; } + delete image; + image = NULL; } switch( type ) { @@ -694,7 +716,7 @@ bool EventStream::sendFrame( int delta_us ) { } - if(send_raw) { + if ( send_raw ) { #if HAVE_SENDFILE fprintf( stdout, "Content-Length: %d\r\n\r\n", (int)filestat.st_size ); if ( zm_sendfile(fileno(stdout), fileno(fdj), 0, (int)filestat.st_size) != (int)filestat.st_size ) { @@ -714,6 +736,7 @@ bool EventStream::sendFrame( int delta_us ) { #endif fclose(fdj); /* Close the file handle */ } else { + Debug(3, "Content length: %d", img_buffer_size ); fprintf( stdout, "Content-Length: %d\r\n\r\n", img_buffer_size ); if ( fwrite( img_buffer, img_buffer_size, 1, stdout ) != 1 ) { Error( "Unable to send stream frame: %s", strerror(errno) ); @@ -730,11 +753,14 @@ bool EventStream::sendFrame( int delta_us ) { void EventStream::runStream() { Event::Initialise(); + Debug(3, "Initialized"); openComms(); + Debug(3, "Comms open"); checkInitialised(); + Debug(3, "frame rate is: (%f)", (double)event_data->frame_count/event_data->duration ); updateFrameRate( (double)event_data->frame_count/event_data->duration ); if ( type == STREAM_JPEG ) @@ -757,6 +783,7 @@ void EventStream::runStream() { if ( step != 0 ) curr_frame_id += step; + // Detects when we hit end of event and will load the next event or previous event checkEventLoaded(); // Get current frame data diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index 34a32bd61..4ba88d900 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -130,181 +130,6 @@ int av_dict_parse_string(AVDictionary **pm, const char *str, #endif #endif // HAVE_LIBAVUTIL -#if HAVE_LIBSWSCALE && HAVE_LIBAVUTIL -SWScale::SWScale() : gotdefaults(false), swscale_ctx(NULL), input_avframe(NULL), output_avframe(NULL) { - Debug(4,"SWScale object created"); - - /* Allocate AVFrame for the input */ -#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) - input_avframe = av_frame_alloc(); -#else - input_avframe = avcodec_alloc_frame(); -#endif - if(input_avframe == NULL) { - Fatal("Failed allocating AVFrame for the input"); - } - - /* Allocate AVFrame for the output */ -#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) - output_avframe = av_frame_alloc(); -#else - output_avframe = avcodec_alloc_frame(); -#endif - if(output_avframe == NULL) { - Fatal("Failed allocating AVFrame for the output"); - } -} - -SWScale::~SWScale() { - - /* Free up everything */ - av_frame_free( &input_avframe ); - //input_avframe = NULL; - - av_frame_free( &output_avframe ); - //output_avframe = NULL; - - if(swscale_ctx) { - sws_freeContext(swscale_ctx); - swscale_ctx = NULL; - } - - Debug(4,"SWScale object destroyed"); -} - -int SWScale::SetDefaults(enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height) { - - /* Assign the defaults */ - default_input_pf = in_pf; - default_output_pf = out_pf; - default_width = width; - default_height = height; - - gotdefaults = true; - - 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) { - /* Parameter checking */ - if(in_buffer == NULL || out_buffer == NULL) { - Error("NULL Input or output buffer"); - return -1; - } - // if(in_pf == 0 || out_pf == 0) { - // Error("Invalid input or output pixel formats"); - // return -2; - // } - if (!width || !height) { - Error("Invalid width or height"); - return -3; - } - -#if LIBSWSCALE_VERSION_CHECK(0, 8, 0, 8, 0) - /* Warn if the input or output pixelformat is not supported */ - if(!sws_isSupportedInput(in_pf)) { - Warning("swscale does not support the input format: %c%c%c%c",(in_pf)&0xff,((in_pf)&0xff),((in_pf>>16)&0xff),((in_pf>>24)&0xff)); - } - if(!sws_isSupportedOutput(out_pf)) { - Warning("swscale does not support the output format: %c%c%c%c",(out_pf)&0xff,((out_pf>>8)&0xff),((out_pf>>16)&0xff),((out_pf>>24)&0xff)); - } -#endif - - /* Check the buffer sizes */ -#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) - size_t insize = av_image_get_buffer_size(in_pf, width, height,1); -#else - size_t insize = avpicture_get_size(in_pf, width, height); -#endif - if(insize != in_buffer_size) { - Error("The input buffer size does not match the expected size for the input format. Required: %d Available: %d", insize, in_buffer_size); - return -4; - } -#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) - size_t outsize = av_image_get_buffer_size(out_pf, width, height,1); -#else - size_t outsize = avpicture_get_size(out_pf, width, height); -#endif - - if(outsize < out_buffer_size) { - Error("The output buffer is undersized for the output format. Required: %d Available: %d", outsize, out_buffer_size); - return -5; - } - - /* Get the context */ - swscale_ctx = sws_getCachedContext( swscale_ctx, width, height, in_pf, width, height, out_pf, SWS_FAST_BILINEAR, NULL, NULL, NULL ); - if(swscale_ctx == NULL) { - Error("Failed getting swscale context"); - return -6; - } - - /* Fill in the buffers */ -#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) - if (av_image_fill_arrays(input_avframe->data, input_avframe->linesize, - (uint8_t*) in_buffer, in_pf, width, height, 1) <= 0) { -#else - if (avpicture_fill((AVPicture*) input_avframe, (uint8_t*) in_buffer, - in_pf, width, height) <= 0) { -#endif - Error("Failed filling input frame with input buffer"); - return -7; - } -#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) - if (av_image_fill_arrays(output_avframe->data, output_avframe->linesize, - out_buffer, out_pf, width, height, 1) <= 0) { -#else - if (avpicture_fill((AVPicture*) output_avframe, out_buffer, out_pf, width, - height) <= 0) { -#endif - Error("Failed filling output frame with output buffer"); - return -8; - } - - /* Do the conversion */ - if(!sws_scale(swscale_ctx, input_avframe->data, input_avframe->linesize, 0, height, output_avframe->data, output_avframe->linesize ) ) { - Error("swscale conversion failed"); - return -10; - } - - return 0; -} - -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) { - Error("Source image width differs. Source: %d Output: %d",img->Width(), width); - return -12; - } - - 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); -} - -int SWScale::ConvertDefaults(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size) { - - if(!gotdefaults) { - Error("Defaults are not set"); - return -24; - } - - return Convert(img,out_buffer,out_buffer_size,default_input_pf,default_output_pf,default_width,default_height); -} - -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) { - Error("Defaults are not set"); - return -24; - } - - return Convert(in_buffer,in_buffer_size,out_buffer,out_buffer_size,default_input_pf,default_output_pf,default_width,default_height); -} -#endif // HAVE_LIBSWSCALE && HAVE_LIBAVUTIL - - #endif // HAVE_LIBAVCODEC || HAVE_LIBAVUTIL || HAVE_LIBSWSCALE #if HAVE_LIBAVUTIL @@ -560,5 +385,3 @@ bool is_audio_stream( AVStream * stream ) { } return false; } - - diff --git a/src/zm_ffmpeg.h b/src/zm_ffmpeg.h index cd328b6eb..10ad5260c 100644 --- a/src/zm_ffmpeg.h +++ b/src/zm_ffmpeg.h @@ -21,11 +21,8 @@ #define ZM_FFMPEG_H #include #include "zm.h" -#include "zm_image.h" -#ifdef __cplusplus extern "C" { -#endif // AVUTIL #if HAVE_LIBAVUTIL_AVUTIL_H @@ -207,31 +204,6 @@ void FFMPEGInit(); enum _AVPIXELFORMAT GetFFMPEGPixelFormat(unsigned int p_colours, unsigned p_subpixelorder); #endif // HAVE_LIBAVUTIL - -/* SWScale wrapper class to make our life easier and reduce code reuse */ -#if HAVE_LIBSWSCALE && HAVE_LIBAVUTIL -class SWScale { -public: - SWScale(); - ~SWScale(); - int SetDefaults(enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height); - int ConvertDefaults(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size); - int ConvertDefaults(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size); - int Convert(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height); - int Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height); - -protected: - bool gotdefaults; - struct SwsContext* swscale_ctx; - AVFrame* input_avframe; - AVFrame* output_avframe; - enum _AVPIXELFORMAT default_input_pf; - enum _AVPIXELFORMAT default_output_pf; - unsigned int default_width; - unsigned int default_height; -}; -#endif // HAVE_LIBSWSCALE && HAVE_LIBAVUTIL - #if !LIBAVCODEC_VERSION_CHECK(54, 25, 0, 51, 100) #define AV_CODEC_ID_NONE CODEC_ID_NONE #define AV_CODEC_ID_PCM_MULAW CODEC_ID_PCM_MULAW diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 259d65fa6..3af1e5880 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -290,7 +290,7 @@ int FfmpegCamera::Capture( Image &image ) { /* Request a writeable buffer of the target image */ directbuffer = image.WriteBuffer(width, height, colours, subpixelorder); - if(directbuffer == NULL) { + if ( directbuffer == NULL ) { Error("Failed requesting writeable buffer for the captured image."); return (-1); } @@ -304,17 +304,6 @@ int FfmpegCamera::Capture( Image &image ) { #endif #if HAVE_LIBSWSCALE - if ( mConvertContext == NULL ) { - mConvertContext = sws_getContext(mVideoCodecContext->width, - mVideoCodecContext->height, - mVideoCodecContext->pix_fmt, - width, height, imagePixFormat, - SWS_BICUBIC, NULL, NULL, NULL); - - if ( mConvertContext == NULL ) - Fatal( "Unable to create conversion context for %s", mPath.c_str() ); - } - if ( sws_scale(mConvertContext, mRawFrame->data, mRawFrame->linesize, 0, mVideoCodecContext->height, mFrame->data, mFrame->linesize) < 0 ) Fatal("Unable to convert raw format %u to target format %u at frame %d", mVideoCodecContext->pix_fmt, imagePixFormat, frameCount); #else // HAVE_LIBSWSCALE diff --git a/src/zm_ffmpeg_input.cpp b/src/zm_ffmpeg_input.cpp index b47e573b7..7469a1cfb 100644 --- a/src/zm_ffmpeg_input.cpp +++ b/src/zm_ffmpeg_input.cpp @@ -7,6 +7,9 @@ FFmpeg_Input::FFmpeg_Input() { input_format_context = NULL; video_stream_id = -1; audio_stream_id = -1; + av_register_all(); + avcodec_register_all(); + } FFmpeg_Input::~FFmpeg_Input() { } @@ -16,7 +19,7 @@ int FFmpeg_Input::Open( const char *filepath ) { int error; /** Open the input file to read from it. */ - if ((error = avformat_open_input( &input_format_context, filepath, NULL, NULL)) < 0) { + if ( (error = avformat_open_input( &input_format_context, filepath, NULL, NULL)) < 0 ) { Error("Could not open input file '%s' (error '%s')\n", filepath, av_make_error_string(error).c_str() ); @@ -25,7 +28,7 @@ int FFmpeg_Input::Open( const char *filepath ) { } /** Get information on the input file (number of streams etc.). */ - if ((error = avformat_find_stream_info( input_format_context, NULL)) < 0) { + if ( (error = avformat_find_stream_info(input_format_context, NULL)) < 0 ) { Error( "Could not open find stream info (error '%s')\n", av_make_error_string(error).c_str() ); avformat_close_input(&input_format_context); @@ -34,15 +37,14 @@ int FFmpeg_Input::Open( const char *filepath ) { for ( unsigned int i = 0; i < input_format_context->nb_streams; i += 1 ) { if ( is_video_stream( input_format_context->streams[i] ) ) { + zm_dump_stream_format(input_format_context, i, 0, 0); if ( video_stream_id == -1 ) { video_stream_id = i; // if we break, then we won't find the audio stream - continue; } else { Warning( "Have another video stream." ); } - } - if ( is_audio_stream( input_format_context->streams[i] ) ) { + } else if ( is_audio_stream( input_format_context->streams[i] ) ) { if ( audio_stream_id == -1 ) { audio_stream_id = i; } else { @@ -56,15 +58,16 @@ int FFmpeg_Input::Open( const char *filepath ) { #else streams[i].context = input_format_context->streams[i]->codec; #endif + streams[i].frame_count = 0; - /** Find a decoder for the audio stream. */ - if (!(streams[i].codec = avcodec_find_decoder(input_format_context->streams[i]->codecpar->codec_id))) { + if ( !(streams[i].codec = avcodec_find_decoder(input_format_context->streams[i]->codecpar->codec_id)) ) { Error( "Could not find input codec\n"); avformat_close_input(&input_format_context); return AVERROR_EXIT; + } else { + Debug(1, "Using codec (%s) for stream %d", streams[i].codec->name, i ); } - /** Open the decoder for the audio stream to use it later. */ if ((error = avcodec_open2( streams[i].context, streams[i].codec, NULL)) < 0) { Error( "Could not open input codec (error '%s')\n", av_make_error_string(error).c_str() ); @@ -72,13 +75,104 @@ int FFmpeg_Input::Open( const char *filepath ) { avformat_close_input(&input_format_context); return error; } - } // end foreach stream + if ( video_stream_id == -1 ) Error( "Unable to locate video stream in %s", filepath ); if ( audio_stream_id == -1 ) Debug( 3, "Unable to locate audio stream in %s", filepath ); return 0; -} // end int FFmpeg::Open( const char * filepath ) +} // end int FFmpeg_Input::Open( const char * filepath ) +AVFrame *FFmpeg_Input::get_frame( int stream_id ) { + Debug(1, "Getting frame from stream %d", stream_id ); + + int frameComplete = false; + AVPacket packet; + av_init_packet( &packet ); + AVFrame *frame = zm_av_frame_alloc(); + char errbuf[AV_ERROR_MAX_STRING_SIZE]; + + while ( !frameComplete ) { + int ret = av_read_frame( input_format_context, &packet ); + if ( ret < 0 ) { + av_strerror(ret, errbuf, AV_ERROR_MAX_STRING_SIZE); + if ( + // Check if EOF. + (ret == AVERROR_EOF || (input_format_context->pb && input_format_context->pb->eof_reached)) || + // Check for Connection failure. + (ret == -110) + ) { + Info( "av_read_frame returned %s.", errbuf ); + return NULL; + } + Error( "Unable to read packet from stream %d: error %d \"%s\".", packet.stream_index, ret, errbuf ); + return NULL; + } + + if ( (stream_id < 0 ) || ( packet.stream_index == stream_id ) ) { + Debug(1,"Packet is for our stream (%d)", packet.stream_index ); + + AVCodecContext *context = streams[packet.stream_index].context; + +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + ret = avcodec_send_packet( context, &packet ); + if ( ret < 0 ) { + av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); + Error( "Unable to send packet at frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf ); + zm_av_packet_unref( &packet ); + continue; + } else { + Debug(1, "Success getting a packet"); + } + +#if HAVE_AVUTIL_HWCONTEXT_H + if ( hwaccel ) { + ret = avcodec_receive_frame( context, hwFrame ); + if ( ret < 0 ) { + av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); + Error( "Unable to receive frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf ); + zm_av_packet_unref( &packet ); + continue; + } + ret = av_hwframe_transfer_data(frame, hwFrame, 0); + if (ret < 0) { + av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); + Error( "Unable to transfer frame at frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf ); + zm_av_packet_unref( &packet ); + continue; + } + } else { +#endif + Debug(1,"Getting a frame?"); + ret = avcodec_receive_frame( context, frame ); + if ( ret < 0 ) { + av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); + Error( "Unable to send packet at frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf ); + zm_av_packet_unref( &packet ); + continue; + } + +#if HAVE_AVUTIL_HWCONTEXT_H + } +#endif + + frameComplete = 1; +# else + ret = zm_avcodec_decode_video( streams[packet.stream_index].context, frame, &frameComplete, &packet ); + if ( ret < 0 ) { + av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); + Error( "Unable to decode frame at frame %d: %s, continuing", frameCount, errbuf ); + zm_av_packet_unref( &packet ); + continue; + } +#endif + } // end if it's the right stream + + zm_av_packet_unref( &packet ); + + } // end while ! frameComplete + return frame; + +} // end AVFrame *FFmpeg_Input::get_frame diff --git a/src/zm_ffmpeg_input.h b/src/zm_ffmpeg_input.h index 9a2147bd0..3e12f45cc 100644 --- a/src/zm_ffmpeg_input.h +++ b/src/zm_ffmpeg_input.h @@ -21,11 +21,19 @@ class FFmpeg_Input { int Open( const char *filename ); int Close(); + AVFrame *get_frame( int stream_id=-1 ); + int get_video_stream_id() { + return video_stream_id; + } + int get_audio_stream_id() { + return audio_stream_id; + } private: typedef struct { AVCodecContext *context; AVCodec *codec; + int frame_count; } stream; stream streams[2]; diff --git a/src/zm_image.cpp b/src/zm_image.cpp index cab8a225d..9ff23a217 100644 --- a/src/zm_image.cpp +++ b/src/zm_image.cpp @@ -22,6 +22,7 @@ #include "zm_image.h" #include "zm_utils.h" #include "zm_rgb.h" +#include "zm_ffmpeg.h" #include #include @@ -128,6 +129,46 @@ Image::Image( int p_width, int p_height, int p_colours, int p_subpixelorder, uin text[0] = '\0'; } +Image::Image( const AVFrame *frame ) { + AVFrame *dest_frame = zm_av_frame_alloc(); + + width = frame->width; + height = frame->height; + pixels = width*height; + colours = ZM_COLOUR_RGB32; + subpixelorder = ZM_SUBPIX_ORDER_RGBA; + size = pixels*colours; + buffer = 0; + holdbuffer = 0; + AllocImgBuffer(size); + +#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) + av_image_fill_arrays(dest_frame->data, dest_frame->linesize, + buffer, AV_PIX_FMT_RGBA, width, height, 1); +#else + avpicture_fill( (AVPicture *)mFrame, buffer, + AV_PIX_FMT_RGBA, width, height); +#endif + +#if HAVE_LIBSWSCALE + struct SwsContext *mConvertContext = sws_getContext( + width, + height, + (AVPixelFormat)frame->format, + width, height, + AV_PIX_FMT_RGBA, SWS_BICUBIC, NULL, + NULL, NULL); + if ( mConvertContext == NULL ) + Fatal( "Unable to create conversion context" ); + + if ( sws_scale(mConvertContext, frame->data, frame->linesize, 0, frame->height, dest_frame->data, dest_frame->linesize) < 0 ) + Fatal("Unable to convert raw format %u to target format %u", frame->format, AV_PIX_FMT_RGBA); +#else // HAVE_LIBSWSCALE + Fatal("You must compile ffmpeg with the --enable-swscale option to use ffmpeg cameras"); +#endif // HAVE_LIBSWSCALE + av_frame_free( &dest_frame ); +} + Image::Image( const Image &p_image ) { if ( !initialised ) Initialise(); diff --git a/src/zm_image.h b/src/zm_image.h index e68e0ff70..934d2a682 100644 --- a/src/zm_image.h +++ b/src/zm_image.h @@ -21,8 +21,7 @@ #define ZM_IMAGE_H #include "zm.h" -extern "C" -{ +extern "C" { #include "zm_jpeg.h" } #include "zm_rgb.h" @@ -32,6 +31,9 @@ extern "C" #include "zm_mem_utils.h" #include "zm_utils.h" +class Image; +#include "zm_ffmpeg.h" + #include #if HAVE_ZLIB_H @@ -148,12 +150,12 @@ protected: int holdbuffer; /* Hold the buffer instead of replacing it with new one */ char text[1024]; - public: Image(); Image( const char *filename ); Image( int p_width, int p_height, int p_colours, int p_subpixelorder, uint8_t *p_buffer=0); Image( const Image &p_image ); + Image( const AVFrame *frame ); ~Image(); static void Initialise(); static void Deinitialise(); diff --git a/src/zm_packet.cpp b/src/zm_packet.cpp index 8fbb65cb8..7c08d4158 100644 --- a/src/zm_packet.cpp +++ b/src/zm_packet.cpp @@ -20,6 +20,8 @@ #include "zm_packet.h" #include "zm_ffmpeg.h" +#include + using namespace std; ZMPacket::ZMPacket( AVPacket *p ) { diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index 497809342..f55a7a680 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -19,12 +19,11 @@ #include "zm_packetqueue.h" #include "zm_ffmpeg.h" +#include #define VIDEO_QUEUESIZE 200 #define AUDIO_QUEUESIZE 50 -using namespace std; - zm_packetqueue::zm_packetqueue(){ } @@ -68,7 +67,7 @@ unsigned int zm_packetqueue::clearQueue( unsigned int frames_to_keep, int stream return 0; } - list::reverse_iterator it; + std::list::reverse_iterator it; ZMPacket *packet = NULL; for ( it = pktQueue.rbegin(); it != pktQueue.rend() && frames_to_keep; ++it ) { @@ -121,7 +120,7 @@ void zm_packetqueue::clear_unwanted_packets( timeval *recording_started, int mVi // Step 1 - find keyframe < recording_started. // Step 2 - pop packets until we get to the packet in step 2 - list::reverse_iterator it; + std::list::reverse_iterator it; Debug(3, "Looking for keyframe after start recording stream id (%d)", mVideoStreamId ); for ( it = pktQueue.rbegin(); it != pktQueue.rend(); ++ it ) { diff --git a/src/zm_video.h b/src/zm_video.h index 936adfeb8..2b71f12df 100644 --- a/src/zm_video.h +++ b/src/zm_video.h @@ -21,6 +21,7 @@ #include "zm_utils.h" #include "zm_ffmpeg.h" #include "zm_buffer.h" +#include "zm_swscale.h" /* #define HAVE_LIBX264 1 diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index af5c187df..b2842e711 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -39,8 +39,8 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, audio_in_stream = p_audio_in_stream; #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - video_in_ctx = avcodec_alloc_ctx3(NULL); - avcodec_parameters_to_ctx(video_in_ctx, + video_in_ctx = avcodec_alloc_context3(NULL); + avcodec_parameters_to_context(video_in_ctx, video_in_stream->codecpar); // zm_dump_codecpar( video_in_stream->codecpar ); #else @@ -53,7 +53,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, Info("Opening video storage stream %s format: %s", filename, format); - ret = avformat_alloc_out_ctx2(&oc, NULL, NULL, filename); + ret = avformat_alloc_output_context2(&oc, NULL, NULL, filename); if (ret < 0) { Warning( "Could not create video storage stream %s as no out ctx" @@ -65,7 +65,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, // Couldn't deduce format from filename, trying from format name if (!oc) { - avformat_alloc_out_ctx2(&oc, NULL, format, filename); + avformat_alloc_output_context2(&oc, NULL, format, filename); if (!oc) { Fatal( "Could not create video storage stream %s as no out ctx" @@ -87,10 +87,10 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) // Since we are not re-encoding, all we have to do is copy the parameters - video_out_ctx = avcodec_alloc_ctx3(NULL); + video_out_ctx = avcodec_alloc_context3(NULL); // Copy params from instream to ctx - ret = avcodec_parameters_to_ctx(video_out_ctx, + ret = avcodec_parameters_to_context(video_out_ctx, video_in_stream->codecpar); if (ret < 0) { Error("Could not initialize ctx parameteres"); @@ -113,7 +113,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, } // Now copy them to the out stream - ret = avcodec_parameters_from_ctx(video_out_stream->codecpar, + ret = avcodec_parameters_from_context(video_out_stream->codecpar, video_out_ctx); if (ret < 0) { Error("Could not initialize stream parameteres"); @@ -202,8 +202,8 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, Debug(3, "Have audio stream"); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - audio_in_ctx = avcodec_alloc_ctx3(NULL); - ret = avcodec_parameters_to_ctx(audio_in_ctx, + audio_in_ctx = avcodec_alloc_context3(NULL); + ret = avcodec_parameters_to_context(audio_in_ctx, audio_in_stream->codecpar); #else audio_in_ctx = audio_in_stream->codec; @@ -222,7 +222,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, Debug(3, "Got AAC"); audio_out_stream = - avformat_new_stream(oc, reinterpret_castaudio_in_ctx->codec); + avformat_new_stream(oc, reinterpret_cast(audio_in_ctx->codec)); if (!audio_out_stream) { Error("Unable to create audio out stream\n"); audio_out_stream = NULL; @@ -230,15 +230,15 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, Debug(2, "setting parameters"); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - audio_out_ctx = avcodec_alloc_ctx3(audio_out_codec); + audio_out_ctx = avcodec_alloc_context3(audio_out_codec); // Copy params from instream to ctx - ret = avcodec_parameters_to_ctx(audio_out_ctx, + ret = avcodec_parameters_to_context(audio_out_ctx, audio_in_stream->codecpar); if (ret < 0) { Error("Unable to copy audio params to ctx %s\n", av_make_error_string(ret).c_str()); } - ret = avcodec_parameters_from_ctx(audio_out_stream->codecpar, + ret = avcodec_parameters_from_context(audio_out_stream->codecpar, audio_out_ctx); if (ret < 0) { Error("Unable to copy audio params to stream %s\n", @@ -430,7 +430,7 @@ VideoStore::~VideoStore() { } /* free the stream */ - avformat_free_ctx(oc); + avformat_free_context(oc); } bool VideoStore::setup_resampler() { @@ -460,7 +460,7 @@ bool VideoStore::setup_resampler() { Debug(2, "Have audio out codec"); // audio_out_ctx = audio_out_stream->codec; - audio_out_ctx = avcodec_alloc_ctx3(audio_out_codec); + audio_out_ctx = avcodec_alloc_context3(audio_out_codec); if (!audio_out_ctx) { Error("could not allocate codec ctx for AAC\n"); @@ -512,7 +512,7 @@ bool VideoStore::setup_resampler() { audio_out_stream = avformat_new_stream(oc, audio_out_codec); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - ret = avcodec_parameters_from_ctx(audio_out_stream->codecpar, + ret = avcodec_parameters_from_context(audio_out_stream->codecpar, audio_out_ctx); if (ret < 0) { Error("Could not initialize stream parameteres"); @@ -554,7 +554,7 @@ bool VideoStore::setup_resampler() { } // Setup the audio resampler - resample_ctx = avresample_alloc_ctx(); + resample_ctx = avresample_alloc_context(); if (!resample_ctx) { Error("Could not allocate resample ctx\n"); return false; diff --git a/src/zm_videostore.h b/src/zm_videostore.h index c33b4c2ff..014731f40 100644 --- a/src/zm_videostore.h +++ b/src/zm_videostore.h @@ -76,7 +76,7 @@ public: const char *format_in, AVStream *video_in_stream, AVStream *audio_in_stream, - int64_t nStartTime,xi + int64_t nStartTime, Monitor * p_monitor); ~VideoStore(); diff --git a/src/zms.cpp b/src/zms.cpp index 3b1a6dfd1..2161a822e 100644 --- a/src/zms.cpp +++ b/src/zms.cpp @@ -52,7 +52,7 @@ int main( int argc, const char *argv[] ) { srand( getpid() * time( 0 ) ); - enum { ZMS_MONITOR, ZMS_EVENT } source = ZMS_MONITOR; + enum { ZMS_UNKNOWN, ZMS_MONITOR, ZMS_EVENT } source = ZMS_UNKNOWN; enum { ZMS_JPEG, ZMS_MPEG, ZMS_RAW, ZMS_ZIP, ZMS_SINGLE } mode = ZMS_JPEG; char format[32] = ""; int monitor_id = 0; @@ -125,8 +125,10 @@ int main( int argc, const char *argv[] ) { event_time = atoi( value ); } else if ( !strcmp( name, "event" ) ) { event_id = strtoull( value, (char **)NULL, 10 ); + source = ZMS_EVENT; } else if ( !strcmp( name, "frame" ) ) { frame_id = strtoull( value, (char **)NULL, 10 ); + source = ZMS_EVENT; } else if ( !strcmp( name, "scale" ) ) { scale = atoi( value ); } else if ( !strcmp( name, "rate" ) ) { @@ -264,6 +266,7 @@ int main( int argc, const char *argv[] ) { if ( ! event_id ) { Fatal( "Can't view an event without specifying an event_id." ); } + Debug(3,"Doing event stream scale(%d)", scale ); EventStream stream; stream.setStreamScale( scale ); stream.setStreamReplayRate( rate ); @@ -273,6 +276,7 @@ int main( int argc, const char *argv[] ) { if ( monitor_id && event_time ) { stream.setStreamStart( monitor_id, event_time ); } else { + Debug(3, "Setting stream start to frame (%d)", frame_id); stream.setStreamStart( event_id, frame_id ); } if ( mode == ZMS_JPEG ) { @@ -291,6 +295,8 @@ int main( int argc, const char *argv[] ) { #endif // HAVE_LIBAVCODEC } // end if jpeg or mpeg stream.runStream(); + } else { + Error("Neither a monitor or event was specified."); } // end if monitor or event logTerm(); diff --git a/web/includes/Event.php b/web/includes/Event.php index 7bef5498f..a9102723f 100644 --- a/web/includes/Event.php +++ b/web/includes/Event.php @@ -131,7 +131,7 @@ class Event { } # end Event->delete public function getStreamSrc( $args=array(), $querySep='&' ) { - if ( $this->{'DefaultVideo'} ) { + if ( $this->{'DefaultVideo'} and $args['mode'] != 'jpeg' ) { return ( ZM_BASE_PATH != '/' ? ZM_BASE_PATH : '' ).'/index.php?view=view_video&eid='.$this->{'Id'}; } From a4cf47b5c3b922152d07fbeafeff52cd1223faca Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 23 Aug 2017 15:06:12 -0400 Subject: [PATCH 107/114] move swscale into it's own files --- src/zm_swscale.cpp | 198 +++++++++++++++++++++++++++++++++++++++++++++ src/zm_swscale.h | 31 +++++++ 2 files changed, 229 insertions(+) create mode 100644 src/zm_swscale.cpp create mode 100644 src/zm_swscale.h diff --git a/src/zm_swscale.cpp b/src/zm_swscale.cpp new file mode 100644 index 000000000..2dc391eb0 --- /dev/null +++ b/src/zm_swscale.cpp @@ -0,0 +1,198 @@ +/* + * ZoneMinder FFMPEG implementation, $Date$, $Revision$ + * Copyright (C) 2001-2008 Philip Coombes + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "zm_ffmpeg.h" +#include "zm_image.h" +#include "zm_rgb.h" + +#include "zm_swscale.h" + +#if HAVE_LIBSWSCALE && HAVE_LIBAVUTIL +SWScale::SWScale() : gotdefaults(false), swscale_ctx(NULL), input_avframe(NULL), output_avframe(NULL) { + Debug(4,"SWScale object created"); + + /* Allocate AVFrame for the input */ +#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) + input_avframe = av_frame_alloc(); +#else + input_avframe = avcodec_alloc_frame(); +#endif + if(input_avframe == NULL) { + Fatal("Failed allocating AVFrame for the input"); + } + + /* Allocate AVFrame for the output */ +#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) + output_avframe = av_frame_alloc(); +#else + output_avframe = avcodec_alloc_frame(); +#endif + if(output_avframe == NULL) { + Fatal("Failed allocating AVFrame for the output"); + } +} + +SWScale::~SWScale() { + + /* Free up everything */ + av_frame_free( &input_avframe ); + //input_avframe = NULL; + + av_frame_free( &output_avframe ); + //output_avframe = NULL; + + if(swscale_ctx) { + sws_freeContext(swscale_ctx); + swscale_ctx = NULL; + } + + Debug(4,"SWScale object destroyed"); +} + +int SWScale::SetDefaults(enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height) { + + /* Assign the defaults */ + default_input_pf = in_pf; + default_output_pf = out_pf; + default_width = width; + default_height = height; + + gotdefaults = true; + + 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) { + /* Parameter checking */ + if(in_buffer == NULL || out_buffer == NULL) { + Error("NULL Input or output buffer"); + return -1; + } + // if(in_pf == 0 || out_pf == 0) { + // Error("Invalid input or output pixel formats"); + // return -2; + // } + if (!width || !height) { + Error("Invalid width or height"); + return -3; + } + +#if LIBSWSCALE_VERSION_CHECK(0, 8, 0, 8, 0) + /* Warn if the input or output pixelformat is not supported */ + if(!sws_isSupportedInput(in_pf)) { + Warning("swscale does not support the input format: %c%c%c%c",(in_pf)&0xff,((in_pf)&0xff),((in_pf>>16)&0xff),((in_pf>>24)&0xff)); + } + if(!sws_isSupportedOutput(out_pf)) { + Warning("swscale does not support the output format: %c%c%c%c",(out_pf)&0xff,((out_pf>>8)&0xff),((out_pf>>16)&0xff),((out_pf>>24)&0xff)); + } +#endif + + /* Check the buffer sizes */ +#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) + size_t insize = av_image_get_buffer_size(in_pf, width, height,1); +#else + size_t insize = avpicture_get_size(in_pf, width, height); +#endif + if(insize != in_buffer_size) { + Error("The input buffer size does not match the expected size for the input format. Required: %d Available: %d", insize, in_buffer_size); + return -4; + } +#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) + size_t outsize = av_image_get_buffer_size(out_pf, width, height,1); +#else + size_t outsize = avpicture_get_size(out_pf, width, height); +#endif + + if(outsize < out_buffer_size) { + Error("The output buffer is undersized for the output format. Required: %d Available: %d", outsize, out_buffer_size); + return -5; + } + + /* Get the context */ + swscale_ctx = sws_getCachedContext( swscale_ctx, width, height, in_pf, width, height, out_pf, SWS_FAST_BILINEAR, NULL, NULL, NULL ); + if(swscale_ctx == NULL) { + Error("Failed getting swscale context"); + return -6; + } + + /* Fill in the buffers */ +#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) + if (av_image_fill_arrays(input_avframe->data, input_avframe->linesize, + (uint8_t*) in_buffer, in_pf, width, height, 1) <= 0) { +#else + if (avpicture_fill((AVPicture*) input_avframe, (uint8_t*) in_buffer, + in_pf, width, height) <= 0) { +#endif + Error("Failed filling input frame with input buffer"); + return -7; + } +#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) + if (av_image_fill_arrays(output_avframe->data, output_avframe->linesize, + out_buffer, out_pf, width, height, 1) <= 0) { +#else + if (avpicture_fill((AVPicture*) output_avframe, out_buffer, out_pf, width, + height) <= 0) { +#endif + Error("Failed filling output frame with output buffer"); + return -8; + } + + /* Do the conversion */ + if(!sws_scale(swscale_ctx, input_avframe->data, input_avframe->linesize, 0, height, output_avframe->data, output_avframe->linesize ) ) { + Error("swscale conversion failed"); + return -10; + } + + return 0; +} + +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) { + Error("Source image width differs. Source: %d Output: %d",img->Width(), width); + return -12; + } + + 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); +} + +int SWScale::ConvertDefaults(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size) { + + if(!gotdefaults) { + Error("Defaults are not set"); + return -24; + } + + return Convert(img,out_buffer,out_buffer_size,default_input_pf,default_output_pf,default_width,default_height); +} + +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) { + Error("Defaults are not set"); + return -24; + } + + return Convert(in_buffer,in_buffer_size,out_buffer,out_buffer_size,default_input_pf,default_output_pf,default_width,default_height); +} +#endif // HAVE_LIBSWSCALE && HAVE_LIBAVUTIL diff --git a/src/zm_swscale.h b/src/zm_swscale.h new file mode 100644 index 000000000..66a3d470a --- /dev/null +++ b/src/zm_swscale.h @@ -0,0 +1,31 @@ +#ifndef ZM_SWSCALE_H +#define ZM_SWSCALE_H + +#include "zm_image.h" +#include "zm_ffmpeg.h" + +/* SWScale wrapper class to make our life easier and reduce code reuse */ +#if HAVE_LIBSWSCALE && HAVE_LIBAVUTIL +class SWScale { + public: + SWScale(); + ~SWScale(); + int SetDefaults(enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height); + int ConvertDefaults(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size); + int ConvertDefaults(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size); + int Convert(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height); + int Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height); + + protected: + bool gotdefaults; + struct SwsContext* swscale_ctx; + AVFrame* input_avframe; + AVFrame* output_avframe; + enum _AVPIXELFORMAT default_input_pf; + enum _AVPIXELFORMAT default_output_pf; + unsigned int default_width; + unsigned int default_height; +}; +#endif // HAVE_LIBSWSCALE && HAVE_LIBAVUTIL + +#endif From 789de37d336f8c7d039820b7e9d638bd7dd9a62b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 24 Aug 2017 09:53:40 -0400 Subject: [PATCH 108/114] fix builds on older ffmpeg --- src/zm_ffmpeg_input.cpp | 6 +++--- src/zm_videostore.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/zm_ffmpeg_input.cpp b/src/zm_ffmpeg_input.cpp index 7469a1cfb..982c33dde 100644 --- a/src/zm_ffmpeg_input.cpp +++ b/src/zm_ffmpeg_input.cpp @@ -52,15 +52,15 @@ int FFmpeg_Input::Open( const char *filepath ) { } } + streams[i].frame_count = 0; #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) streams[i].context = avcodec_alloc_context3( NULL ); avcodec_parameters_to_context( streams[i].context, input_format_context->streams[i]->codecpar ); #else streams[i].context = input_format_context->streams[i]->codec; #endif - streams[i].frame_count = 0; - if ( !(streams[i].codec = avcodec_find_decoder(input_format_context->streams[i]->codecpar->codec_id)) ) { + if ( !(streams[i].codec = avcodec_find_decoder(streams[i].context->codec_id)) ) { Error( "Could not find input codec\n"); avformat_close_input(&input_format_context); return AVERROR_EXIT; @@ -163,7 +163,7 @@ AVFrame *FFmpeg_Input::get_frame( int stream_id ) { ret = zm_avcodec_decode_video( streams[packet.stream_index].context, frame, &frameComplete, &packet ); if ( ret < 0 ) { av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); - Error( "Unable to decode frame at frame %d: %s, continuing", frameCount, errbuf ); + Error( "Unable to decode frame at frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf ); zm_av_packet_unref( &packet ); continue; } diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index b2842e711..8bb274fa2 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -125,14 +125,14 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, #else video_out_stream = - avformat_new_stream(oc, reinterpret_castvideo_in_ctx->codec); + avformat_new_stream(oc, reinterpret_cast(video_in_ctx->codec)); if (!video_out_stream) { Fatal("Unable to create video out stream\n"); } else { Debug(2, "Success creating video out stream"); } video_out_ctx = video_out_stream->codec; - ret = avcodec_copy_ctx(video_out_ctx, video_in_ctx); + ret = avcodec_copy_context(video_out_ctx, video_in_ctx); if (ret < 0) { Fatal("Unable to copy in video ctx to out video ctx %s\n", av_make_error_string(ret).c_str()); @@ -254,7 +254,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, #else audio_out_ctx = audio_out_stream->codec; - ret = avcodec_copy_ctx(audio_out_ctx, audio_in_ctx); + ret = avcodec_copy_context(audio_out_ctx, audio_in_ctx); audio_out_ctx->codec_tag = 0; #endif if (ret < 0) { From 48e9e12063ed94e12c1564220ed88517d2961e85 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 24 Aug 2017 10:13:46 -0400 Subject: [PATCH 109/114] assume source=monitor when a monitor_id is specified --- src/zms.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/zms.cpp b/src/zms.cpp index 2161a822e..d8fc0a86c 100644 --- a/src/zms.cpp +++ b/src/zms.cpp @@ -121,6 +121,8 @@ int main( int argc, const char *argv[] ) { strncpy( format, value, sizeof(format) ); } else if ( !strcmp( name, "monitor" ) ) { monitor_id = atoi( value ); + if ( source == ZMS_UNKNOWN ) + source = ZMS_MONITOR; } else if ( !strcmp( name, "time" ) ) { event_time = atoi( value ); } else if ( !strcmp( name, "event" ) ) { From d11a2947bbe84d824d94e323566f7805207f66cf Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 24 Aug 2017 10:44:14 -0400 Subject: [PATCH 110/114] use Id instead of id --- scripts/zmwatch.pl.in | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/zmwatch.pl.in b/scripts/zmwatch.pl.in index cdc7d38d9..393d8fe90 100644 --- a/scripts/zmwatch.pl.in +++ b/scripts/zmwatch.pl.in @@ -143,11 +143,11 @@ while( 1 ) { if ( !defined($image_time) ) { # Can't read from shared data $restart = 1; - Error( "Error reading shared data for $$monitor{id} $$monitor{Name}\n"); + Error( "Error reading shared data for $$monitor{Id} $$monitor{Name}\n"); } elsif ( !$image_time ) { # We can't get the last capture time so can't be sure it's died. $restart = 1; - Error( "Error getting last capture time for $$monitor{id} $$monitor{Name}\n"); + Error( "Error getting last capture time for $$monitor{Id} $$monitor{Name}\n"); } else { my $max_image_delay = ( $monitor->{MaxFPS} @@ -159,7 +159,7 @@ while( 1 ) { my $image_delay = $now-$image_time; Debug( "Monitor $monitor->{Id} last analysed $image_delay seconds ago, max is $max_image_delay\n" ); if ( $image_delay > $max_image_delay ) { - Info( "Analysis daemon for $$monitor{id} $$monitor{Name} needs restarting," + Info( "Analysis daemon for $$monitor{Id} $$monitor{Name} needs restarting," ." time since last analysis $image_delay seconds ($now-$image_time)\n" ); $restart = 1; @@ -167,7 +167,7 @@ while( 1 ) { } if ( $restart ) { - Info( "Restarting analysis daemon for $$monitor{id} $$monitor{Name}\n"); + Info( "Restarting analysis daemon for $$monitor{Id} $$monitor{Name}\n"); my $command = "zmdc.pl restart zma -m ".$monitor->{Id}; runCommand( $command ); } # end if restart From 0c24556611399e93ecc253c7a48253602acb9570 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 24 Aug 2017 10:59:56 -0400 Subject: [PATCH 111/114] fix missing ! --- scripts/zmaudit.pl.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/zmaudit.pl.in b/scripts/zmaudit.pl.in index deb1c7781..a2c666b89 100644 --- a/scripts/zmaudit.pl.in +++ b/scripts/zmaudit.pl.in @@ -271,7 +271,7 @@ MAIN: while( $loop ) { } # end foreach event chdir( $Storage->Path() ); } # if USE_DEEP_STORAGE - Debug( 'Got '.int(keys(%$fs_events))." events for monitor $monitor_dir\n" ); + Debug( 'Got '.int(keys(%$fs_events))." filesystem events for monitor $monitor_dir\n" ); #delete_empty_directories( $monitor_dir ); } # end foreach monitor @@ -351,7 +351,7 @@ MAIN: while( $loop ) { if ( ! defined( $fs_events->{$db_event} ) ) { Debug("Event $db_event is not in fs."); my $Event = ZoneMinder::Event->find_one( Id=>$db_event ); - if ( $Event ) { + if ( ! $Event ) { Debug("Event $db_event is no longer in db. Filter probably deleted it while we were auditing."); next; } From 2a4f751a4f52646363de0c551b3c8c7a64ecb93c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 24 Aug 2017 12:00:48 -0400 Subject: [PATCH 112/114] ffmpeg versionc heck --- src/zm_ffmpeg_input.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/zm_ffmpeg_input.cpp b/src/zm_ffmpeg_input.cpp index 982c33dde..6c715b6d1 100644 --- a/src/zm_ffmpeg_input.cpp +++ b/src/zm_ffmpeg_input.cpp @@ -71,7 +71,9 @@ int FFmpeg_Input::Open( const char *filepath ) { if ((error = avcodec_open2( streams[i].context, streams[i].codec, NULL)) < 0) { Error( "Could not open input codec (error '%s')\n", av_make_error_string(error).c_str() ); +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) avcodec_free_context( &streams[i].context ); +#endif avformat_close_input(&input_format_context); return error; } From 08bdf5a72968e685df1e516033be19d2cb0a82c6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 24 Aug 2017 12:19:57 -0400 Subject: [PATCH 113/114] fix build on trusty --- src/zm_image.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_image.cpp b/src/zm_image.cpp index 9ff23a217..e109b46bc 100644 --- a/src/zm_image.cpp +++ b/src/zm_image.cpp @@ -146,7 +146,7 @@ Image::Image( const AVFrame *frame ) { av_image_fill_arrays(dest_frame->data, dest_frame->linesize, buffer, AV_PIX_FMT_RGBA, width, height, 1); #else - avpicture_fill( (AVPicture *)mFrame, buffer, + avpicture_fill( (AVPicture *)dest_frame, buffer, AV_PIX_FMT_RGBA, width, height); #endif From 11b29bf1ec97905d75090caefcddf7e8c9088328 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 25 Aug 2017 11:16:37 -0400 Subject: [PATCH 114/114] Fixup ONVIF module, making it actually usable --- scripts/ZoneMinder/CMakeLists.txt | 1 + scripts/ZoneMinder/lib/ZoneMinder/ONVIF.pm.in | 56 +++++++++++-------- 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/scripts/ZoneMinder/CMakeLists.txt b/scripts/ZoneMinder/CMakeLists.txt index 3ed9bf7c6..876a33da3 100644 --- a/scripts/ZoneMinder/CMakeLists.txt +++ b/scripts/ZoneMinder/CMakeLists.txt @@ -16,6 +16,7 @@ configure_file(lib/ZoneMinder/Base.pm.in "${CMAKE_CURRENT_BINARY_DIR}/lib/ZoneMi configure_file(lib/ZoneMinder/Config.pm.in "${CMAKE_CURRENT_BINARY_DIR}/lib/ZoneMinder/Config.pm" @ONLY) configure_file(lib/ZoneMinder/Memory.pm.in "${CMAKE_CURRENT_BINARY_DIR}/lib/ZoneMinder/Memory.pm" @ONLY) configure_file(lib/ZoneMinder/ConfigData.pm.in "${CMAKE_CURRENT_BINARY_DIR}/lib/ZoneMinder/ConfigData.pm" @ONLY) +configure_file(lib/ZoneMinder/ONVIF.pm.in "${CMAKE_CURRENT_BINARY_DIR}/lib/ZoneMinder/ONVIF.pm" @ONLY) if(CMAKE_VERBOSE_MAKEFILE) set(MAKEMAKER_NOECHO_COMMAND "") diff --git a/scripts/ZoneMinder/lib/ZoneMinder/ONVIF.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/ONVIF.pm.in index 3b295c45f..23914bdd2 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/ONVIF.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/ONVIF.pm.in @@ -48,6 +48,8 @@ our $VERSION = $ZoneMinder::Base::VERSION; use Getopt::Std; use Data::UUID; +use vars qw( $verbose $soap_version ); + require ONVIF::Client; require WSDiscovery10::Interfaces::WSDiscovery::WSDiscoveryPort; @@ -77,33 +79,35 @@ sub deserialize_message { # Try deserializing response - there may be some, # even if transport did not succeed (got a 500 response) - if ( $response ) { + if ( ! $response ) { + return; + } + # as our faults are false, returning a success marker is the only # reliable way of determining whether the deserializer succeeded. # Custom deserializers may return an empty list, or undef, # and $@ is not guaranteed to be undefined. - my ($success, $result_body, $result_header) = eval { - (1, $deserializer->deserialize( $response )); - }; - if (defined $success) { - return wantarray - ? ($result_body, $result_header) - : $result_body; - } - elsif (blessed $@) { #}&& $@->isa('SOAP::WSDL::SOAP::Typelib::Fault11')) { - return $@; - } - else { - return $deserializer->generate_fault({ - code => 'soap:Server', - role => 'urn:localhost', - message => "Error deserializing message: $@. \n" - . "Message was: \n$response" - }); - } - }; -} -ub interpret_messages { + my ($success, $result_body, $result_header) = eval { + (1, $deserializer->deserialize( $response )); + }; + if (defined $success) { + return wantarray + ? ($result_body, $result_header) + : $result_body; + } elsif (blessed $@) { #}&& $@->isa('SOAP::WSDL::SOAP::Typelib::Fault11')) { + return $@; + } + + #else + return $deserializer->generate_fault({ + code => 'soap:Server', + role => 'urn:localhost', + message => "Error deserializing message: $@. \n" + . "Message was: \n$response" + }); +} # end sub deserialize_message + +sub interpret_messages { my ($svc_discover, $services, @responses ) = @_; my @results; @@ -167,6 +171,7 @@ ub interpret_messages { # functions sub discover { + my ( $soap_version ) = @_; my @results; ## collect all responses @@ -246,6 +251,8 @@ sub discover { } sub profiles { + my ( $client ) = @_; + my $result = $client->get_endpoint('media')->GetProfiles( { } ,, ); die $result if not $result; if($verbose) { @@ -293,7 +300,7 @@ sub profiles { } sub move { - my ($dir) = @_; + my ($client, $dir) = @_; my $result = $client->get_endpoint('ptz')->GetNodes( { } ,, ); @@ -302,6 +309,7 @@ sub move { } # end sub move sub metadata { + my ( $client ) = @_; my $result = $client->get_endpoint('media')->GetMetadataConfigurations( { } ,, ); die $result if not $result; print $result . "\n";