From 5a052c47d1ac6cb374c80cfdbb10af43cee916c8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 26 Oct 2017 09:16:52 -0700 Subject: [PATCH 01/47] Allow 0 preeventimage count --- web/skins/classic/views/js/monitor.js.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/monitor.js.php b/web/skins/classic/views/js/monitor.js.php index 97a60dd8c..470bb92b8 100644 --- a/web/skins/classic/views/js/monitor.js.php +++ b/web/skins/classic/views/js/monitor.js.php @@ -97,7 +97,7 @@ function validateForm( form ) { errors[errors.length] = ""; if ( !form.elements['newMonitor[WarmupCount]'].value || !(parseInt(form.elements['newMonitor[WarmupCount]'].value) >= 0 ) ) errors[errors.length] = ""; - if ( !form.elements['newMonitor[PreEventCount]'].value || !(parseInt(form.elements['newMonitor[PreEventCount]'].value) > 0 ) || (parseInt(form.elements['newMonitor[PreEventCount]'].value) > parseInt(form.elements['newMonitor[ImageBufferCount]'].value)) ) + if ( !form.elements['newMonitor[PreEventCount]'].value || !(parseInt(form.elements['newMonitor[PreEventCount]'].value) >= 0 ) || (parseInt(form.elements['newMonitor[PreEventCount]'].value) > parseInt(form.elements['newMonitor[ImageBufferCount]'].value)) ) errors[errors.length] = ""; if ( !form.elements['newMonitor[PostEventCount]'].value || !(parseInt(form.elements['newMonitor[PostEventCount]'].value) >= 0 ) ) errors[errors.length] = ""; From c16e1011200212eca6e7a905921c6a9d4aa021d6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 27 Oct 2017 20:52:08 -0700 Subject: [PATCH 02/47] rough in add monitors import wizard --- web/ajax/add_monitors.php | 209 +++++++++++++++++++++ web/skins/classic/views/add_monitors.php | 112 +++++++++++ web/skins/classic/views/js/add_monitors.js | 89 +++++++++ 3 files changed, 410 insertions(+) create mode 100644 web/ajax/add_monitors.php create mode 100644 web/skins/classic/views/add_monitors.php create mode 100644 web/skins/classic/views/js/add_monitors.js diff --git a/web/ajax/add_monitors.php b/web/ajax/add_monitors.php new file mode 100644 index 000000000..b95f0e8f4 --- /dev/null +++ b/web/ajax/add_monitors.php @@ -0,0 +1,209 @@ +set(array( + 'StorageId' => 1, + 'ServerId' => 'auto', + 'Function' => 'Record', + 'Type' => 'Ffmpeg', + 'Enabled' => '1', + 'Colour' => '4', // 32bit + 'PreEventCount' => 0, +) ); + +function probe( &$url_bits ) { + global $defaultMonitor; + $available_streams = array(); + if ( ! isset($url_bits['port']) ) { + // No port given, do a port scan + foreach ( range( 2000, 2007 ) as $port ) { + $socket = socket_create( AF_INET, SOCK_STREAM, SOL_TCP ); + socket_set_option( $socket, + SOL_SOCKET, // socket level + SO_SNDTIMEO, // timeout option + array( + "sec"=>0, // Timeout in seconds + "usec"=>500 // I assume timeout in microseconds + ) + ); + $new_stream = null; +Info("Testing connection to " . $url_bits['host'].':'.$port); + if ( socket_connect( $socket, $url_bits['host'], $port ) ) { + $new_stream = $url_bits; // make a copy + $new_stream['port'] = $port; + } else { + socket_close($socket); + Info("No connection to ".$url_bits['host'] . " on port $port"); + continue; + } + if ( $new_stream ) { + if ( ! isset($new_stream['scheme'] ) ) + $new_stream['scheme'] = 'http'; + $url = unparse_url($new_stream, array('path'=>'/', 'query'=>'action=snapshot')); + list($width, $height, $type, $attr) = getimagesize( $url ); + Info("Got $width x $height from $url"); + $new_stream['Width'] = $width; + $new_stream['Height'] = $height; + + //try { + //if ( $response = do_request( 'GET', $url ) ) { + //$new_stream['path'] = '/'; + //$new_stream['query'] = '?action=stream'; +//$image = imagecreatefromstring($response); + ////$size = getimagesize( $image ); + // + //} else { + //Info("No response from $url"); + //} + //} catch ( EXception $e ) { + //Info("No response from $url"); + //} + $available_streams[] = $new_stream; + } // end if new_Stream + } // end foreach port to scan + } else { + // A port was specified, so don't need to port scan. + $available_streams[] = $url_bits; + } + foreach ( $available_streams as &$stream ) { + # check for existence in db. + $stream['url'] = unparse_url( $stream, array( 'path'=>'/','query'=>'action=stream' ) ); + $monitors = Monitor::find_all( array( 'Path'=>$stream['url'] ) ); + if ( count($monitors ) ) { + $stream['Monitor'] = $monitors[0]; + if ( isset( $stream['Width'] ) and ( $stream['Monitor']->Width() != $stream['Width'] ) ) { + $stream['Warning'] .= 'Monitor width ('.$stream['Monitor']->Width().') and stream width ('.$stream['Width'].") do not match!\n"; + } + if ( isset( $stream['Height'] ) and ( $stream['Monitor']->Height() != $stream['Height'] ) ) { + $stream['Warning'] .= 'Monitor height ('.$stream['Monitor']->Height().') and stream width ('.$stream['Height'].") do not match!\n"; + } + } else { + $stream['Monitor'] = $defaultMonitor; + if ( isset($stream['Width']) ) { + $stream['Monitor']->Width( $stream['Width'] ); + $stream['Monitor']->Height( $stream['Height'] ); + } + } // Monitor found or not + } // end foreach Stream + + #$macCommandString = 'arp ' . $url_bits['host'] . " | awk 'BEGIN{ i=1; } { i++; if(i==3) print $3 }'"; + #$mac = exec($macCommandString); + #Info("Mac $mac"); + return $available_streams; +} // end function probe + +if ( canEdit( 'Monitors' ) ) { + switch ( $_REQUEST['action'] ) { + case 'probe' : + { + $available_streams = array(); + $url_bits = null; + if ( preg_match('/(\d+)\.(\d+)\.(\d+)\.(\d+)/', $_REQUEST['url'] ) ) { + $url_bits = array( 'host'=>$_REQUEST['url'] ); + } else { + $url_bits = parse_url( $_REQUEST['url'] ); + } + +if ( 0 ) { + // Shortcut test + $monitors = Monitor::find_all( array( 'Path'=>$_REQUEST['url'] ) ); + if ( count( $monitors ) ) { + Info("Monitor found for " . $_REQUEST['url']); + $url_bits['url'] = $_REQUEST['url']; + $url_bits['Monitor'] = $monitors[0]; + $available_stream[] = $url_bits; + ajaxResponse( array ( 'Streams'=>$available_streams) ); + return; + } # end url already has a monitor +} + + if ( ! $url_bits ) { + ajaxError("The given URL was too malformed to parse."); + return; + } + + $available_streams = probe( $url_bits ); + + ajaxResponse( array('Streams'=>$available_streams) ); + return; + } // end case url_probe + case 'import': + { + + $file = $_FILES['import_file']; + + if ($file["error"] > 0) { + ajaxError($file["error"]); + return; + } else { + $filename = $file["name"]; + + $available_streams = array(); + $row = 1; + if (($handle = fopen($file['tmp_name'], 'r')) !== FALSE) { + while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) { + $name = $data[0]; + $url = $data[1]; + $group = $data[2]; + Info("Have the following line data $name $url $group"); + + $url_bits = null; + if ( preg_match('/(\d+)\.(\d+)\.(\d+)\.(\d+)/', $url) ) { + $url_bits = array( 'host'=>$url, 'scheme'=>'http' ); + } else { + $url_bits = parse_url( $url ); + } + if ( ! $url_bits ) { + Info("Bad url, skipping line $name $url $group"); + continue; + } + + $available_streams += probe( $url_bits ); + + //$url_bits['url'] = unparse_url( $url_bits ); + //$url_bits['Monitor'] = $defaultMonitor; + //$url_bits['Monitor']->Name( $name ); + //$url_bits['Monitor']->merge( $_POST['newMonitor'] ); + //$available_streams[] = $url_bits; + + } // end while rows + fclose($handle); + ajaxResponse( array('Streams'=>$available_streams) ); + } else { + ajaxError("Uploaded file does not exist"); + return; + } + + } + } // end case import + default: + { + Warning("unknown action " . $_REQUEST['action'] ); + } // end ddcase default + } +} else { + Warning("Cannot edit monitors" ); +} + +ajaxError( 'Unrecognised action or insufficient permissions' ); + +?> diff --git a/web/skins/classic/views/add_monitors.php b/web/skins/classic/views/add_monitors.php new file mode 100644 index 000000000..61f26c4d5 --- /dev/null +++ b/web/skins/classic/views/add_monitors.php @@ -0,0 +1,112 @@ + + +
+ +
+ +
+
+
+
Results +
+ +
+
+
+
+
Enter by IP or URL + + +
+
Import CSV Spreadsheet + Spreadsheet should have the following format:
+ + + + + + + + + + + +
NameURLGroup
Example Name MN1-30 INQ37.01http://10.34.152.20:2001/?action=streamMN1
+ Defaults to apply to each monitor:
+ + +Id()] = $S; + } + + if ( count($ServersById) > 0 ) { ?> + +Id()] = $S; + } + if ( count($StorageById) > 0 ) { +?> + + + +
SettingValue
+ +
+ 'Auto')+$ServersById, '' ); ?> +
+'All')+$StorageById, 1 ); ?> +
+ + + +
+
+ +
+
+
+ diff --git a/web/skins/classic/views/js/add_monitors.js b/web/skins/classic/views/js/add_monitors.js new file mode 100644 index 000000000..a94fd2200 --- /dev/null +++ b/web/skins/classic/views/js/add_monitors.js @@ -0,0 +1,89 @@ + +var probeReq = new Request.JSON( { url:thisUrl, method: 'get', timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getProbeResponse } ); + +function probe( url_e ) { + probeReq.send( "request=add_monitors&action=probe&url="+url_e.value ); +} + +var ProbeResults; + +function getProbeResponse( respObj, respText ) { + if ( checkStreamForErrors( "getProbeResponse", respObj ) ) + return; +//alert(respText); + + if ( respObj.Streams ) { + parseStreams( respObj.Streams ); + } else { + alert("No Streams"); + } +} // end function getProbeResponse + +function parseStreams( Streams ) { + ProbeResults = Array(); + + var results_div = $j('#url_results')[0]; + if ( ! results_div ) { + console.log("No results div found."); + return; + } + results_div.innerHTML = ''; + var html = ''; + + for( i in Streams ) { + var stream = Streams[i]; + if ( stream.url ) { + html += '

'+stream.url; + if ( stream.Monitor.Id ) { + html += ' is already entered into the system by Monitor ' + stream.Monitor.Id + ' ' + stream.Monitor.Name + '
'; + html += ''; + } else { + html += ''; + } + html += '

'; + ProbeResults[stream.url] = stream; + } else { + //console.log(stream); + } + } // end for eah Stream + + results_div.innerHTML = html; +} + +function addMonitor(url) { + if ( ! ProbeResults[url] ) { + alert("Monitor for url " + url + " not found in probe results." ); + return; + } + var Stream = ProbeResults[url]; + var Monitor = Stream.Monitor; + + popup_url = '?view=monitor&newMonitor[Path]='+url; + keys = Object.keys( Monitor ); + for ( i in Monitor ) { + if ( ! Monitor[i] ) + continue; + if ( Monitor[i] == 'null' ) + Monitor[i]=''; + popup_url += '&newMonitor['+i+']='+Monitor[i]; + } + createPopup( popup_url, 'zmMonitor0', 'monitor' ); +} + +function import_csv( form ) { + var formData = new FormData( form ); + console.log(formData); + //formData.append('file', $('#file')[0].files[0]); + + $j.ajax({ + url : thisUrl+"?request=add_monitors&action=import", + type : 'POST', + data : formData, + processData: false, // tell jQuery not to process the data + contentType: false, // tell jQuery not to set contentType + success : function(data) { + var json = JSON.parse(data); + parseStreams( json.Streams ); + } + }); +} From cb01b96dc092130dd5af4137efe0973a30473b66 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 1 Nov 2017 12:01:11 -0700 Subject: [PATCH 03/47] fixes --- scripts/ZoneMinder/lib/ZoneMinder/Event.pm | 33 +++++++++- scripts/ZoneMinder/lib/ZoneMinder/Logger.pm | 14 ++-- scripts/ZoneMinder/lib/ZoneMinder/Object.pm | 73 ++++++++++++--------- 3 files changed, 84 insertions(+), 36 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm index 3e877205d..2fc590977 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Event.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Event.pm @@ -48,9 +48,38 @@ use ZoneMinder::Logger qw(:all); use ZoneMinder::Database qw(:all); require Date::Parse; -use vars qw/ $table $primary_key /; +use vars qw/ $table $primary_key %fields $serial @identified_by/; $table = 'Events'; -$primary_key = 'Id'; +@identified_by = ('Id'); +$serial = $primary_key = 'Id'; +%fields = map { $_, $_ } qw( + Id + MonitorId + StorageId + Name + Cause + StartTime + EndTime + Width + Height + Length + Frames + AlarmFrames + DefaultVideo + TotScore + AvgScore + MaxScore + Archived + Videoed + Uploaded + Emailed + Messaged + Executed + Notes + StateId + Orientation + DiskSpace +); use POSIX; diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm index 8bdbe3f7f..f8033800f 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Logger.pm @@ -678,7 +678,10 @@ sub Dump { fetch()->logPrint( DEBUG, Data::Dumper->Dump( [ $var ], [ $label ] ) ); } -sub debug { $_[0]->logPrint( DEBUG, @_ ); } +sub debug { + my $log = shift; + $log->logPrint( DEBUG, @_ ); + } sub Debug( @ ) { fetch()->logPrint( DEBUG, @_ ); @@ -688,7 +691,8 @@ sub Info( @ ) { fetch()->logPrint( INFO, @_ ); } sub info { - $_[0]->logPrint( INFO, @_ ); + my $log = shift; + $log->logPrint( INFO, @_ ); } @@ -696,14 +700,16 @@ sub Warning( @ ) { fetch()->logPrint( WARNING, @_ ); } sub warn { - $_[0]->logPrint( WARNING, @_ ); + my $log = shift; + $log->logPrint( WARNING, @_ ); } sub Error( @ ) { fetch()->logPrint( ERROR, @_ ); } sub error { - $_[0]->logPrint( ERROR, @_ ); + my $log = shift; + $log->logPrint( ERROR, @_ ); } sub Fatal( @ ) { diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Object.pm b/scripts/ZoneMinder/lib/ZoneMinder/Object.pm index dfcc02ea9..e06486bf0 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Object.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Object.pm @@ -48,7 +48,7 @@ use vars qw/ $AUTOLOAD $log $dbh/; *dbh = \$ZoneMinder::Database::dbh; my $debug = 1; -use constant DEBUG_ALL=>0; +use constant DEBUG_ALL=>1; sub new { my ( $parent, $id, $data ) = @_; @@ -185,8 +185,11 @@ $log->debug("No serial") if $debug; next; } if ( ! $$self{$id} ) { - ($$self{$id}) = ($sql{$$fields{$id}}) = $local_dbh->selectrow_array( q{SELECT nextval('} . $serial{$id} . q{')} ); - $log->debug("SQL statement execution SELECT nextval('$serial{$id}') returned $$self{$id}") if $debug or DEBUG_ALL; + my $s = qq{SELECT `auto_increment` FROM INFORMATION_SCHEMA.TABLES WHERE table_name = '$table'}; + + ($$self{$id}) = ($sql{$$fields{$id}}) = $local_dbh->selectrow_array( $s ); + #($$self{$id}) = ($sql{$$fields{$id}}) = $local_dbh->selectrow_array( q{SELECT nextval('} . $serial{$id} . q{')} ); + $log->debug("SQL statement execution SELECT $s returned $$self{$id}") if $debug or DEBUG_ALL; $insert = 1; } # end if } # end foreach @@ -224,22 +227,28 @@ $log->debug("No serial") if $debug; } # end if } # end if } else { # not identified_by - @identified_by = ('id') if ! @identified_by; - my $need_serial = ! ( @identified_by == map { $$self{$_} ? $_ : () } @identified_by ); + @identified_by = ('Id') if ! @identified_by; + + # If the size of the arrays are not equal which means one or more are missing + my @identified_by_without_values = map { $$self{$_} ? () : $_ } @identified_by; + my $need_serial = @identified_by_without_values > 0; if ( $force_insert or $need_serial ) { if ( $need_serial ) { if ( $serial ) { - @$self{@identified_by} = @sql{@$fields{@identified_by}} = $local_dbh->selectrow_array( q{SELECT nextval('} . $serial . q{')} ); + my $s = qq{SELECT `auto_increment` FROM INFORMATION_SCHEMA.TABLES WHERE table_name = '$table'}; + @$self{@identified_by} = @sql{@$fields{@identified_by}} = $local_dbh->selectrow_array( $s ); +#@$self{@identified_by} = @sql{@$fields{@identified_by}} = $local_dbh->selectrow_array( q{SELECT nextval('} . $serial . q{')} ); if ( $local_dbh->errstr() ) { $log->error("Error getting next id. " . $local_dbh->errstr() ); - $log->error("SQL statement execution SELECT nextval('$serial') returned ".join(',',@$self{@identified_by})); + $log->error("SQL statement execution $s returned ".join(',',@$self{@identified_by})); } elsif ( $debug or DEBUG_ALL ) { - $log->debug("SQL statement execution SELECT nextval('$serial') returned ".join(',',@$self{@identified_by})); + $log->debug("SQL statement execution $s returned ".join(',',@$self{@identified_by})); } # end if } # end if } # end if + my @keys = keys %sql; my $command = "INSERT INTO $table (" . join(',', @keys ) . ') VALUES (' . join(',', map { '?' } @sql{@keys} ) . ')'; if ( ! ( $_ = $local_dbh->prepare($command) and $_->execute( @sql{@keys} ) ) ) { @@ -257,7 +266,9 @@ $log->debug("No serial") if $debug; } else { delete $sql{created_on}; my @keys = keys %sql; - @keys = sets::exclude( [ @$fields{@identified_by} ], \@keys ); + my %identified_by = map { $_, $_ } @identified_by; + + @keys = map { $identified_by{$_} ? () : $$fields{$_} } @keys; my $command = "UPDATE $table SET " . join(',', map { $_ . ' = ?' } @keys ) . ' WHERE ' . join(' AND ', map { $$fields{$_} .'= ?' } @identified_by ); if ( ! ( $_ = $local_dbh->prepare($command) and $_->execute( @sql{@keys}, @sql{@$fields{@identified_by}} ) ) ) { my $error = $local_dbh->errstr; @@ -294,30 +305,32 @@ sub set { my $type = ref $self; my %fields = eval ('%'.$type.'::fields'); if ( ! %fields ) { - $log->warn('ZoneMinder::Object::set called on an object with no fields'); + $log->warn("ZoneMinder::Object::set called on an object ($type) with no fields".$@); } # end if my %defaults = eval('%'.$type.'::defaults'); if ( ref $params ne 'HASH' ) { my ( $caller, undef, $line ) = caller; - $openprint::log->error("$type -> set called with non-hash params from $caller $line"); + $log->error("$type -> set called with non-hash params from $caller $line"); } foreach my $field ( keys %fields ) { -$log->debug("field: $field, param: ".$$params{$field}) if $debug; - if ( exists $$params{$field} ) { -$openprint::log->debug("field: $field, $$self{$field} =? param: ".$$params{$field}) if $debug; - if ( ( ! defined $$self{$field} ) or ($$self{$field} ne $params->{$field}) ) { + if ( $params ) { + $log->debug("field: $field, param: ".$$params{$field}) if $debug; + if ( exists $$params{$field} ) { + $log->debug("field: $field, $$self{$field} =? param: ".$$params{$field}) if $debug; + if ( ( ! defined $$self{$field} ) or ($$self{$field} ne $params->{$field}) ) { # Only make changes to fields that have changed - if ( defined $fields{$field} ) { - $$self{$field} = $$params{$field} if defined $fields{$field}; - push @set_fields, $fields{$field}, $$params{$field}; #mark for sql updating - } # end if -$openprint::log->debug("Running $field with $$params{$field}") if $debug; - if ( my $func = $self->can( $field ) ) { - $func->( $self, $$params{$field} ); - } # end if - } # end if - } # end if + if ( defined $fields{$field} ) { + $$self{$field} = $$params{$field} if defined $fields{$field}; + push @set_fields, $fields{$field}, $$params{$field}; #mark for sql updating + } # end if + $log->debug("Running $field with $$params{$field}") if $debug; + if ( my $func = $self->can( $field ) ) { + $func->( $self, $$params{$field} ); + } # end if + } # end if + } # end if + } # end if $params if ( defined $fields{$field} ) { if ( $$self{$field} ) { @@ -356,7 +369,7 @@ sub transform { if ( defined $$fields{$_[1]} ) { my @transforms = eval('@{$'.$type.'::transforms{$_[1]}}'); - $openprint::log->debug("Transforms for $_[1] before $_[2]: @transforms") if $debug; + $log->debug("Transforms for $_[1] before $_[2]: @transforms") if $debug; if ( @transforms ) { foreach my $transform ( @transforms ) { if ( $transform =~ /^s\// or $transform =~ /^tr\// ) { @@ -366,15 +379,15 @@ sub transform { $value = undef; } # end if } else { - $openprint::log->debug("evalling $value ".$transform . " Now value is $value" ); + $log->debug("evalling $value ".$transform . " Now value is $value" ); eval '$value '.$transform; - $openprint::log->error("Eval error $@") if $@; + $log->error("Eval error $@") if $@; } - $openprint::log->debug("After $transform: $value") if $debug; + $log->debug("After $transform: $value") if $debug; } # end foreach } # end if } else { - $openprint::log->error("Object::transform ($_[1]) not in fields for $type"); + $log->error("Object::transform ($_[1]) not in fields for $type"); } # end if return $value; From 5aa61cf1f5c0802990e95b67f16d2130893948da Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 2 Nov 2017 07:59:25 -0400 Subject: [PATCH 04/47] unset the ref so that last monitor isn't duplicated --- web/skins/classic/views/console.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index b9fc80633..fb5785c92 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -122,10 +122,11 @@ for ( $i = 0; $i < count($displayMonitors); $i++ ) { $sql = 'SELECT '.join($counts,', ').' FROM Events as E where MonitorId = ?'; $counts = dbFetchOne( $sql, NULL, array($monitor['Id']) ); if ( $counts ) - $displayMonitors[$i] = $monitor = array_merge( $monitor, $counts ); + $monitor = array_merge( $monitor, $counts ); for ( $j = 0; $j < count($eventCounts); $j += 1 ) { $eventCounts[$j]['total'] += $monitor['EventCount'.$j]; } + unset($monitor); } $cycleWidth = $maxWidth; $cycleHeight = $maxHeight; From a8b679e4797b1179b54ef3221a16e480febf2c78 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 2 Nov 2017 11:45:33 -0400 Subject: [PATCH 05/47] set frameCount for audio packets too so that a long period of just audio will return and update lastframesent etc. --- src/zm_ffmpeg_camera.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 3339f2958..4b6e5e4ee 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -964,7 +964,7 @@ else if ( packet.pts && video_last_pts > packet.pts ) { zm_av_packet_unref( &packet ); continue; } - + #if HAVE_AVUTIL_HWCONTEXT_H } #endif @@ -980,8 +980,6 @@ else if ( packet.pts && video_last_pts > packet.pts ) { } #endif - Debug( 4, "Decoded video packet at frame %d", frameCount ); - if ( frameComplete ) { Debug( 4, "Got frame %d", frameCount ); @@ -1012,6 +1010,7 @@ else if ( packet.pts && video_last_pts > packet.pts ) { Debug( 3, "Not framecomplete after av_read_frame" ); } // end if frameComplete } else if ( packet.stream_index == mAudioStreamId ) { //FIXME best way to copy all other streams + frameComplete = 1; if ( videoStore ) { if ( record_audio ) { if ( have_video_keyframe ) { From 495cd580aafdc7ca9014109e5b2d4662c40d1f26 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 2 Nov 2017 11:45:49 -0400 Subject: [PATCH 06/47] add more debugging --- src/zm_monitorstream.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/zm_monitorstream.cpp b/src/zm_monitorstream.cpp index 6c3f7b144..010877b90 100644 --- a/src/zm_monitorstream.cpp +++ b/src/zm_monitorstream.cpp @@ -563,14 +563,22 @@ void MonitorStream::runStream() { while ( !zm_terminate ) { bool got_command = false; if ( feof( stdout ) || ferror( stdout ) || !monitor->ShmValid() ) { + if ( feof( stdout ) ) { + Debug(2,"feof stdout"); + } else if ( ferror( stdout ) ) { + Debug(2,"ferror stdout"); + } else if ( !monitor->ShmValid() ) { + Debug(2,"monitor not valid.... maybe we should wait until it comes back."); + } break; } gettimeofday( &now, NULL ); if ( connkey ) { -Debug(2, "checking command Queue for connkey: %d", connkey ); +//Debug(2, "checking command Queue for connkey: %d", connkey ); while(checkCommandQueue()) { +Debug(2, "Have checking command Queue for connkey: %d", connkey ); got_command = true; } } @@ -659,8 +667,10 @@ Debug(2, "checking command Queue for connkey: %d", connkey ); // Send the next frame Monitor::Snapshot *snap = &monitor->image_buffer[index]; - if ( !sendFrame( snap->image, snap->timestamp ) ) + if ( !sendFrame( snap->image, snap->timestamp ) ) { + Debug(2, "sendFrame failed, quiting."); zm_terminate = true; + } memcpy( &last_frame_timestamp, snap->timestamp, sizeof(last_frame_timestamp) ); //frame_sent = true; @@ -697,9 +707,12 @@ Debug(2, "checking command Queue for connkey: %d", connkey ); } // end if buffered playback frame_count++; } + unsigned long sleep_time = (unsigned long)((1000000 * ZM_RATE_BASE)/((base_fps?base_fps:1)*abs(replay_rate*2))); + Debug(2, "Sleeping for (%d)", sleep_time); usleep( (unsigned long)((1000000 * ZM_RATE_BASE)/((base_fps?base_fps:1)*abs(replay_rate*2))) ); if ( ttl ) { if ( (now.tv_sec - stream_start_time) > ttl ) { + Debug(2, "now(%d) - start(%d) > ttl(%d) break", now.tv_sec, stream_start_time, ttl); break; } } From 31b756bd53e9fe3b481e8c98241287d68fd4c4b3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 3 Nov 2017 07:18:30 -0400 Subject: [PATCH 07/47] add missing tests for StartDateTime etc --- scripts/ZoneMinder/lib/ZoneMinder/Filter.pm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm index 07dd659cc..02209a55c 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Filter.pm @@ -224,7 +224,7 @@ sub Sql { || $term->{attr} eq 'Notes' ) { $value = "'$temp_value'"; - } elsif ( $term->{attr} eq 'DateTime' ) { + } elsif ( $term->{attr} eq 'DateTime' or $term->{attr} eq 'StartDateTime' or $term->{attr} eq 'EndDateTime' ) { $value = DateTimeToSQL( $temp_value ); if ( !$value ) { Error( "Error parsing date/time '$temp_value', " @@ -232,7 +232,7 @@ sub Sql { return; } $value = "'$value'"; - } elsif ( $term->{attr} eq 'Date' ) { + } elsif ( $term->{attr} eq 'Date' or $term->{attr} eq 'StartDate' or $term->{attr} eq 'EndDate' ) { $value = DateTimeToSQL( $temp_value ); if ( !$value ) { Error( "Error parsing date/time '$temp_value', " @@ -240,7 +240,7 @@ sub Sql { return; } $value = "to_days( '$value' )"; - } elsif ( $term->{attr} eq 'Time' ) { + } elsif ( $term->{attr} eq 'Time' or $term->{attr} eq 'StartTime' or $term->{attr} eq 'EndTime' ) { $value = DateTimeToSQL( $temp_value ); if ( !$value ) { Error( "Error parsing date/time '$temp_value', " From 4ef28bb30dcdd36d468553b6fc036ae07fa89160 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 3 Nov 2017 09:22:43 -0400 Subject: [PATCH 08/47] don't put the leading / in the cache link --- web/includes/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index 6a94bb8ef..2f201c6e3 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -2064,7 +2064,7 @@ function cache_bust( $file ) { # Use the last modified timestamp to create a link that gets a different filename # To defeat caching. Should probably use md5 hash $parts = pathinfo($file); - $cacheFile = '/cache/'.$parts['filename'].'-'.filemtime($file).'.'.$parts['extension']; + $cacheFile = 'cache/'.$parts['filename'].'-'.filemtime($file).'.'.$parts['extension']; if ( file_exists( ZM_PATH_WEB.$cacheFile ) or symlink( ZM_PATH_WEB.'/'.$file, ZM_PATH_WEB.$cacheFile ) ) { return $cacheFile; } else { From fdbd344d742a4a1bd57e0101eaad58c925b531ef Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 3 Nov 2017 09:23:08 -0400 Subject: [PATCH 09/47] whitespace --- src/zm_videostore.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 208f64818..c8704eae0 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -823,19 +823,19 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) { int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { Debug(4, "writeAudioFrame"); - if (!audio_out_stream) { + if ( !audio_out_stream ) { Debug(1, "Called writeAudioFramePacket when no audio_out_stream"); return 0; // FIXME -ve return codes do not free packet in ffmpeg_camera at // the moment } - if (audio_out_codec) { + if ( audio_out_codec ) { Debug(3, "Have audio codec"); #ifdef HAVE_LIBAVRESAMPLE #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) ret = avcodec_send_packet(audio_in_ctx, ipkt); - if (ret < 0) { + if ( ret < 0 ) { Error("avcodec_send_packet fail %s", av_make_error_string(ret).c_str()); return 0; } From 073c06f6a872e24efc6a999f14d140b3c0dbb06a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 3 Nov 2017 09:23:50 -0400 Subject: [PATCH 10/47] fix sizing after switching scale. basically re-apply the layout --- web/skins/classic/views/js/montage.js | 41 +++++++++++++++++++-------- 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/web/skins/classic/views/js/montage.js b/web/skins/classic/views/js/montage.js index 97fee5998..5927c9b39 100644 --- a/web/skins/classic/views/js/montage.js +++ b/web/skins/classic/views/js/montage.js @@ -8,7 +8,7 @@ function Monitor( monitorData ) { this.alarmState = STATE_IDLE; this.lastAlarmState = STATE_IDLE; this.streamCmdParms = "view=request&request=stream&connkey="+this.connKey; - this.onclick=monitorData.onclick; + this.onclick = monitorData.onclick; if ( auth_hash ) this.streamCmdParms += '&auth='+auth_hash; this.streamCmdTimer = null; @@ -34,6 +34,7 @@ function Monitor( monitorData ) { this.streamCmdTimer = clearTimeout( this.streamCmdTimer ); var stream = $j('#liveStream'+this.id)[0]; + if ( respObj.result == 'Ok' ) { this.status = respObj.status; this.alarmState = this.status.state; @@ -97,15 +98,17 @@ function Monitor( monitorData ) { } } // end if Ok or not var streamCmdTimeout = statusRefreshTimeout; - if ( this.alarmState == STATE_ALARM || this.alarmState == STATE_ALERT ) - streamCmdTimeout = streamCmdTimeout/5; + // The idea here is if we are alarmed, do updates faster. However, there is a timeout in the php side which isn't getting modified, so this may cause a problem. Also the server may only be able to update so fast. + //if ( this.alarmState == STATE_ALARM || this.alarmState == STATE_ALERT ) { + //streamCmdTimeout = streamCmdTimeout/5; + //} this.streamCmdTimer = this.streamCmdQuery.delay( streamCmdTimeout, this ); this.lastAlarmState = this.alarmState; }; this.streamCmdQuery = function( resent ) { - //if ( resent ) - //console.log( this.connKey+": Resending" ); + if ( resent ) + console.log( this.connKey+": Resending" ); //this.streamCmdReq.cancel(); this.streamCmdReq.send( this.streamCmdParms+"&command="+CMD_QUERY ); }; @@ -231,13 +234,32 @@ function changeSize() { function changeScale() { var scale = $('scale').get('value'); - + $('width').set('value', ''); + $('height').set('value', ''); + Cookie.write( 'zmMontageScale', scale, { duration: 10*365 } ); + Cookie.write( 'zmMontageWidth', '', { duration: 10*365 } ); + Cookie.write( 'zmMontageHeight', '', { duration: 10*365 } ); + if ( ! scale ) { + selectLayout('#zmMontageLayout'); + return; + } for ( var x = 0; x < monitors.length; x++ ) { var monitor = monitors[x]; var newWidth = ( monitorData[x].width * scale ) / SCALE_BASE; var newHeight = ( monitorData[x].height * scale ) / SCALE_BASE; + + // Scale the frame + monitor_frame = $j('#monitorFrame'+monitor.id); + if ( ! monitor_frame ) { + console.log("Error finding frame for " + monitor.id ); + continue; + } + if ( width ) + monitor_frame.css('width',width+'px'); + if ( height ) + monitor_frame.css('height',height+'px'); /*Stream could be an applet so can't use moo tools*/ - var streamImg = document.getElementById( 'liveStream'+monitor.id ); + var streamImg = $j('#liveStream'+monitor.id )[0]; if ( streamImg ) { if ( streamImg.nodeName == 'IMG' ) { var src = streamImg.src; @@ -258,11 +280,6 @@ function changeScale() { zonesSVG.style.height = newHeight + "px"; } } - $('width').set('value', ''); - $('height').set('value', ''); - Cookie.write( 'zmMontageScale', scale, { duration: 10*365 } ); - Cookie.write( 'zmMontageWidth', '', { duration: 10*365 } ); - Cookie.write( 'zmMontageHeight', '', { duration: 10*365 } ); } function toGrid(value) { From 09938ef7eeaca6eb7da507700620f76084590a1a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 3 Nov 2017 09:24:13 -0400 Subject: [PATCH 11/47] join the echo's into 1 to also get the line breaks --- web/skins/classic/includes/functions.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/includes/functions.php b/web/skins/classic/includes/functions.php index c2b5a14de..450cf63b3 100644 --- a/web/skins/classic/includes/functions.php +++ b/web/skins/classic/includes/functions.php @@ -48,8 +48,10 @@ function xhtmlHeaders( $file, $title ) { <?php echo ZM_WEB_TITLE_PREFIX ?> - <?php echo validHtmlStr($title) ?> \n"; - echo "\n"; + echo " + + +"; } else { echo ' From 67bb8c302faf7e3f3b37afe76a22458d11dd49c8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 3 Nov 2017 10:00:29 -0400 Subject: [PATCH 12/47] add missing / --- web/includes/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index 2f201c6e3..724e9e521 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -2065,7 +2065,7 @@ function cache_bust( $file ) { # To defeat caching. Should probably use md5 hash $parts = pathinfo($file); $cacheFile = 'cache/'.$parts['filename'].'-'.filemtime($file).'.'.$parts['extension']; - if ( file_exists( ZM_PATH_WEB.$cacheFile ) or symlink( ZM_PATH_WEB.'/'.$file, ZM_PATH_WEB.$cacheFile ) ) { + if ( file_exists( ZM_PATH_WEB.'/'.$cacheFile ) or symlink( ZM_PATH_WEB.'/'.$file, ZM_PATH_WEB.'/'.$cacheFile ) ) { return $cacheFile; } else { Warning("Failed linking $file to $cacheFile"); From 54d77519c05a4d8bdcf4b3d0b11965c0824555ba Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 3 Nov 2017 12:03:01 -0400 Subject: [PATCH 13/47] Only show Storage and Server filters if there is more than 1 --- web/skins/classic/views/_monitor_filters.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/views/_monitor_filters.php b/web/skins/classic/views/_monitor_filters.php index 231e4bdce..c8607f845 100644 --- a/web/skins/classic/views/_monitor_filters.php +++ b/web/skins/classic/views/_monitor_filters.php @@ -118,7 +118,7 @@ $groupSql = Group::get_group_sql( $group_id ); ?> 0 ) { +if ( count($ServersById) > 1 ) { ?> 'All')+$ServersById, (isset($_SESSION 0 ) { ?> +if ( count($StorageById) > 1 ) { ?> 'All')+$StorageById, (isset($_SESSION['StorageFilter'])?$_SESSION['StorageFilter']:''), array('onchange'=>'changeFilter(this);') ); From cab8c4cd5ee30d292167547109b5e30f9a4af187 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 3 Nov 2017 13:49:42 -0400 Subject: [PATCH 14/47] cleanup Monitor::Capture. Cleanup the return values from Capture and CaptureAndRecord. <0 is error, 0 is things ok, but no video frame. > 0 means we have a frame. Plus google code style --- src/zm_curl_camera.cpp | 24 +++---- src/zm_ffmpeg_camera.cpp | 8 ++- src/zm_libvlc_camera.cpp | 80 ++++++++--------------- src/zm_monitor.cpp | 91 +++++++++++++-------------- src/zm_remote_camera_http.cpp | 55 +++++++--------- src/zm_remote_camera_rtsp.cpp | 22 +++---- src/zm_stream.cpp | 2 +- web/skins/classic/views/js/montage.js | 20 +++++- 8 files changed, 138 insertions(+), 164 deletions(-) diff --git a/src/zm_curl_camera.cpp b/src/zm_curl_camera.cpp index 3db890bf9..dbd824dad 100644 --- a/src/zm_curl_camera.cpp +++ b/src/zm_curl_camera.cpp @@ -128,10 +128,10 @@ int cURLCamera::Capture( Image &image ) { /* Grab the mutex to ensure exclusive access to the shared data */ lock(); - while (!frameComplete) { + while ( !frameComplete ) { /* If the work thread did a reset, reset our local variables */ - if(bReset) { + if ( bReset ) { SubHeadersParsingComplete = false; frame_content_length = 0; frame_content_type.clear(); @@ -139,25 +139,25 @@ int cURLCamera::Capture( Image &image ) { bReset = false; } - if(mode == MODE_UNSET) { + if ( mode == MODE_UNSET ) { /* Don't have a mode yet. Sleep while waiting for data */ nRet = pthread_cond_wait(&data_available_cond,&shareddata_mutex); - if(nRet != 0) { + if ( nRet != 0 ) { Error("Failed waiting for available data condition variable: %s",strerror(nRet)); return -20; } } - if(mode == MODE_STREAM) { + if ( mode == MODE_STREAM ) { /* Subheader parsing */ - while(!SubHeadersParsingComplete && !need_more_data) { + while( !SubHeadersParsingComplete && !need_more_data ) { size_t crlf_start, crlf_end, crlf_size; std::string subheader; /* Check if the buffer contains something */ - if(databuffer.empty()) { + if ( databuffer.empty() ) { /* Empty buffer, wait for data */ need_more_data = true; break; @@ -165,14 +165,14 @@ int cURLCamera::Capture( Image &image ) { /* Find crlf start */ crlf_start = memcspn(databuffer,"\r\n",databuffer.size()); - if(crlf_start == databuffer.size()) { + if ( crlf_start == databuffer.size() ) { /* Not found, wait for more data */ need_more_data = true; break; } /* See if we have enough data for determining crlf length */ - if(databuffer.size() < crlf_start+5) { + if ( databuffer.size() < crlf_start+5 ) { /* Need more data */ need_more_data = true; break; @@ -183,13 +183,13 @@ int cURLCamera::Capture( Image &image ) { crlf_size = (crlf_start + crlf_end) - crlf_start; /* Is this the end of a previous stream? (This is just before the boundary) */ - if(crlf_start == 0) { + if ( crlf_start == 0 ) { databuffer.consume(crlf_size); continue; } /* Check for invalid CRLF size */ - if(crlf_size > 4) { + if ( crlf_size > 4 ) { Error("Invalid CRLF length"); } @@ -209,7 +209,7 @@ int cURLCamera::Capture( Image &image ) { /* Find where the data in this header starts */ size_t subheader_data_start = subheader.rfind(' '); - if(subheader_data_start == std::string::npos) { + if ( subheader_data_start == std::string::npos ) { subheader_data_start = subheader.find(':'); } diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 4b6e5e4ee..889f2eb6f 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -317,7 +317,7 @@ int FfmpegCamera::Capture( Image &image ) { } // end if packet.stream_index == mVideoStreamId zm_av_packet_unref( &packet ); } // end while ! frameComplete - return (0); + return 1; } // FfmpegCamera::Capture int FfmpegCamera::PostCapture() { @@ -1010,7 +1010,7 @@ else if ( packet.pts && video_last_pts > packet.pts ) { Debug( 3, "Not framecomplete after av_read_frame" ); } // end if frameComplete } else if ( packet.stream_index == mAudioStreamId ) { //FIXME best way to copy all other streams - frameComplete = 1; + frameComplete = 1; if ( videoStore ) { if ( record_audio ) { if ( have_video_keyframe ) { @@ -1032,6 +1032,8 @@ else if ( packet.pts && video_last_pts > packet.pts ) { } else { Debug(4, "Have audio packet, but not recording atm" ); } + zm_av_packet_unref( &packet ); + return 0; } else { #if LIBAVUTIL_VERSION_CHECK(56, 23, 0, 23, 0) Debug( 3, "Some other stream index %d, %s", packet.stream_index, av_get_media_type_string( mFormatContext->streams[packet.stream_index]->codecpar->codec_type) ); @@ -1043,7 +1045,7 @@ else if ( packet.pts && video_last_pts > packet.pts ) { // 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); + return frameCount; } // end FfmpegCamera::CaptureAndRecord diff --git a/src/zm_libvlc_camera.cpp b/src/zm_libvlc_camera.cpp index a4135d352..70d833c31 100644 --- a/src/zm_libvlc_camera.cpp +++ b/src/zm_libvlc_camera.cpp @@ -23,8 +23,7 @@ #if HAVE_LIBVLC // Do all the buffer checking work here to avoid unnecessary locking -void* LibvlcLockBuffer(void* opaque, void** planes) -{ +void* LibvlcLockBuffer(void* opaque, void** planes) { LibvlcPrivateData* data = (LibvlcPrivateData*)opaque; data->mutex.lock(); @@ -36,15 +35,12 @@ void* LibvlcLockBuffer(void* opaque, void** planes) return NULL; } -void LibvlcUnlockBuffer(void* opaque, void* picture, void *const *planes) -{ +void LibvlcUnlockBuffer(void* opaque, void* picture, void *const *planes) { LibvlcPrivateData* data = (LibvlcPrivateData*)opaque; bool newFrame = false; - for(uint32_t i = 0; i < data->bufferSize; i++) - { - if(data->buffer[i] != data->prevBuffer[i]) - { + for( uint32_t i = 0; i < data->bufferSize; i++ ) { + if ( data->buffer[i] != data->prevBuffer[i] ) { newFrame = true; break; } @@ -54,8 +50,7 @@ void LibvlcUnlockBuffer(void* opaque, void* picture, void *const *planes) time_t now; time(&now); // Return frames slightly faster than 1fps (if time() supports greater than one second resolution) - if(newFrame || difftime(now, data->prevTime) >= 0.8) - { + if ( newFrame || difftime(now, data->prevTime) >= 0.8 ) { data->prevTime = now; data->newImage.updateValueSignal(true); } @@ -90,58 +85,46 @@ LibvlcCamera::LibvlcCamera( int p_id, const std::string &p_path, const std::stri Panic("Unexpected colours: %d",colours); } - if ( capture ) - { + if ( capture ) { Initialise(); } } -LibvlcCamera::~LibvlcCamera() -{ - if ( capture ) - { +LibvlcCamera::~LibvlcCamera() { + if ( capture ) { Terminate(); } - if(mLibvlcMediaPlayer != NULL) - { + if ( mLibvlcMediaPlayer != NULL ) { libvlc_media_player_release(mLibvlcMediaPlayer); mLibvlcMediaPlayer = NULL; } - if(mLibvlcMedia != NULL) - { + if ( mLibvlcMedia != NULL ) { libvlc_media_release(mLibvlcMedia); mLibvlcMedia = NULL; } - if(mLibvlcInstance != NULL) - { + if ( mLibvlcInstance != NULL ) { libvlc_release(mLibvlcInstance); mLibvlcInstance = NULL; } - if (mOptArgV != NULL) - { + if ( mOptArgV != NULL ) { delete[] mOptArgV; } } -void LibvlcCamera::Initialise() -{ +void LibvlcCamera::Initialise() { } -void LibvlcCamera::Terminate() -{ +void LibvlcCamera::Terminate() { libvlc_media_player_stop(mLibvlcMediaPlayer); - if(mLibvlcData.buffer != NULL) - { + if(mLibvlcData.buffer != NULL) { zm_freealigned(mLibvlcData.buffer); } - if(mLibvlcData.prevBuffer != NULL) - { + if(mLibvlcData.prevBuffer != NULL) { zm_freealigned(mLibvlcData.prevBuffer); } } -int LibvlcCamera::PrimeCapture() -{ +int LibvlcCamera::PrimeCapture() { Info("Priming capture from %s", mPath.c_str()); StringVector opVect = split(Options(), ","); @@ -154,8 +137,7 @@ int LibvlcCamera::PrimeCapture() else if ( Method() == "rtpRtspHttp" ) opVect.push_back("--rtsp-http"); - if (opVect.size() > 0) - { + if ( opVect.size() > 0 ) { mOptArgV = new char*[opVect.size()]; Debug(2, "Number of Options: %d",opVect.size()); for (size_t i=0; i< opVect.size(); i++) { @@ -166,7 +148,7 @@ int LibvlcCamera::PrimeCapture() } mLibvlcInstance = libvlc_new (opVect.size(), (const char* const*)mOptArgV); - if(mLibvlcInstance == NULL) + if ( mLibvlcInstance == NULL ) Fatal("Unable to create libvlc instance due to: %s", libvlc_errmsg()); mLibvlcMedia = libvlc_media_new_location(mLibvlcInstance, mPath.c_str()); @@ -189,17 +171,15 @@ int LibvlcCamera::PrimeCapture() libvlc_media_player_play(mLibvlcMediaPlayer); - return(0); + return 0; } -int LibvlcCamera::PreCapture() -{ +int LibvlcCamera::PreCapture() { return(0); } // Should not return -1 as cancels capture. Always wait for image if available. -int LibvlcCamera::Capture( Image &image ) -{ +int LibvlcCamera::Capture( Image &image ) { while(!mLibvlcData.newImage.getValueImmediate()) mLibvlcData.newImage.getUpdatedValue(1); @@ -208,25 +188,15 @@ int LibvlcCamera::Capture( Image &image ) mLibvlcData.newImage.setValueImmediate(false); mLibvlcData.mutex.unlock(); - return (0); + return 1; } // Should not return -1 as cancels capture. Always wait for image if available. -int LibvlcCamera::CaptureAndRecord(Image &image, timeval recording, char* event_directory) -{ - while(!mLibvlcData.newImage.getValueImmediate()) - mLibvlcData.newImage.getUpdatedValue(1); - - mLibvlcData.mutex.lock(); - image.Assign(width, height, colours, subpixelorder, mLibvlcData.buffer, width * height * mBpp); - mLibvlcData.newImage.setValueImmediate(false); - mLibvlcData.mutex.unlock(); - +int LibvlcCamera::CaptureAndRecord(Image &image, timeval recording, char* event_directory) { return (0); } -int LibvlcCamera::PostCapture() -{ +int LibvlcCamera::PostCapture() { return(0); } diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index e51c2ca7d..28002d393 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -2878,6 +2878,12 @@ int Monitor::Capture() { captureResult = camera->CaptureAndRecord(*(next_buffer.image), video_store_data->recording, video_store_data->event_file ); + // CaptureAndRecord returns # of frames captured I think + //if ( ( videowriter == H264PASSTHROUGH ) && ( captureResult > 0 ) ) { + if ( captureResult > 0 ) { + //video_store_data->frameNumber = captureResult; + captureResult = 0; + } } else { captureResult = camera->Capture(*(next_buffer.image)); } @@ -2889,33 +2895,28 @@ int Monitor::Capture() { } else { //Check if FFMPEG camera - if ( (videowriter == H264PASSTHROUGH ) && camera->SupportsNativeVideo() ) { + if ( (videowriter == H264PASSTHROUGH) && camera->SupportsNativeVideo() ) { //Warning("ZMC: Recording: %d", video_store_data->recording); - captureResult = camera->CaptureAndRecord(*capture_image, video_store_data->recording, video_store_data->event_file); - }else{ + // Should return -1 on error, like loss of signal. Should return 0 if ok but no video frame. > 0 for received a frame. + captureResult = camera->CaptureAndRecord( + *capture_image, + video_store_data->recording, + video_store_data->event_file + ); + } else { /* Capture directly into image buffer, avoiding the need to memcpy() */ captureResult = camera->Capture(*capture_image); } } - // CaptureAndRecord returns # of frames captured I think - if ( ( videowriter == H264PASSTHROUGH ) && ( captureResult > 0 ) ) { - //video_store_data->frameNumber = captureResult; - captureResult = 0; - } - if ( captureResult != 0 ) { + if ( captureResult < 0 ) { // Unable to capture image for temporary reason // Fake a signal loss image Rgb signalcolor; signalcolor = rgb_convert(signal_check_colour, ZM_SUBPIX_ORDER_BGR); /* HTML colour code is actually BGR in memory, we want RGB */ capture_image->Fill(signalcolor); - captureResult = 0; - } else { - captureResult = 1; - } - - if ( captureResult == 1 ) { + } else if ( captureResult > 0 ) { /* Deinterlacing */ if ( deinterlacing_value == 1 ) { @@ -2978,40 +2979,38 @@ int Monitor::Capture() { shared_data->last_write_time = image_buffer[index].timestamp->tv_sec; image_count++; + } - if ( image_count && fps_report_interval && !(image_count%fps_report_interval) ) { - time_t now = image_buffer[index].timestamp->tv_sec; - fps = double(fps_report_interval)/(now-last_fps_time); - //Info( "%d -> %d -> %d", fps_report_interval, now, last_fps_time ); - //Info( "%d -> %d -> %lf -> %lf", now-last_fps_time, fps_report_interval/(now-last_fps_time), double(fps_report_interval)/(now-last_fps_time), fps ); - Info( "%s: %d - Capturing at %.2lf fps", name, image_count, fps ); - last_fps_time = now; - static char sql[ZM_SQL_SML_BUFSIZ]; - snprintf( sql, sizeof(sql), "UPDATE Monitors SET CaptureFPS = '%.2lf' WHERE Id = '%d'", fps, id ); - if ( mysql_query( &dbconn, sql ) ) { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); - } + if ( image_count && fps_report_interval && !(image_count%fps_report_interval) ) { + time_t now = image_buffer[index].timestamp->tv_sec; + fps = double(fps_report_interval)/(now-last_fps_time); + //Info( "%d -> %d -> %d", fps_report_interval, now, last_fps_time ); + //Info( "%d -> %d -> %lf -> %lf", now-last_fps_time, fps_report_interval/(now-last_fps_time), double(fps_report_interval)/(now-last_fps_time), fps ); + Info( "%s: %d - Capturing at %.2lf fps", name, image_count, fps ); + last_fps_time = now; + static char sql[ZM_SQL_SML_BUFSIZ]; + snprintf( sql, sizeof(sql), "UPDATE Monitors SET CaptureFPS = '%.2lf' WHERE Id = '%d'", fps, id ); + if ( mysql_query( &dbconn, sql ) ) { + Error( "Can't run query: %s", mysql_error( &dbconn ) ); } + } - // Icon: I'm not sure these should be here. They have nothing to do with capturing - if ( shared_data->action & GET_SETTINGS ) { - shared_data->brightness = camera->Brightness(); - shared_data->hue = camera->Hue(); - shared_data->colour = camera->Colour(); - shared_data->contrast = camera->Contrast(); - shared_data->action &= ~GET_SETTINGS; - } - if ( shared_data->action & SET_SETTINGS ) { - camera->Brightness( shared_data->brightness ); - camera->Hue( shared_data->hue ); - camera->Colour( shared_data->colour ); - camera->Contrast( shared_data->contrast ); - shared_data->action &= ~SET_SETTINGS; - } - return( 0 ); - } // end if captureResults == 1 which is success I think - shared_data->signal = false; - return( -1 ); + // Icon: I'm not sure these should be here. They have nothing to do with capturing + if ( shared_data->action & GET_SETTINGS ) { + shared_data->brightness = camera->Brightness(); + shared_data->hue = camera->Hue(); + shared_data->colour = camera->Colour(); + shared_data->contrast = camera->Contrast(); + shared_data->action &= ~GET_SETTINGS; + } + if ( shared_data->action & SET_SETTINGS ) { + camera->Brightness( shared_data->brightness ); + camera->Hue( shared_data->hue ); + camera->Colour( shared_data->colour ); + camera->Contrast( shared_data->contrast ); + shared_data->action &= ~SET_SETTINGS; + } + return captureResult; } void Monitor::TimestampImage( Image *ts_image, const struct timeval *ts_time ) const { diff --git a/src/zm_remote_camera_http.cpp b/src/zm_remote_camera_http.cpp index 95c8ae507..2907e90a3 100644 --- a/src/zm_remote_camera_http.cpp +++ b/src/zm_remote_camera_http.cpp @@ -1063,23 +1063,18 @@ int RemoteCameraHttp::GetResponse() return( 0 ); } -int RemoteCameraHttp::PreCapture() -{ - if ( sd < 0 ) - { +int RemoteCameraHttp::PreCapture() { + if ( sd < 0 ) { Connect(); - if ( sd < 0 ) - { + if ( sd < 0 ) { Error( "Unable to connect to camera" ); return( -1 ); } mode = SINGLE_IMAGE; buffer.clear(); } - if ( mode == SINGLE_IMAGE ) - { - if ( SendRequest() < 0 ) - { + if ( mode == SINGLE_IMAGE ) { + if ( SendRequest() < 0 ) { Error( "Unable to send request" ); Disconnect(); return( -1 ); @@ -1088,50 +1083,43 @@ int RemoteCameraHttp::PreCapture() return( 0 ); } -int RemoteCameraHttp::Capture( Image &image ) -{ +int RemoteCameraHttp::Capture( Image &image ) { int content_length = GetResponse(); - if ( content_length == 0 ) - { + if ( content_length == 0 ) { Warning( "Unable to capture image, retrying" ); - return( 1 ); + return 0; } - if ( content_length < 0 ) - { + if ( content_length < 0 ) { Error( "Unable to get response, disconnecting" ); Disconnect(); - return( -1 ); + return -1; } - switch( format ) - { + switch( format ) { case JPEG : { - if ( !image.DecodeJpeg( buffer.extract( content_length ), content_length, colours, subpixelorder ) ) - { + if ( !image.DecodeJpeg( buffer.extract( content_length ), content_length, colours, subpixelorder ) ) { Error( "Unable to decode jpeg" ); Disconnect(); - return( -1 ); + return -1; } break; } case X_RGB : { - if ( content_length != (long)image.Size() ) - { + if ( content_length != (long)image.Size() ) { Error( "Image length mismatch, expected %d bytes, content length was %d", image.Size(), content_length ); Disconnect(); - return( -1 ); + return -1; } image.Assign( width, height, colours, subpixelorder, buffer, imagesize ); break; } case X_RGBZ : { - if ( !image.Unzip( buffer.extract( content_length ), content_length ) ) - { + if ( !image.Unzip( buffer.extract( content_length ), content_length ) ) { Error( "Unable to unzip RGB image" ); Disconnect(); - return( -1 ); + return -1; } image.Assign( width, height, colours, subpixelorder, buffer, imagesize ); break; @@ -1140,13 +1128,12 @@ int RemoteCameraHttp::Capture( Image &image ) { Error( "Unexpected image format encountered" ); Disconnect(); - return( -1 ); + return -1; } } - return( 0 ); + return 1; } -int RemoteCameraHttp::PostCapture() -{ - return( 0 ); +int RemoteCameraHttp::PostCapture() { + return 0; } diff --git a/src/zm_remote_camera_rtsp.cpp b/src/zm_remote_camera_rtsp.cpp index 9b0b6b41d..b8e5dc573 100644 --- a/src/zm_remote_camera_rtsp.cpp +++ b/src/zm_remote_camera_rtsp.cpp @@ -266,15 +266,15 @@ int RemoteCameraRtsp::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); + return -1; } while ( true ) { buffer.clear(); if ( !rtspThread->isRunning() ) - return (-1); + return -1; if ( rtspThread->getFrame( buffer ) ) { Debug( 3, "Read frame %d bytes", buffer.size() ); @@ -282,21 +282,21 @@ int RemoteCameraRtsp::Capture( Image &image ) { Hexdump( 4, buffer.head(), 16 ); if ( !buffer.size() ) - return( -1 ); + return -1; - if(mCodecContext->codec_id == AV_CODEC_ID_H264) { + if ( mCodecContext->codec_id == AV_CODEC_ID_H264 ) { // SPS and PPS frames should be saved and appended to IDR frames int nalType = (buffer.head()[3] & 0x1f); // SPS The SPS NAL unit contains parameters that apply to a series of consecutive coded video pictures - if(nalType == 7) { + if ( nalType == 7 ) { lastSps = buffer; continue; - } else if(nalType == 8) { + } else if ( nalType == 8 ) { // PPS The PPS NAL unit contains parameters that apply to the decoding of one or more individual pictures inside a coded video sequence lastPps = buffer; continue; - } else if(nalType == 5) { + } else if ( nalType == 5 ) { // IDR buffer += lastSps; buffer += lastPps; @@ -357,13 +357,13 @@ int RemoteCameraRtsp::Capture( Image &image ) { zm_av_packet_unref( &packet ); } /* getFrame() */ - if(frameComplete) - return (0); + if ( frameComplete ) + return 1; } // end while true // can never get here. - return (0); + return 0; } //Function to handle capture and store diff --git a/src/zm_stream.cpp b/src/zm_stream.cpp index 8002c4f18..282db0f40 100644 --- a/src/zm_stream.cpp +++ b/src/zm_stream.cpp @@ -311,7 +311,7 @@ void StreamBase::openComms() { strncpy( rem_addr.sun_path, rem_sock_path, sizeof(rem_addr.sun_path) ); rem_addr.sun_family = AF_UNIX; } // end if connKey > 0 - Debug(3, "comms open" ); + Debug(2, "comms open" ); } void StreamBase::closeComms() { diff --git a/web/skins/classic/views/js/montage.js b/web/skins/classic/views/js/montage.js index 5927c9b39..364e79b91 100644 --- a/web/skins/classic/views/js/montage.js +++ b/web/skins/classic/views/js/montage.js @@ -7,7 +7,7 @@ function Monitor( monitorData ) { this.status = null; this.alarmState = STATE_IDLE; this.lastAlarmState = STATE_IDLE; - this.streamCmdParms = "view=request&request=stream&connkey="+this.connKey; + this.streamCmdParms = 'view=request&request=stream&connkey='+this.connKey; this.onclick = monitorData.onclick; if ( auth_hash ) this.streamCmdParms += '&auth='+auth_hash; @@ -112,8 +112,24 @@ function Monitor( monitorData ) { //this.streamCmdReq.cancel(); this.streamCmdReq.send( this.streamCmdParms+"&command="+CMD_QUERY ); }; + this.onError = function( text, error ) { + console.log('onerror: ' + text + ' error:'+error); + }; + this.onFailure = function( xhr ) { + console.log('onFailure: ' ); + console.log(xhr ); + }; - this.streamCmdReq = new Request.JSON( { url: this.server_url, method: 'get', timeout: 1000+AJAX_TIMEOUT, onSuccess: this.getStreamCmdResponse.bind( this ), onTimeout: this.streamCmdQuery.bind( this, true ), link: 'cancel' } ); + this.streamCmdReq = new Request.JSON( { + url: this.server_url, + method: 'get', + timeout: 1000+AJAX_TIMEOUT, + onSuccess: this.getStreamCmdResponse.bind( this ), + onTimeout: this.streamCmdQuery.bind( this, true ), + onError: this.onError.bind(this), + onFailure: this.onFailure.bind(this), + link: 'cancel' + } ); requestQueue.addRequest( "cmdReq"+this.id, this.streamCmdReq ); } From 0ef5c16bcce76a80fb31b535db0597f375e1ff12 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 3 Nov 2017 15:07:04 -0400 Subject: [PATCH 15/47] when doing parseSort, reset the sortfield to StartTime instead of DateTime --- web/includes/functions.php | 1 + 1 file changed, 1 insertion(+) diff --git a/web/includes/functions.php b/web/includes/functions.php index 724e9e521..4579f21af 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -1058,6 +1058,7 @@ function parseSort( $saveToSession=false, $querySep='&' ) { break; case 'DateTime' : $sortColumn = 'E.StartTime'; + $_REQUEST['sort_field'] = 'StartTime'; break; case 'DiskSpace' : $sortColumn = 'E.DiskSpace'; From 8432ab5938528a52671f01ac21f675bd9bd3f9b6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 3 Nov 2017 15:09:19 -0400 Subject: [PATCH 16/47] change quotes, and limit the # of results to 2 when getting next and previous frames. 2 is because one of them could be the currently selected Event, --- web/ajax/status.php | 316 ++++++++++++++++++++++---------------------- 1 file changed, 158 insertions(+), 158 deletions(-) diff --git a/web/ajax/status.php b/web/ajax/status.php index 82929c20b..6827b7e79 100644 --- a/web/ajax/status.php +++ b/web/ajax/status.php @@ -1,170 +1,170 @@ array( - "permission" => "System", - "table" => "Monitors", - "limit" => 1, - "elements" => array( - "MonitorCount" => array( "sql" => "count(*)" ), - "ActiveMonitorCount" => array( "sql" => "count(if(Function != 'None',1,NULL))" ), - "State" => array( "func" => "daemonCheck()?".translate('Running').":".translate('Stopped') ), - "Load" => array( "func" => "getLoad()" ), - "Disk" => array( "func" => "getDiskPercent()" ), + 'system' => array( + 'permission' => 'System', + 'table' => 'Monitors', + 'limit' => 1, + 'elements' => array( + 'MonitorCount' => array( 'sql' => "count(*)" ), + 'ActiveMonitorCount' => array( 'sql' => "count(if(Function != 'None',1,NULL))" ), + 'State' => array( 'func' => "daemonCheck()?".translate('Running').":".translate('Stopped') ), + 'Load' => array( 'func' => "getLoad()" ), + 'Disk' => array( 'func' => "getDiskPercent()" ), ), ), - "monitor" => array( - "permission" => "Monitors", - "table" => "Monitors", - "limit" => 1, - "selector" => "Monitors.Id", - "elements" => array( - "Id" => array( "sql" => "Monitors.Id" ), - "Name" => array( "sql" => "Monitors.Name" ), - "Type" => true, - "Function" => true, - "Enabled" => true, - "LinkedMonitors" => true, - "Triggers" => true, - "Device" => true, - "Channel" => true, - "Format" => true, - "Host" => true, - "Port" => true, - "Path" => true, - "Width" => array( "sql" => "Monitors.Width" ), - "Height" => array( "sql" => "Monitors.Height" ), - "Palette" => true, - "Orientation" => true, - "Brightness" => true, - "Contrast" => true, - "Hue" => true, - "Colour" => true, - "EventPrefix" => true, - "LabelFormat" => true, - "LabelX" => true, - "LabelY" => true, - "LabelSize" => true, - "ImageBufferCount" => true, - "WarmupCount" => true, - "PreEventCount" => true, - "PostEventCount" => true, - "AlarmFrameCount" => true, - "SectionLength" => true, - "FrameSkip" => true, - "MotionFrameSkip" => true, - "MaxFPS" => true, - "AlarmMaxFPS" => true, - "FPSReportInterval" => true, - "RefBlendPerc" => true, - "Controllable" => true, - "ControlId" => true, - "ControlDevice" => true, - "ControlAddress" => true, - "AutoStopTimeout" => true, - "TrackMotion" => true, - "TrackDelay" => true, - "ReturnLocation" => true, - "ReturnDelay" => true, - "DefaultView" => true, - "DefaultRate" => true, - "DefaultScale" => true, - "WebColour" => true, - "Sequence" => true, - "MinEventId" => array( "sql" => "(SELECT min(Events.Id) FROM Events WHERE Events.MonitorId = Monitors.Id" ), - "MaxEventId" => array( "sql" => "(SELECT max(Events.Id) FROM Events WHERE Events.MonitorId = Monitors.Id" ), - "TotalEvents" => array( "sql" => "(SELECT count(Events.Id) FROM Events WHERE Events.MonitorId = Monitors.Id" ), - "Status" => array( "zmu" => "-m ".escapeshellarg($_REQUEST['id'][0])." -s" ), - "FrameRate" => array( "zmu" => "-m ".escapeshellarg($_REQUEST['id'][0])." -f" ), + 'monitor' => array( + 'permission' => 'Monitors', + 'table' => 'Monitors', + 'limit' => 1, + 'selector' => "Monitors.Id", + 'elements' => array( + 'Id' => array( 'sql' => "Monitors.Id" ), + 'Name' => array( 'sql' => "Monitors.Name" ), + 'Type' => true, + 'Function' => true, + 'Enabled' => true, + 'LinkedMonitors' => true, + 'Triggers' => true, + 'Device' => true, + 'Channel' => true, + 'Format' => true, + 'Host' => true, + 'Port' => true, + 'Path' => true, + 'Width' => array( 'sql' => "Monitors.Width" ), + 'Height' => array( 'sql' => "Monitors.Height" ), + 'Palette' => true, + 'Orientation' => true, + 'Brightness' => true, + 'Contrast' => true, + 'Hue' => true, + 'Colour' => true, + 'EventPrefix' => true, + 'LabelFormat' => true, + 'LabelX' => true, + 'LabelY' => true, + 'LabelSize' => true, + 'ImageBufferCount' => true, + 'WarmupCount' => true, + 'PreEventCount' => true, + 'PostEventCount' => true, + 'AlarmFrameCount' => true, + 'SectionLength' => true, + 'FrameSkip' => true, + 'MotionFrameSkip' => true, + 'MaxFPS' => true, + 'AlarmMaxFPS' => true, + 'FPSReportInterval' => true, + 'RefBlendPerc' => true, + 'Controllable' => true, + 'ControlId' => true, + 'ControlDevice' => true, + 'ControlAddress' => true, + 'AutoStopTimeout' => true, + 'TrackMotion' => true, + 'TrackDelay' => true, + 'ReturnLocation' => true, + 'ReturnDelay' => true, + 'DefaultView' => true, + 'DefaultRate' => true, + 'DefaultScale' => true, + 'WebColour' => true, + 'Sequence' => true, + 'MinEventId' => array( 'sql' => "(SELECT min(Events.Id) FROM Events WHERE Events.MonitorId = Monitors.Id" ), + 'MaxEventId' => array( 'sql' => "(SELECT max(Events.Id) FROM Events WHERE Events.MonitorId = Monitors.Id" ), + 'TotalEvents' => array( 'sql' => "(SELECT count(Events.Id) FROM Events WHERE Events.MonitorId = Monitors.Id" ), + 'Status' => array( 'zmu' => "-m ".escapeshellarg($_REQUEST['id'][0])." -s" ), + 'FrameRate' => array( 'zmu' => "-m ".escapeshellarg($_REQUEST['id'][0])." -f" ), ), ), - "events" => array( - "permission" => "Events", - "table" => "Events", - "selector" => "Events.MonitorId", - "elements" => array( - "Id" => true, - "Name" => true, - "Cause" => true, - "Notes" => true, - "StartTime" => true, - "StartTimeShort" => array( "sql" => "date_format( StartTime, '".MYSQL_FMT_DATETIME_SHORT."' )" ), - "EndTime" => true, - "Width" => true, - "Height" => true, - "Length" => true, - "Frames" => true, - "AlarmFrames" => true, - "TotScore" => true, - "AvgScore" => true, - "MaxScore" => true, + 'events' => array( + 'permission' => 'Events', + 'table' => 'Events', + 'selector' => "Events.MonitorId", + 'elements' => array( + 'Id' => true, + 'Name' => true, + 'Cause' => true, + 'Notes' => true, + 'StartTime' => true, + 'StartTimeShort' => array( 'sql' => "date_format( StartTime, '".MYSQL_FMT_DATETIME_SHORT."' )" ), + 'EndTime' => true, + 'Width' => true, + 'Height' => true, + 'Length' => true, + 'Frames' => true, + 'AlarmFrames' => true, + 'TotScore' => true, + 'AvgScore' => true, + 'MaxScore' => true, ), ), - "event" => array( - "permission" => "Events", - "table" => "Events", - "limit" => 1, - "selector" => "Events.Id", - "elements" => array( - "Id" => array( "sql" => "Events.Id" ), - "MonitorId" => true, - "MonitorName" => array("sql" => "(SELECT Monitors.Name FROM Monitors WHERE Monitors.Id = Events.MonitorId)"), - "Name" => true, - "Cause" => true, - "StartTime" => true, - "StartTimeShort" => array( "sql" => "date_format( StartTime, '".MYSQL_FMT_DATETIME_SHORT."' )" ), - "EndTime" => true, - "Width" => true, - "Height" => true, - "Length" => true, - "Frames" => true, - "DefaultVideo" => true, - "AlarmFrames" => true, - "TotScore" => true, - "AvgScore" => true, - "MaxScore" => true, - "Archived" => true, - "Videoed" => true, - "Uploaded" => true, - "Emailed" => true, - "Messaged" => true, - "Executed" => true, - "Notes" => true, - "MinFrameId" => array( "sql" => "(SELECT min(Frames.FrameId) FROM Frames WHERE EventId=Events.Id)" ), - "MaxFrameId" => array( "sql" => "(SELECT max(Frames.FrameId) FROM Frames WHERE Events.Id = Frames.EventId)" ), - "MinFrameDelta" => array( "sql" => "(SELECT min(Frames.Delta) FROM Frames WHERE Events.Id = Frames.EventId)" ), - "MaxFrameDelta" => array( "sql" => "(SELECT max(Frames.Delta) FROM Frames WHERE Events.Id = Frames.EventId)" ), - //"Path" => array( "postFunc" => "getEventPath" ), + 'event' => array( + 'permission' => 'Events', + 'table' => 'Events', + 'limit' => 1, + 'selector' => "Events.Id", + 'elements' => array( + 'Id' => array( 'sql' => "Events.Id" ), + 'MonitorId' => true, + 'MonitorName' => array('sql' => "(SELECT Monitors.Name FROM Monitors WHERE Monitors.Id = Events.MonitorId)"), + 'Name' => true, + 'Cause' => true, + 'StartTime' => true, + 'StartTimeShort' => array( 'sql' => "date_format( StartTime, '".MYSQL_FMT_DATETIME_SHORT."' )" ), + 'EndTime' => true, + 'Width' => true, + 'Height' => true, + 'Length' => true, + 'Frames' => true, + 'DefaultVideo' => true, + 'AlarmFrames' => true, + 'TotScore' => true, + 'AvgScore' => true, + 'MaxScore' => true, + 'Archived' => true, + 'Videoed' => true, + 'Uploaded' => true, + 'Emailed' => true, + 'Messaged' => true, + 'Executed' => true, + 'Notes' => true, + 'MinFrameId' => array( 'sql' => "(SELECT min(Frames.FrameId) FROM Frames WHERE EventId=Events.Id)" ), + 'MaxFrameId' => array( 'sql' => "(SELECT max(Frames.FrameId) FROM Frames WHERE Events.Id = Frames.EventId)" ), + 'MinFrameDelta' => array( 'sql' => "(SELECT min(Frames.Delta) FROM Frames WHERE Events.Id = Frames.EventId)" ), + 'MaxFrameDelta' => array( 'sql' => "(SELECT max(Frames.Delta) FROM Frames WHERE Events.Id = Frames.EventId)" ), + //'Path' => array( 'postFunc' => 'getEventPath' ), ), ), - "frame" => array( - "permission" => "Events", - "table" => "Frames", - "limit" => 1, - "selector" => array( array( "table" => "Events", "join" => "Events.Id = Frames.EventId", "selector"=>"Events.Id" ), "Frames.FrameId" ), - "elements" => array( - //"Id" => array( "sql" => "Frames.FrameId" ), - "FrameId" => true, - "EventId" => true, - "Type" => true, - "TimeStamp" => true, - "TimeStampShort" => array( "sql" => "date_format( StartTime, '".MYSQL_FMT_DATETIME_SHORT."' )" ), - "Delta" => true, - "Score" => true, - //"Image" => array( "postFunc" => "getFrameImage" ), + 'frame' => array( + 'permission' => 'Events', + 'table' => 'Frames', + 'limit' => 1, + 'selector' => array( array( 'table' => 'Events', 'join' => "Events.Id = Frames.EventId", 'selector'=>"Events.Id" ), "Frames.FrameId" ), + 'elements' => array( + //'Id' => array( 'sql' => "Frames.FrameId" ), + 'FrameId' => true, + 'EventId' => true, + 'Type' => true, + 'TimeStamp' => true, + 'TimeStampShort' => array( 'sql' => "date_format( StartTime, '".MYSQL_FMT_DATETIME_SHORT."' )" ), + 'Delta' => true, + 'Score' => true, + //'Image' => array( 'postFunc' => 'getFrameImage' ), ), ), - "frameimage" => array( - "permission" => "Events", - "func" => "getFrameImage()" + 'frameimage' => array( + 'permission' => 'Events', + 'func' => "getFrameImage()" ), - "nearframe" => array( - "permission" => "Events", - "func" => "getNearFrame()" + 'nearframe' => array( + 'permission' => 'Events', + 'func' => "getNearFrame()" ), - "nearevents" => array( - "permission" => "Events", - "func" => "getNearEvents()" + 'nearevents' => array( + 'permission' => 'Events', + 'func' => "getNearEvents()" ) ); @@ -290,7 +290,7 @@ function collectData() { $data = collectData(); if ( !isset($_REQUEST['layout']) ) { - $_REQUEST['layout'] = "json"; + $_REQUEST['layout'] = 'json'; } switch( $_REQUEST['layout'] ) { @@ -331,7 +331,7 @@ function getFrameImage() { $frame = array(); $frame['EventId'] = $eventId; $frame['FrameId'] = $frameId; - $frame['Type'] = "Virtual"; + $frame['Type'] = 'Virtual'; } $event = dbFetchOne( 'select * from Events where Id = ?', NULL, array( $frame['EventId'] ) ); $frame['Image'] = getImageSrc( $event, $frame, SCALE_BASE ); @@ -349,7 +349,7 @@ function getNearFrame() { return( array() ); } } - $_REQUEST['entity'] = "frame"; + $_REQUEST['entity'] = 'frame'; $_REQUEST['id'][1] = $nearFrameId; return( collectData() ); } @@ -358,7 +358,7 @@ function getNearEvents() { global $user, $sortColumn, $sortOrder; $eventId = $_REQUEST['id']; - $event = dbFetchOne( 'select * from Events where Id = ?', NULL, array( $eventId ) ); + $event = dbFetchOne( 'SELECT * FROM Events WHERE Id=?', NULL, array( $eventId ) ); parseFilter( $_REQUEST['filter'] ); parseSort(); @@ -368,7 +368,7 @@ function getNearEvents() { else $midSql = ''; - $sql = "select E.Id as Id, E.StartTime as StartTime from Events as E inner join Monitors as M on E.MonitorId = M.Id where $sortColumn ".($sortOrder=='asc'?'<=':'>=')." '".$event[$_REQUEST['sort_field']]."'".$_REQUEST['filter']['sql'].$midSql." order by $sortColumn ".($sortOrder=='asc'?'desc':'asc'); + $sql = "SELECT E.Id AS Id, E.StartTime AS StartTime FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id WHERE $sortColumn ".($sortOrder=='asc'?'<=':'>=')." '".$event[$_REQUEST['sort_field']]."'".$_REQUEST['filter']['sql'].$midSql." ORDER BY $sortColumn ".($sortOrder=='asc'?'desc':'asc') . ' LIMIT 2'; $result = dbQuery( $sql ); while ( $id = dbFetchNext( $result, 'Id' ) ) { if ( $id == $eventId ) { @@ -377,7 +377,7 @@ function getNearEvents() { } } - $sql = "select E.Id as Id, E.StartTime as StartTime from Events as E inner join Monitors as M on E.MonitorId = M.Id where $sortColumn ".($sortOrder=='asc'?'>=':'<=')." '".$event[$_REQUEST['sort_field']]."'".$_REQUEST['filter']['sql'].$midSql." order by $sortColumn $sortOrder"; + $sql = "SELECT E.Id AS Id, E.StartTime AS StartTime FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id WHERE $sortColumn ".($sortOrder=='asc'?'>=':'<=')." '".$event[$_REQUEST['sort_field']]."'".$_REQUEST['filter']['sql'].$midSql." ORDER BY $sortColumn $sortOrder LIMIT 2"; $result = dbQuery( $sql ); while ( $id = dbFetchNext( $result, 'Id' ) ) { if ( $id == $eventId ) { From f39353a4a323d6a54e64c825c66788de81099b04 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 3 Nov 2017 15:44:53 -0400 Subject: [PATCH 17/47] add missing breaks --- web/includes/functions.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web/includes/functions.php b/web/includes/functions.php index 4579f21af..8dcab3b42 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -1277,8 +1277,10 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&' ) { break; case 'IS' : $filter['sql'] .= " IS $value"; + break; case 'IS NOT' : $filter['sql'] .= " IS NOT $value"; + break; } $filter['query'] .= $querySep.urlencode("filter[Query][terms][$i][op]").'='.urlencode($terms[$i]['op']); From 63c788ef0e5af5fcb12ebfcdf0f3df511bb57751 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 3 Nov 2017 15:45:11 -0400 Subject: [PATCH 18/47] handle when sql error occurs and no params given --- web/includes/database.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/includes/database.php b/web/includes/database.php index bbfd588b0..34387e040 100644 --- a/web/includes/database.php +++ b/web/includes/database.php @@ -141,7 +141,7 @@ if ( 0 ) { Warning("SQL: $sql: rows:" . $result->rowCount() ); } } catch(PDOException $e) { - Error( "SQL-ERR '".$e->getMessage()."', statement was '".$sql."' params:" . implode(',',$params) ); + Error( "SQL-ERR '".$e->getMessage()."', statement was '".$sql."' params:" . $params?implode(',',$params):'' ); } return( $result ); } From 09f3355e183c5a49436721561922bc585a0cc85e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 4 Nov 2017 14:52:36 -0400 Subject: [PATCH 19/47] add /usr/share/zoneminder/www/cache as a temp dir --- distros/ubuntu1604/zoneminder.dirs | 1 + distros/ubuntu1604/zoneminder.tmpfile | 1 + web/skins/classic/views/console.php | 3 +-- web/skins/classic/views/group.php | 6 ++++-- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/distros/ubuntu1604/zoneminder.dirs b/distros/ubuntu1604/zoneminder.dirs index 56dd56e6b..08840aef4 100644 --- a/distros/ubuntu1604/zoneminder.dirs +++ b/distros/ubuntu1604/zoneminder.dirs @@ -4,5 +4,6 @@ var/cache/zoneminder/events var/cache/zoneminder/images var/cache/zoneminder/temp usr/share/zoneminder/db +usr/share/zoneminder/www/cache etc/zm/ etc/zm/conf.d diff --git a/distros/ubuntu1604/zoneminder.tmpfile b/distros/ubuntu1604/zoneminder.tmpfile index ef68288ba..f23ca55b3 100644 --- a/distros/ubuntu1604/zoneminder.tmpfile +++ b/distros/ubuntu1604/zoneminder.tmpfile @@ -1,3 +1,4 @@ d /var/run/zm 0755 www-data www-data d /tmp/zm 0755 www-data www-data d /var/tmp/zm 0755 www-data www-data +d /usr/share/zoneminder/www/cache 0755 www-data www-data diff --git a/web/skins/classic/views/console.php b/web/skins/classic/views/console.php index fb5785c92..43214ea1f 100644 --- a/web/skins/classic/views/console.php +++ b/web/skins/classic/views/console.php @@ -263,8 +263,7 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { - - + diff --git a/web/skins/classic/views/group.php b/web/skins/classic/views/group.php index 9f00555dd..0e71040c7 100644 --- a/web/skins/classic/views/group.php +++ b/web/skins/classic/views/group.php @@ -87,9 +87,11 @@ function get_children($Group) { } $kids = get_children($newGroup); -$kids[] = $newGroup->Id(); +if ( $newGroup->Id() ) + $kids[] = $newGroup->Id(); +$sql = 'SELECT Id,Name from Groups'.(count($kids)?' WHERE Id NOT IN ('.implode(',',array_map(function(){return '?';}, $kids )).')' : '').' ORDER BY Name'; $options = array(''=>'None'); -foreach ( dbFetchAll( 'SELECT Id,Name from Groups WHERE Id NOT IN ('.implode(',',array_map(function(){return '?';}, $kids )).') ORDER BY Name', null, $kids ) as $option ) { +foreach ( dbFetchAll( $sql, null, $kids ) as $option ) { $options[$option['Id']] = $option['Name']; } echo htmlSelect( 'newGroup[ParentId]', $options, $newGroup->ParentId(), array('onchange'=>'configureButtons(this);' )); From ee96f58ac4762e5974c99698cfbd1296523807dd Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 5 Nov 2017 09:59:06 -0500 Subject: [PATCH 20/47] fix fps reporting value when Capture doesn't return a new frame --- src/zm_monitor.cpp | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 28002d393..7e0d4b630 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1178,7 +1178,7 @@ bool Monitor::Analyse() { gettimeofday( &now, NULL ); if ( image_count && fps_report_interval && !(image_count%fps_report_interval) ) { - fps = double(fps_report_interval)/(now.tv_sec-last_fps_time); + fps = double(fps_report_interval)/(now.tv_sec - last_fps_time); Info( "%s: %d - Analysing at %.2f fps", name, image_count, fps ); static char sql[ZM_SQL_SML_BUFSIZ]; snprintf( sql, sizeof(sql), "UPDATE Monitors SET AnalysisFPS = '%.2lf' WHERE Id = '%d'", fps, id ); @@ -2878,12 +2878,6 @@ int Monitor::Capture() { captureResult = camera->CaptureAndRecord(*(next_buffer.image), video_store_data->recording, video_store_data->event_file ); - // CaptureAndRecord returns # of frames captured I think - //if ( ( videowriter == H264PASSTHROUGH ) && ( captureResult > 0 ) ) { - if ( captureResult > 0 ) { - //video_store_data->frameNumber = captureResult; - captureResult = 0; - } } else { captureResult = camera->Capture(*(next_buffer.image)); } @@ -2908,8 +2902,7 @@ int Monitor::Capture() { captureResult = camera->Capture(*capture_image); } } - - +Debug(4, "Return from Capture (%d)", captureResult); if ( captureResult < 0 ) { // Unable to capture image for temporary reason // Fake a signal loss image @@ -2970,26 +2963,34 @@ int Monitor::Capture() { if ( privacy_bitmask ) capture_image->MaskPrivacy( privacy_bitmask ); + // Might be able to remove this call, when we start passing around ZMPackets, which will already have a timestamp gettimeofday( image_buffer[index].timestamp, NULL ); if ( config.timestamp_on_capture ) { TimestampImage( capture_image, image_buffer[index].timestamp ); } + // Maybe we don't need to do this on all camera types shared_data->signal = CheckSignal(capture_image); shared_data->last_write_index = index; shared_data->last_write_time = image_buffer[index].timestamp->tv_sec; image_count++; - } + } // end if captureResult if ( image_count && fps_report_interval && !(image_count%fps_report_interval) ) { - time_t now = image_buffer[index].timestamp->tv_sec; - fps = double(fps_report_interval)/(now-last_fps_time); - //Info( "%d -> %d -> %d", fps_report_interval, now, last_fps_time ); + + struct timeval now; + if ( !captureResult ) { + gettimeofday( &now, NULL ); + } else { + now.tv_sec = image_buffer[index].timestamp->tv_sec; + } + fps = double(fps_report_interval)/(now.tv_sec-last_fps_time); + Info( "%d -> %d -> %d", fps_report_interval, now, last_fps_time ); //Info( "%d -> %d -> %lf -> %lf", now-last_fps_time, fps_report_interval/(now-last_fps_time), double(fps_report_interval)/(now-last_fps_time), fps ); Info( "%s: %d - Capturing at %.2lf fps", name, image_count, fps ); - last_fps_time = now; + last_fps_time = now.tv_sec; static char sql[ZM_SQL_SML_BUFSIZ]; - snprintf( sql, sizeof(sql), "UPDATE Monitors SET CaptureFPS = '%.2lf' WHERE Id = '%d'", fps, id ); + snprintf( sql, sizeof(sql), "UPDATE Monitors SET CaptureFPS='%.2lf' WHERE Id=%d", fps, id ); if ( mysql_query( &dbconn, sql ) ) { Error( "Can't run query: %s", mysql_error( &dbconn ) ); } From 0a3327e2d2efcda3b19f9557e9c4e59717a9b288 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 5 Nov 2017 09:59:27 -0500 Subject: [PATCH 21/47] move test for h264 into the code that opens the stream instead of comparing on every capture --- src/zm_ffmpeg_camera.cpp | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 889f2eb6f..ee5437633 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -495,7 +495,16 @@ int FfmpegCamera::OpenFfmpeg() { } } } - + } else { +#ifdef AV_CODEC_ID_H265 + if ( mVideoCodecContext->codec_id == AV_CODEC_ID_H265 ) { + Debug( 1, "Input stream appears to be h265. The stored event file may not be viewable in browser." ); + } else { +#endif + Error( "Input stream is not h264. The stored event file may not be viewable in browser." ); +#ifdef AV_CODEC_ID_H265 + } +#endif } // end if h264 #endif @@ -735,22 +744,12 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event mReopenThread = 0; } - if ( mVideoCodecContext->codec_id != AV_CODEC_ID_H264 ) { -#ifdef AV_CODEC_ID_H265 - if ( mVideoCodecContext->codec_id == AV_CODEC_ID_H265 ) { - Debug( 1, "Input stream appears to be h265. The stored event file may not be viewable in browser." ); - } else { -#endif - Error( "Input stream is not h264. The stored event file may not be viewable in browser." ); -#ifdef AV_CODEC_ID_H265 - } -#endif - } int frameComplete = false; while ( ! frameComplete ) { av_init_packet( &packet ); + Debug(4,"before read frame"); ret = av_read_frame( mFormatContext, &packet ); if ( ret < 0 ) { av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE ); @@ -960,7 +959,7 @@ else if ( packet.pts && video_last_pts > packet.pts ) { 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 ); + Warning( "Unable to receive frame %d: %s, continuing", frameCount, errbuf ); zm_av_packet_unref( &packet ); continue; } From 7374ced0762088986561dd3a818787380e63e17e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 5 Nov 2017 10:00:24 -0500 Subject: [PATCH 22/47] 0 is a prefectly valid PreEventCount --- web/skins/classic/views/js/monitor.js.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/monitor.js.php b/web/skins/classic/views/js/monitor.js.php index 97a60dd8c..470bb92b8 100644 --- a/web/skins/classic/views/js/monitor.js.php +++ b/web/skins/classic/views/js/monitor.js.php @@ -97,7 +97,7 @@ function validateForm( form ) { errors[errors.length] = ""; if ( !form.elements['newMonitor[WarmupCount]'].value || !(parseInt(form.elements['newMonitor[WarmupCount]'].value) >= 0 ) ) errors[errors.length] = ""; - if ( !form.elements['newMonitor[PreEventCount]'].value || !(parseInt(form.elements['newMonitor[PreEventCount]'].value) > 0 ) || (parseInt(form.elements['newMonitor[PreEventCount]'].value) > parseInt(form.elements['newMonitor[ImageBufferCount]'].value)) ) + if ( !form.elements['newMonitor[PreEventCount]'].value || !(parseInt(form.elements['newMonitor[PreEventCount]'].value) >= 0 ) || (parseInt(form.elements['newMonitor[PreEventCount]'].value) > parseInt(form.elements['newMonitor[ImageBufferCount]'].value)) ) errors[errors.length] = ""; if ( !form.elements['newMonitor[PostEventCount]'].value || !(parseInt(form.elements['newMonitor[PostEventCount]'].value) >= 0 ) ) errors[errors.length] = ""; From bef7c0ed947d52a9988069e449a74c0c7a49e308 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 5 Nov 2017 11:54:00 -0500 Subject: [PATCH 23/47] Only start a monitor if it has a Function --- web/includes/Monitor.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/web/includes/Monitor.php b/web/includes/Monitor.php index 5c4643657..e7b114dde 100644 --- a/web/includes/Monitor.php +++ b/web/includes/Monitor.php @@ -301,6 +301,7 @@ private $control_fields = array( $values[] = $this->{'Id'}; dbQuery( $sql, $values ); } // end function save + function zmcControl( $mode=false ) { if ( (!defined('ZM_SERVER_ID')) or ( ZM_SERVER_ID==$this->{'ServerId'} ) ) { if ( $this->{'Type'} == 'Local' ) { @@ -315,7 +316,8 @@ private $control_fields = array( if ( $mode == 'restart' ) { daemonControl( 'stop', 'zmc', $zmcArgs ); } - daemonControl( 'start', 'zmc', $zmcArgs ); + if ( $this->{'Function'} != 'None' ) + daemonControl( 'start', 'zmc', $zmcArgs ); } } else { $Server = $this->Server(); From 4b8a8e7b566c454818cc2a1e28de3468fd7a4fa7 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 5 Nov 2017 18:02:09 -0500 Subject: [PATCH 24/47] fix new return value from Capture, 1 signals 1 frame captured --- src/zm_local_camera.cpp | 78 +++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 50 deletions(-) diff --git a/src/zm_local_camera.cpp b/src/zm_local_camera.cpp index 52fb2c8f8..e6bc1a405 100644 --- a/src/zm_local_camera.cpp +++ b/src/zm_local_camera.cpp @@ -1995,17 +1995,14 @@ int LocalCamera::Contrast( int p_contrast ) return( -1 ); } -int LocalCamera::PrimeCapture() -{ +int LocalCamera::PrimeCapture() { Initialise(); Debug( 2, "Priming capture" ); #if ZM_HAS_V4L2 - if ( v4l_version == 2 ) - { + if ( v4l_version == 2 ) { Debug( 3, "Queueing buffers" ); - for ( unsigned int frame = 0; frame < v4l2_data.reqbufs.count; frame++ ) - { + for ( unsigned int frame = 0; frame < v4l2_data.reqbufs.count; frame++ ) { struct v4l2_buffer vid_buf; memset( &vid_buf, 0, sizeof(vid_buf) ); @@ -2028,13 +2025,10 @@ int LocalCamera::PrimeCapture() } #endif // ZM_HAS_V4L2 #if ZM_HAS_V4L1 - if ( v4l_version == 1 ) - { - for ( int frame = 0; frame < v4l1_data.frames.frames; frame++ ) - { + if ( v4l_version == 1 ) { + for ( int frame = 0; frame < v4l1_data.frames.frames; frame++ ) { Debug( 3, "Queueing frame %d", frame ); - if ( ioctl( vid_fd, VIDIOCMCAPTURE, &v4l1_data.buffers[frame] ) < 0 ) - { + if ( ioctl( vid_fd, VIDIOCMCAPTURE, &v4l1_data.buffers[frame] ) < 0 ) { Error( "Capture failure for frame %d: %s", frame, strerror(errno) ); return( -1 ); } @@ -2045,14 +2039,12 @@ int LocalCamera::PrimeCapture() return( 0 ); } -int LocalCamera::PreCapture() -{ - Debug( 2, "Pre-capturing" ); +int LocalCamera::PreCapture() { + Debug( 5, "Pre-capturing" ); return( 0 ); } -int LocalCamera::Capture( Image &image ) -{ +int LocalCamera::Capture( Image &image ) { Debug( 3, "Capturing" ); static uint8_t* buffer = NULL; static uint8_t* directbuffer = NULL; @@ -2069,11 +2061,9 @@ int LocalCamera::Capture( Image &image ) // Do the capture, unless we are the second or subsequent camera on a channel, in which case just reuse the buffer - if ( channel_prime ) - { + if ( channel_prime ) { #if ZM_HAS_V4L2 - if ( v4l_version == 2 ) - { + if ( v4l_version == 2 ) { static struct v4l2_buffer vid_buf; memset( &vid_buf, 0, sizeof(vid_buf) ); @@ -2083,10 +2073,8 @@ int LocalCamera::Capture( Image &image ) vid_buf.memory = v4l2_data.reqbufs.memory; Debug( 3, "Capturing %d frames", captures_per_frame ); - while ( captures_per_frame ) - { - if ( vidioctl( vid_fd, VIDIOC_DQBUF, &vid_buf ) < 0 ) - { + while ( captures_per_frame ) { + if ( vidioctl( vid_fd, VIDIOC_DQBUF, &vid_buf ) < 0 ) { if ( errno == EIO ) Warning( "Capture failure, possible signal loss?: %s", strerror(errno) ) else @@ -2096,15 +2084,13 @@ int LocalCamera::Capture( Image &image ) v4l2_data.bufptr = &vid_buf; capture_frame = v4l2_data.bufptr->index; - if ( --captures_per_frame ) - { - if ( vidioctl( vid_fd, VIDIOC_QBUF, &vid_buf ) < 0 ) - { + if ( --captures_per_frame ) { + if ( vidioctl( vid_fd, VIDIOC_QBUF, &vid_buf ) < 0 ) { Error( "Unable to requeue buffer %d: %s", vid_buf.index, strerror(errno) ); return( -1 ); } } - } + } // while captures_per_frame Debug( 3, "Captured frame %d/%d from channel %d", capture_frame, v4l2_data.bufptr->sequence, channel ); @@ -2115,23 +2101,19 @@ int LocalCamera::Capture( Image &image ) Fatal("Captured image dimensions differ: V4L2: %dx%d monitor: %dx%d",v4l2_data.fmt.fmt.pix.width,v4l2_data.fmt.fmt.pix.height,width,height); } - } + } // end if v4l2 #endif // ZM_HAS_V4L2 #if ZM_HAS_V4L1 - if ( v4l_version == 1 ) - { + if ( v4l_version == 1 ) { Debug( 3, "Capturing %d frames", captures_per_frame ); - while ( captures_per_frame ) - { + while ( captures_per_frame ) { Debug( 3, "Syncing frame %d", v4l1_data.active_frame ); - if ( ioctl( vid_fd, VIDIOCSYNC, &v4l1_data.active_frame ) < 0 ) - { + if ( ioctl( vid_fd, VIDIOCSYNC, &v4l1_data.active_frame ) < 0 ) { Error( "Sync failure for frame %d buffer %d: %s", v4l1_data.active_frame, captures_per_frame, strerror(errno) ); return( -1 ); } captures_per_frame--; - if ( captures_per_frame ) - { + if ( captures_per_frame ) { Debug( 3, "Capturing frame %d", v4l1_data.active_frame ); if ( ioctl( vid_fd, VIDIOCMCAPTURE, &v4l1_data.buffers[v4l1_data.active_frame] ) < 0 ) { @@ -2148,18 +2130,18 @@ int LocalCamera::Capture( Image &image ) #endif // ZM_HAS_V4L1 } /* prime capture */ - if(conversion_type != 0) { + if ( conversion_type != 0 ) { Debug( 3, "Performing format conversion" ); /* Request a writeable buffer of the target image */ directbuffer = image.WriteBuffer(width, height, colours, subpixelorder); - if(directbuffer == NULL) { + if ( directbuffer == NULL ) { Error("Failed requesting writeable buffer for the captured image."); - return (-1); + return -1; } #if HAVE_LIBSWSCALE - if(conversion_type == 1) { + if ( conversion_type == 1 ) { Debug( 9, "Calling sws_scale to perform the conversion" ); /* Use swscale to convert the image directly into the shared memory */ @@ -2174,14 +2156,11 @@ int LocalCamera::Capture( Image &image ) sws_scale( imgConversionContext, capturePictures[capture_frame]->data, capturePictures[capture_frame]->linesize, 0, height, tmpPicture->data, tmpPicture->linesize ); } #endif - if(conversion_type == 2) { - + if ( conversion_type == 2 ) { Debug( 9, "Calling the conversion function" ); /* Call the image conversion function and convert directly into the shared memory */ (*conversion_fptr)(buffer, directbuffer, pixels); - } - else if(conversion_type == 3) { - + } else if ( conversion_type == 3 ) { Debug( 9, "Decoding the JPEG image" ); /* JPEG decoding */ image.DecodeJpeg(buffer, buffer_bytesused, colours, subpixelorder); @@ -2192,10 +2171,9 @@ int LocalCamera::Capture( Image &image ) /* No conversion was performed, the image is in the V4L buffers and needs to be copied into the shared memory */ image.Assign( width, height, colours, subpixelorder, buffer, imagesize); - } - return( 0 ); + return 1; } int LocalCamera::PostCapture() From c2fab6e959daa33ccb421772e67e2d392eb43b8f Mon Sep 17 00:00:00 2001 From: APHW2 MFGENG Date: Mon, 6 Nov 2017 07:31:08 -0800 Subject: [PATCH 25/47] add the options for nvsocket as an include --- .../classic/views/_monitor_source_nvsocket.html | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 web/skins/classic/views/_monitor_source_nvsocket.html diff --git a/web/skins/classic/views/_monitor_source_nvsocket.html b/web/skins/classic/views/_monitor_source_nvsocket.html new file mode 100644 index 000000000..2a1567dfe --- /dev/null +++ b/web/skins/classic/views/_monitor_source_nvsocket.html @@ -0,0 +1,14 @@ + + + + + + + + + () + () + +Orientation() );?> + + From 2ffa79172ad3e65b70f17a596783caddbc3fc279 Mon Sep 17 00:00:00 2001 From: APHW2 MFGENG Date: Mon, 6 Nov 2017 08:36:53 -0800 Subject: [PATCH 26/47] Only load Name,Value when loading config because that's all we use --- scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in b/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in index d2b444ef4..f69e95b18 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in +++ b/scripts/ZoneMinder/lib/ZoneMinder/Config.pm.in @@ -115,7 +115,7 @@ BEGIN { , $Config{ZM_DB_USER} , $Config{ZM_DB_PASS} ) or croak( "Can't connect to db" ); - my $sql = 'select * from Config'; + my $sql = 'SELECT Name,Value FROM Config'; my $sth = $dbh->prepare_cached( $sql ) or croak( "Can't prepare '$sql': ".$dbh->errstr() ); my $res = $sth->execute() or croak( "Can't execute: ".$sth->errstr() ); while( my $config = $sth->fetchrow_hashref() ) { From c3cfd096c7e8635b8cb81962ed26d4b35202df35 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 7 Nov 2017 09:34:47 -0500 Subject: [PATCH 27/47] Don't connect to the monitor when doing an eventStream --- src/zm_eventstream.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/zm_eventstream.h b/src/zm_eventstream.h index 07e161214..152935d65 100644 --- a/src/zm_eventstream.h +++ b/src/zm_eventstream.h @@ -27,6 +27,7 @@ #include "zm_stream.h" #include "zm_video.h" #include "zm_ffmpeg_input.h" +#include "zm_monitor.h" #ifdef __cplusplus extern "C" { @@ -108,11 +109,17 @@ class EventStream : public StreamBase { } void setStreamStart( int init_event_id, unsigned int init_frame_id=0 ) { loadInitialEventData( init_event_id, init_frame_id ); - loadMonitor( event_data->monitor_id ); + if ( !(monitor = Monitor::Load( event_data->monitor_id, false, Monitor::QUERY )) ) { + Fatal( "Unable to load monitor id %d for streaming", event_data->monitor_id ); + return; + } } void setStreamStart( int monitor_id, time_t event_time ) { loadInitialEventData( monitor_id, event_time ); - loadMonitor( monitor_id ); + if ( !(monitor = Monitor::Load( event_data->monitor_id, false, Monitor::QUERY )) ) { + Fatal( "Unable to load monitor id %d for streaming", monitor_id ); + return; + } } void setStreamMode( StreamMode p_mode ) { mode = p_mode; From a9419064ef1824a59e6bb2227f87a1e1cf9dd16a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 7 Nov 2017 09:35:13 -0500 Subject: [PATCH 28/47] don't calc fps if no time has passed --- src/zm_monitor.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 7e0d4b630..b01b72208 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -2984,15 +2984,18 @@ Debug(4, "Return from Capture (%d)", captureResult); } else { now.tv_sec = image_buffer[index].timestamp->tv_sec; } - fps = double(fps_report_interval)/(now.tv_sec-last_fps_time); - Info( "%d -> %d -> %d", fps_report_interval, now, last_fps_time ); - //Info( "%d -> %d -> %lf -> %lf", now-last_fps_time, fps_report_interval/(now-last_fps_time), double(fps_report_interval)/(now-last_fps_time), fps ); - Info( "%s: %d - Capturing at %.2lf fps", name, image_count, fps ); - last_fps_time = now.tv_sec; - static char sql[ZM_SQL_SML_BUFSIZ]; - snprintf( sql, sizeof(sql), "UPDATE Monitors SET CaptureFPS='%.2lf' WHERE Id=%d", fps, id ); - if ( mysql_query( &dbconn, sql ) ) { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); + // If we are too fast, we get div by zero. This seems to happen in the case of audio packets. + if ( now.tv_sec != last_fps_time ) { + fps = double(fps_report_interval)/(now.tv_sec-last_fps_time); + Info( "%d -> %d -> %d", fps_report_interval, now.tv_sec, last_fps_time ); + //Info( "%d -> %d -> %lf -> %lf", now-last_fps_time, fps_report_interval/(now-last_fps_time), double(fps_report_interval)/(now-last_fps_time), fps ); + Info( "%s: %d - Capturing at %.2lf fps", name, image_count, fps ); + last_fps_time = now.tv_sec; + static char sql[ZM_SQL_SML_BUFSIZ]; + snprintf( sql, sizeof(sql), "UPDATE Monitors SET CaptureFPS='%.2lf' WHERE Id=%d", fps, id ); + if ( mysql_query( &dbconn, sql ) ) { + Error( "Can't run query: %s", mysql_error( &dbconn ) ); + } } } From b6548ba137f7de66a54b9776f5e6278911b8df40 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 7 Nov 2017 15:54:13 -0500 Subject: [PATCH 29/47] put curl back, we use it's decoding function for urls --- distros/ubuntu1604/rules | 1 - 1 file changed, 1 deletion(-) diff --git a/distros/ubuntu1604/rules b/distros/ubuntu1604/rules index 5cf153266..10489432b 100755 --- a/distros/ubuntu1604/rules +++ b/distros/ubuntu1604/rules @@ -28,7 +28,6 @@ override_dh_auto_configure: -DZM_DIR_EVENTS="/var/cache/zoneminder/events" \ -DZM_DIR_IMAGES="/var/cache/zoneminder/images" \ -DZM_PATH_ZMS="/zm/cgi-bin/nph-zms" \ - -DZM_NO_CURL=1 \ -DZM_NO_LIBVLC=1 override_dh_clean: From e17bcb9178d079182eb73436fda390c453241a40 Mon Sep 17 00:00:00 2001 From: APHW2 MFGENG Date: Tue, 7 Nov 2017 18:21:51 -0800 Subject: [PATCH 30/47] updates for mast ffmpeg --- src/zm_ffmpeg.cpp | 2 + src/zm_ffmpeg_camera.cpp | 2 + src/zm_mpeg.cpp | 133 +++++++++++++------- src/zm_mpeg.h | 1 + src/zm_remote_camera.cpp | 1 + src/zm_remote_camera.h | 3 +- src/zm_remote_camera_nvsocket.cpp | 200 ++++++++---------------------- src/zm_remote_camera_nvsocket.h | 2 +- src/zm_sdp.cpp | 92 ++++++++------ src/zm_sdp.h | 18 +-- src/zm_videostore.cpp | 10 +- 11 files changed, 216 insertions(+), 248 deletions(-) diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index 4ba88d900..c9fe65e91 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -133,6 +133,7 @@ int av_dict_parse_string(AVDictionary **pm, const char *str, #endif // HAVE_LIBAVCODEC || HAVE_LIBAVUTIL || HAVE_LIBSWSCALE #if HAVE_LIBAVUTIL +#if LIBAVUTIL_VERSION_CHECK(56, 0, 0, 17, 100) int64_t av_rescale_delta(AVRational in_tb, int64_t in_ts, AVRational fs_tb, int duration, int64_t *last, AVRational out_tb){ int64_t a, b, this_thing; @@ -156,6 +157,7 @@ simple_round: return av_rescale_q(this_thing, fs_tb, out_tb); } #endif +#endif int hacked_up_context2_for_older_ffmpeg(AVFormatContext **avctx, AVOutputFormat *oformat, const char *format, const char *filename) { AVFormatContext *s = avformat_alloc_context(); diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index ee5437633..e6c3432fe 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -458,7 +458,9 @@ int FfmpegCamera::OpenFfmpeg() { // STolen from ispy //this fixes issues with rtsp streams!! woot. //mVideoCodecContext->flags2 |= CODEC_FLAG2_FAST | CODEC_FLAG2_CHUNKS | CODEC_FLAG_LOW_DELAY; // Enable faster H264 decode. +#ifdef CODEC_FLAG2_FAST mVideoCodecContext->flags2 |= CODEC_FLAG2_FAST | CODEC_FLAG_LOW_DELAY; +#endif #if HAVE_AVUTIL_HWCONTEXT_H if ( mVideoCodecContext->codec_id == AV_CODEC_ID_H264 ) { diff --git a/src/zm_mpeg.cpp b/src/zm_mpeg.cpp index e949052dc..2a7a24f87 100644 --- a/src/zm_mpeg.cpp +++ b/src/zm_mpeg.cpp @@ -211,39 +211,52 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei Debug( 1, "Allocated stream" ); - AVCodecContext *c = ost->codec; +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + codec_context = avcodec_alloc_context3(NULL); + avcodec_parameters_to_context(codec_context, ost->codecpar); +#else + codec_context = ost->codec; +#endif - c->codec_id = codec->id; - c->codec_type = codec->type; + codec_context->codec_id = codec->id; + codec_context->codec_type = codec->type; - c->pix_fmt = strcmp( "mjpeg", ofc->oformat->name ) == 0 ? AV_PIX_FMT_YUVJ422P : AV_PIX_FMT_YUV420P; + codec_context->pix_fmt = strcmp( "mjpeg", ofc->oformat->name ) == 0 ? AV_PIX_FMT_YUVJ422P : AV_PIX_FMT_YUV420P; if ( bitrate <= 100 ) { // Quality based bitrate control (VBR). Scale is 1..31 where 1 is best. // This gets rid of artifacts in the beginning of the movie; and well, even quality. - c->flags |= CODEC_FLAG_QSCALE; - c->global_quality = FF_QP2LAMBDA * (31 - (31 * (bitrate / 100.0))); +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + codec_context->flags |= AV_CODEC_FLAG_QSCALE; +#else + codec_context->flags |= CODEC_FLAG_QSCALE; +#endif + codec_context->global_quality = FF_QP2LAMBDA * (31 - (31 * (bitrate / 100.0))); } else { - c->bit_rate = bitrate; + codec_context->bit_rate = bitrate; } /* resolution must be a multiple of two */ - c->width = width; - c->height = height; + codec_context->width = width; + codec_context->height = height; /* time base: this is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented. for fixed-fps content, timebase should be 1/framerate and timestamp increments should be identically 1. */ - c->time_base.den = frame_rate; - c->time_base.num = 1; + codec_context->time_base.den = frame_rate; + codec_context->time_base.num = 1; - Debug( 1, "Will encode in %d fps.", c->time_base.den ); + Debug( 1, "Will encode in %d fps.", codec_context->time_base.den ); /* emit one intra frame every second */ - c->gop_size = frame_rate; + codec_context->gop_size = frame_rate; // some formats want stream headers to be separate if ( of->flags & AVFMT_GLOBALHEADER ) - c->flags |= CODEC_FLAG_GLOBAL_HEADER; +#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) + codec_context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; +#else + codec_context->flags |= CODEC_FLAG_GLOBAL_HEADER; +#endif } else { Fatal( "of->video_codec == AV_CODEC_ID_NONE" ); } @@ -278,13 +291,11 @@ void VideoStream::OpenStream( ) { /* now that all the parameters are set, we can open the video codecs and allocate the necessary encode buffers */ if ( ost ) { - AVCodecContext *c = ost->codec; - /* open the codec */ #if !LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 8, 0) - if ( (avRet = avcodec_open( c, codec )) < 0 ) + if ( (avRet = avcodec_open( codec_context, codec )) < 0 ) #else - if ( (avRet = avcodec_open2( c, codec, 0 )) < 0 ) + if ( (avRet = avcodec_open2( codec_context, codec, 0 )) < 0 ) #endif { Fatal( "Could not open codec. Error code %d \"%s\"", avRet, av_err2str( avRet ) ); @@ -293,19 +304,15 @@ void VideoStream::OpenStream( ) { Debug( 1, "Opened codec" ); /* allocate the encoded raw picture */ -#if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) - opicture = av_frame_alloc( ); -#else - opicture = avcodec_alloc_frame( ); -#endif + opicture = zm_av_frame_alloc( ); if ( !opicture ) { Panic( "Could not allocate opicture" ); } #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) - int size = av_image_get_buffer_size( c->pix_fmt, c->width, c->height, 1 ); + int size = av_image_get_buffer_size( codec_context->pix_fmt, codec_context->width, codec_context->height, 1 ); #else - int size = avpicture_get_size( c->pix_fmt, c->width, c->height ); + int size = avpicture_get_size( codec_context->pix_fmt, codec_context->width, codec_context->height ); #endif uint8_t *opicture_buf = (uint8_t *)av_malloc( size ); @@ -315,17 +322,17 @@ void VideoStream::OpenStream( ) { } #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) av_image_fill_arrays(opicture->data, opicture->linesize, - opicture_buf, c->pix_fmt, c->width, c->height, 1); + opicture_buf, codec_context->pix_fmt, codec_context->width, codec_context->height, 1); #else - avpicture_fill( (AVPicture *)opicture, opicture_buf, c->pix_fmt, - c->width, c->height ); + avpicture_fill( (AVPicture *)opicture, opicture_buf, codec_context->pix_fmt, + codec_context->width, codec_context->height ); #endif /* if the output format is not identical to the input format, then a temporary picture is needed too. It is then converted to the required output format */ tmp_opicture = NULL; - if ( c->pix_fmt != pf ) { + if ( codec_context->pix_fmt != pf ) { #if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) tmp_opicture = av_frame_alloc( ); #else @@ -335,9 +342,9 @@ void VideoStream::OpenStream( ) { Panic( "Could not allocate tmp_opicture" ); } #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) - int size = av_image_get_buffer_size( pf, c->width, c->height,1 ); + int size = av_image_get_buffer_size( pf, codec_context->width, codec_context->height,1 ); #else - int size = avpicture_get_size( pf, c->width, c->height ); + int size = avpicture_get_size( pf, codec_context->width, codec_context->height ); #endif uint8_t *tmp_opicture_buf = (uint8_t *)av_malloc( size ); if ( !tmp_opicture_buf ) { @@ -347,10 +354,10 @@ void VideoStream::OpenStream( ) { #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) av_image_fill_arrays(tmp_opicture->data, tmp_opicture->linesize, tmp_opicture_buf, pf, - c->width, c->height, 1); + codec_context->width, codec_context->height, 1); #else avpicture_fill( (AVPicture *)tmp_opicture, - tmp_opicture_buf, pf, c->width, c->height ); + tmp_opicture_buf, pf, codec_context->width, codec_context->height ); #endif } } @@ -375,7 +382,12 @@ void VideoStream::OpenStream( ) { } video_outbuf = NULL; +#if LIBAVFORMAT_VERSION_CHECK(57, 0, 0, 0, 0) + if (codec_context->codec_type == AVMEDIA_TYPE_VIDEO && + codec_context->codec_id == AV_CODEC_ID_RAWVIDEO) { +#else if ( !(of->flags & AVFMT_RAWPICTURE) ) { +#endif /* allocate output buffer */ /* XXX: API change will be done */ // TODO: Make buffer dynamic. @@ -446,6 +458,8 @@ VideoStream::VideoStream( const char *in_filename, const char *in_format, int bi if ( pthread_mutex_init( buffer_copy_lock, NULL ) != 0 ) { Fatal("pthread_mutex_init failed"); } + + codec_context = NULL; } VideoStream::~VideoStream( ) { @@ -481,7 +495,7 @@ VideoStream::~VideoStream( ) { /* close each codec */ if ( ost ) { - avcodec_close( ost->codec ); + avcodec_close( codec_context ); av_free( opicture->data[0] ); av_frame_free( &opicture ); if ( tmp_opicture ) { @@ -564,17 +578,15 @@ double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size, static struct SwsContext *img_convert_ctx = 0; #endif // HAVE_LIBSWSCALE - AVCodecContext *c = ost->codec; - - if ( c->pix_fmt != pf ) { + if ( codec_context->pix_fmt != pf ) { memcpy( tmp_opicture->data[0], buffer, buffer_size ); #ifdef HAVE_LIBSWSCALE if ( !img_convert_ctx ) { - img_convert_ctx = sws_getCachedContext( NULL, c->width, c->height, pf, c->width, c->height, c->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL ); + img_convert_ctx = sws_getCachedContext( NULL, codec_context->width, codec_context->height, pf, codec_context->width, codec_context->height, codec_context->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL ); if ( !img_convert_ctx ) Panic( "Unable to initialise image scaling context" ); } - sws_scale( img_convert_ctx, tmp_opicture->data, tmp_opicture->linesize, 0, c->height, opicture->data, opicture->linesize ); + sws_scale( img_convert_ctx, tmp_opicture->data, tmp_opicture->linesize, 0, codec_context->height, opicture->data, opicture->linesize ); #else // HAVE_LIBSWSCALE Fatal( "swscale is required for MPEG mode" ); #endif // HAVE_LIBSWSCALE @@ -586,7 +598,13 @@ double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size, AVPacket *pkt = packet_buffers[packet_index]; av_init_packet( pkt ); int got_packet = 0; +#if LIBAVFORMAT_VERSION_CHECK(57, 0, 0, 0, 0) + if (codec_context->codec_type == AVMEDIA_TYPE_VIDEO && + codec_context->codec_id == AV_CODEC_ID_RAWVIDEO) { +#else if ( of->flags & AVFMT_RAWPICTURE ) { +#endif + #if LIBAVCODEC_VERSION_CHECK(52, 30, 2, 30, 2) pkt->flags |= AV_PKT_FLAG_KEY; #else @@ -597,19 +615,34 @@ double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size, pkt->size = sizeof (AVPicture); got_packet = 1; } else { - opicture_ptr->pts = c->frame_number; - opicture_ptr->quality = c->global_quality; + opicture_ptr->pts = codec_context->frame_number; + opicture_ptr->quality = codec_context->global_quality; + +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + // Put encoder into flushing mode + avcodec_send_frame(codec_context, opicture_ptr); + int ret = avcodec_receive_packet(codec_context, pkt); + if ( ret < 0 ) { + if ( AVERROR_EOF != ret ) { + Error("ERror encoding video (%d) (%s)", ret, + av_err2str(ret)); + } + } else { + got_packet = 1; + } +#else #if LIBAVFORMAT_VERSION_CHECK(54, 1, 0, 2, 100) - int ret = avcodec_encode_video2( c, pkt, opicture_ptr, &got_packet ); + int ret = avcodec_encode_video2( codec_context, pkt, opicture_ptr, &got_packet ); if ( ret != 0 ) { Fatal( "avcodec_encode_video2 failed with errorcode %d \"%s\"", ret, av_err2str( ret ) ); } #else - int out_size = avcodec_encode_video( c, video_outbuf, video_outbuf_size, opicture_ptr ); + int out_size = avcodec_encode_video( codec_context, video_outbuf, video_outbuf_size, opicture_ptr ); got_packet = out_size > 0 ? 1 : 0; pkt->data = got_packet ? video_outbuf : NULL; pkt->size = got_packet ? out_size : 0; +#endif #endif if ( got_packet ) { // if ( c->coded_frame->key_frame ) @@ -622,12 +655,12 @@ double VideoStream::ActuallyEncodeFrame( const uint8_t *buffer, int buffer_size, // } if ( pkt->pts != (int64_t)AV_NOPTS_VALUE ) { - pkt->pts = av_rescale_q( pkt->pts, c->time_base, ost->time_base ); + pkt->pts = av_rescale_q( pkt->pts, codec_context->time_base, ost->time_base ); } if ( pkt->dts != (int64_t)AV_NOPTS_VALUE ) { - pkt->dts = av_rescale_q( pkt->dts, c->time_base, ost->time_base ); + pkt->dts = av_rescale_q( pkt->dts, codec_context->time_base, ost->time_base ); } - pkt->duration = av_rescale_q( pkt->duration, c->time_base, ost->time_base ); + pkt->duration = av_rescale_q( pkt->duration, codec_context->time_base, ost->time_base ); pkt->stream_index = ost->index; } } @@ -658,8 +691,12 @@ void *VideoStream::StreamingThreadCallback(void *ctx){ VideoStream* videoStream = reinterpret_cast(ctx); const uint64_t nanosecond_multiplier = 1000000000; - - uint64_t target_interval_ns = nanosecond_multiplier * ( ((double)videoStream->ost->codec->time_base.num) / (videoStream->ost->codec->time_base.den) ); + +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + uint64_t target_interval_ns = nanosecond_multiplier * ( ((double)videoStream->codec_context->time_base.num) / (videoStream->codec_context->time_base.den) ); +#else + uint64_t target_interval_ns = nanosecond_multiplier * ( ((double)videoStream->codec_context->time_base.num) / (videoStream->codec_context->time_base.den) ); +#endif uint64_t frame_count = 0; timespec start_time; clock_gettime(CLOCK_MONOTONIC, &start_time); diff --git a/src/zm_mpeg.h b/src/zm_mpeg.h index 931f9d687..f943b4fd7 100644 --- a/src/zm_mpeg.h +++ b/src/zm_mpeg.h @@ -46,6 +46,7 @@ protected: AVOutputFormat *of; AVFormatContext *ofc; AVStream *ost; + AVCodecContext *codec_context; AVCodec *codec; AVFrame *opicture; AVFrame *tmp_opicture; diff --git a/src/zm_remote_camera.cpp b/src/zm_remote_camera.cpp index 6afc7251b..58d92b73d 100644 --- a/src/zm_remote_camera.cpp +++ b/src/zm_remote_camera.cpp @@ -103,6 +103,7 @@ int RemoteCamera::Read( int fd, char *buf, int size ) { int bytes_to_recv = size - ReceivedBytes; if ( SOCKET_BUF_SIZE < bytes_to_recv ) bytes_to_recv = SOCKET_BUF_SIZE; +//Debug(3, "Aiming to receive %d of %d bytes", bytes_to_recv, size ); bytes = recv(fd, &buf[ReceivedBytes], bytes_to_recv, 0); //socket, buffer, len, flags if ( bytes <= 0 ) { Error("RemoteCamera::Read Recv error. Closing Socket\n"); diff --git a/src/zm_remote_camera.h b/src/zm_remote_camera.h index a0d391d9b..32e22c47a 100644 --- a/src/zm_remote_camera.h +++ b/src/zm_remote_camera.h @@ -87,7 +87,8 @@ public: virtual void Terminate() = 0; virtual int Connect() = 0; virtual int Disconnect() = 0; - virtual int PreCapture() = 0; + virtual int PreCapture() { return 0; }; + virtual int PrimeCapture() { return 0; }; virtual int Capture( Image &image ) = 0; virtual int PostCapture() = 0; virtual int CaptureAndRecord( Image &image, timeval recording, char* event_directory )=0; diff --git a/src/zm_remote_camera_nvsocket.cpp b/src/zm_remote_camera_nvsocket.cpp index 78f65bd92..98eff70cd 100644 --- a/src/zm_remote_camera_nvsocket.cpp +++ b/src/zm_remote_camera_nvsocket.cpp @@ -67,6 +67,7 @@ RemoteCameraNVSocket::RemoteCameraNVSocket( timeout.tv_sec = 0; timeout.tv_usec = 0; + subpixelorder = ZM_SUBPIX_ORDER_BGR; if ( capture ) { Initialise(); @@ -97,43 +98,39 @@ void RemoteCameraNVSocket::Initialise() { } int RemoteCameraNVSocket::Connect() { + int port_num = atoi(port.c_str()); //struct addrinfo *p; -struct sockaddr_in servaddr; - bzero( &servaddr, sizeof(servaddr)); - servaddr.sin_family = AF_INET; - servaddr.sin_addr.s_addr = htons(INADDR_ANY); - servaddr.sin_port = htons(atoi(port.c_str())); + struct sockaddr_in servaddr; + bzero( &servaddr, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = htons(INADDR_ANY); + servaddr.sin_port = htons(port_num); - - sd = socket(AF_INET, SOCK_STREAM, 0); + sd = socket(AF_INET, SOCK_STREAM, 0); //for(p = hp; p != NULL; p = p->ai_next) { - //sd = socket( p->ai_family, p->ai_socktype, p->ai_protocol ); - if ( sd < 0 ) { - Warning("Can't create socket: %s", strerror(errno) ); - //continue; - return -1; - } - - //if ( connect( sd, p->ai_addr, p->ai_addrlen ) < 0 ) { - if ( connect( sd, (struct sockaddr *)&servaddr , sizeof(servaddr) ) < 0 ) { - close(sd); - sd = -1; - - Warning("Can't connect to socket mid: %d : %s", monitor_id, strerror(errno) ); - return -1; - //continue; - //} - /* If we got here, we must have connected successfully */ - //break; + //sd = socket( p->ai_family, p->ai_socktype, p->ai_protocol ); + if ( sd < 0 ) { + Warning("Can't create socket: %s", strerror(errno) ); + //continue; + return -1; } - //if ( p == NULL ) { - //Error("Unable to connect to the remote camera, aborting"); - //return( -1 ); - //} + //if ( connect( sd, p->ai_addr, p->ai_addrlen ) < 0 ) { + if ( connect( sd, (struct sockaddr *)&servaddr , sizeof(servaddr) ) < 0 ) { + close(sd); + sd = -1; - Debug( 3, "Connected to host, socket = %d", sd ); - return( sd ); + Warning("Can't connect to socket mid: %d : %s", monitor_id, strerror(errno) ); + return -1; + } + +//if ( p == NULL ) { +//Error("Unable to connect to the remote camera, aborting"); +//return( -1 ); +//} + + Debug( 3, "Connected to host:%d, socket = %d", port_num, sd ); + return sd; } int RemoteCameraNVSocket::Disconnect() { @@ -144,132 +141,33 @@ int RemoteCameraNVSocket::Disconnect() { } int RemoteCameraNVSocket::SendRequest( std::string request ) { - Debug( 2, "Sending request: %s", request.c_str() ); + Debug( 4, "Sending request: %s", request.c_str() ); if ( write( sd, request.data(), request.length() ) < 0 ) { Error( "Can't write: %s", strerror(errno) ); Disconnect(); return( -1 ); } - Debug( 3, "Request sent" ); + Debug( 4, "Request sent" ); return( 0 ); } -/* Return codes are as follows: - * -1 means there was an error - * 0 means no bytes were returned but there wasn't actually an error. - * > 0 is the # of bytes read. - */ - -int RemoteCameraNVSocket::ReadData( Buffer &buffer, unsigned int bytes_expected ) { - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(sd, &rfds); - - struct timeval temp_timeout = timeout; - - int n_found = select(sd+1, &rfds, NULL, NULL, &temp_timeout); - if ( n_found == 0 ) { - Debug( 4, "Select timed out timeout was %d secs %d usecs", temp_timeout.tv_sec, temp_timeout.tv_usec ); - int error = 0; - socklen_t len = sizeof(error); - int retval = getsockopt(sd, SOL_SOCKET, SO_ERROR, &error, &len); - if ( retval != 0 ) { - Debug(1, "error getting socket error code %s", strerror(retval)); - } - if ( error != 0 ) { - return -1; - } - // Why are we disconnecting? It's just a timeout, meaning that data wasn't available. - //Disconnect(); - return 0; - } else if ( n_found < 0 ) { - Error("Select error: %s", strerror(errno)); - return -1; - } - - unsigned int total_bytes_to_read = 0; - - if ( bytes_expected ) { - total_bytes_to_read = bytes_expected; - } else { - if ( ioctl( sd, FIONREAD, &total_bytes_to_read ) < 0 ) { - Error( "Can't ioctl(): %s", strerror(errno) ); - return( -1 ); - } - - if ( total_bytes_to_read == 0 ) { - if ( mode == SINGLE_IMAGE ) { - int error = 0; - socklen_t len = sizeof (error); - int retval = getsockopt( sd, SOL_SOCKET, SO_ERROR, &error, &len ); - if(retval != 0 ) { - Debug( 1, "error getting socket error code %s", strerror(retval) ); - } - if (error != 0) { - return -1; - } - // Case where we are grabbing a single jpg, but no content-length was given, so the expectation is that we read until close. - return( 0 ); - } - // If socket is closed locally, then select will fail, but if it is closed remotely - // then we have an exception on our socket.. but no data. - Debug( 3, "Socket closed remotely" ); - //Disconnect(); // Disconnect is done outside of ReadData now. - return( -1 ); - } - - // There can be lots of bytes available. I've seen 4MB or more. This will vastly inflate our buffer size unnecessarily. - if ( total_bytes_to_read > ZM_NETWORK_BUFSIZ ) { - total_bytes_to_read = ZM_NETWORK_BUFSIZ; - Debug(3, "Just getting 32K" ); - } else { - Debug(3, "Just getting %d", total_bytes_to_read ); - } - } // end if bytes_expected or not - Debug( 3, "Expecting %d bytes", total_bytes_to_read ); - - int total_bytes_read = 0; - do { - int bytes_read = buffer.read_into( sd, total_bytes_to_read ); - if ( bytes_read < 0 ) { - Error( "Read error: %s", strerror(errno) ); - return( -1 ); - } else if ( bytes_read == 0 ) { - Debug( 2, "Socket closed" ); - //Disconnect(); // Disconnect is done outside of ReadData now. - return( -1 ); - } else if ( (unsigned int)bytes_read < total_bytes_to_read ) { - Error( "Incomplete read, expected %d, got %d", total_bytes_to_read, bytes_read ); - return( -1 ); - } - Debug( 3, "Read %d bytes", bytes_read ); - total_bytes_read += bytes_read; - total_bytes_to_read -= bytes_read; - } while ( total_bytes_to_read ); - - Debug( 4, buffer ); - - return( total_bytes_read ); -} - -int RemoteCameraNVSocket::PreCapture() { +int RemoteCameraNVSocket::PrimeCapture() { if ( sd < 0 ) { Connect(); if ( sd < 0 ) { Error( "Unable to connect to camera" ); return( -1 ); } - mode = SINGLE_IMAGE; - buffer.clear(); } -struct image_def { - uint16_t width; - uint16_t height; - uint16_t type; -}; -struct image_def image_def; + buffer.clear(); + struct image_def { + uint16_t width; + uint16_t height; + uint16_t type; + }; + struct image_def image_def; - if ( SendRequest("GetImageParams") < 0 ) { + if ( SendRequest("GetImageParams\n") < 0 ) { Error( "Unable to send request" ); Disconnect(); return -1; @@ -289,20 +187,28 @@ struct image_def image_def; } int RemoteCameraNVSocket::Capture( Image &image ) { - if ( SendRequest("GetNextImage") < 0 ) { + if ( SendRequest("GetNextImage\n") < 0 ) { Warning( "Unable to capture image, retrying" ); - return( 1 ); + return 0; } if ( Read( sd, buffer, imagesize ) < imagesize ) { Warning( "Unable to capture image, retrying" ); - return( 1 ); + return 0; + } + uint32_t end; + if ( Read(sd, (char *) &end , sizeof(end)) < 0 ) { + Warning( "Unable to capture image, retrying" ); + return 0; + } + if ( end != 0xFFFFFFFF) { + Warning("End Bytes Failed\n"); + return 0; } image.Assign( width, height, colours, subpixelorder, buffer, imagesize ); - return( 0 ); + return 1; } -int RemoteCameraNVSocket::PostCapture() -{ +int RemoteCameraNVSocket::PostCapture() { return( 0 ); } diff --git a/src/zm_remote_camera_nvsocket.h b/src/zm_remote_camera_nvsocket.h index 4f62bafe3..67df93032 100644 --- a/src/zm_remote_camera_nvsocket.h +++ b/src/zm_remote_camera_nvsocket.h @@ -67,7 +67,7 @@ bool p_record_audio ); int SendRequest( std::string ); int ReadData( Buffer &buffer, unsigned int bytes_expected=0 ); int GetResponse(); - int PreCapture(); + int PrimeCapture(); int Capture( Image &image ); int PostCapture(); int CaptureAndRecord( Image &image, timeval recording, char* event_directory ) {return(0);}; diff --git a/src/zm_sdp.cpp b/src/zm_sdp.cpp index ffcea791b..b9f4eb837 100644 --- a/src/zm_sdp.cpp +++ b/src/zm_sdp.cpp @@ -379,21 +379,31 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const stream->id = i; #endif + AVCodecContext *codec_context = NULL; +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + codec_context = avcodec_alloc_context3(NULL); + avcodec_parameters_to_context(codec_context, stream->codecpar); +#else + codec_context = stream->codec; +#endif + + + Debug( 1, "Looking for codec for %s payload type %d / %s", mediaDesc->getType().c_str(), mediaDesc->getPayloadType(), mediaDesc->getPayloadDesc().c_str() ); #if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) if ( mediaDesc->getType() == "video" ) - stream->codec->codec_type = AVMEDIA_TYPE_VIDEO; + codec_context->codec_type = AVMEDIA_TYPE_VIDEO; else if ( mediaDesc->getType() == "audio" ) - stream->codec->codec_type = AVMEDIA_TYPE_AUDIO; + codec_context->codec_type = AVMEDIA_TYPE_AUDIO; else if ( mediaDesc->getType() == "application" ) - stream->codec->codec_type = AVMEDIA_TYPE_DATA; + codec_context->codec_type = AVMEDIA_TYPE_DATA; #else if ( mediaDesc->getType() == "video" ) - stream->codec->codec_type = CODEC_TYPE_VIDEO; + codec_context->codec_type = CODEC_TYPE_VIDEO; else if ( mediaDesc->getType() == "audio" ) - stream->codec->codec_type = CODEC_TYPE_AUDIO; + codec_context->codec_type = CODEC_TYPE_AUDIO; else if ( mediaDesc->getType() == "application" ) - stream->codec->codec_type = CODEC_TYPE_DATA; + codec_context->codec_type = CODEC_TYPE_DATA; #endif #if LIBAVCODEC_VERSION_CHECK(55, 50, 3, 60, 103) @@ -410,31 +420,27 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const #if LIBAVCODEC_VERSION_CHECK(55, 50, 3, 60, 103) codec_name = std::string( smStaticPayloads[i].payloadName ); #else - strncpy( stream->codec->codec_name, smStaticPayloads[i].payloadName, sizeof(stream->codec->codec_name) );; + strncpy( codec_context->codec_name, smStaticPayloads[i].payloadName, sizeof(codec_context->codec_name) );; #endif - stream->codec->codec_type = smStaticPayloads[i].codecType; - stream->codec->codec_id = smStaticPayloads[i].codecId; - stream->codec->sample_rate = smStaticPayloads[i].clockRate; + codec_context->codec_type = smStaticPayloads[i].codecType; + codec_context->codec_id = smStaticPayloads[i].codecId; + codec_context->sample_rate = smStaticPayloads[i].clockRate; break; } } - } - else - { + } else { // Look in dynamic table - for ( unsigned int i = 0; i < (sizeof(smDynamicPayloads)/sizeof(*smDynamicPayloads)); i++ ) - { - if ( smDynamicPayloads[i].payloadName == mediaDesc->getPayloadDesc() ) - { + for ( unsigned int i = 0; i < (sizeof(smDynamicPayloads)/sizeof(*smDynamicPayloads)); i++ ) { + if ( smDynamicPayloads[i].payloadName == mediaDesc->getPayloadDesc() ) { Debug( 1, "Got dynamic payload type %d, %s", mediaDesc->getPayloadType(), smDynamicPayloads[i].payloadName ); #if LIBAVCODEC_VERSION_CHECK(55, 50, 3, 60, 103) codec_name = std::string( smStaticPayloads[i].payloadName ); #else - strncpy( stream->codec->codec_name, smDynamicPayloads[i].payloadName, sizeof(stream->codec->codec_name) );; + strncpy( codec_context->codec_name, smDynamicPayloads[i].payloadName, sizeof(codec_context->codec_name) );; #endif - stream->codec->codec_type = smDynamicPayloads[i].codecType; - stream->codec->codec_id = smDynamicPayloads[i].codecId; - stream->codec->sample_rate = mediaDesc->getClock(); + codec_context->codec_type = smDynamicPayloads[i].codecType; + codec_context->codec_id = smDynamicPayloads[i].codecId; + codec_context->sample_rate = mediaDesc->getClock(); break; } } @@ -450,14 +456,13 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const //return( 0 ); } if ( mediaDesc->getWidth() ) - stream->codec->width = mediaDesc->getWidth(); + codec_context->width = mediaDesc->getWidth(); if ( mediaDesc->getHeight() ) - stream->codec->height = mediaDesc->getHeight(); - if ( stream->codec->codec_id == AV_CODEC_ID_H264 && mediaDesc->getSprops().size()) - { + codec_context->height = mediaDesc->getHeight(); + if ( codec_context->codec_id == AV_CODEC_ID_H264 && mediaDesc->getSprops().size()) { uint8_t start_sequence[]= { 0, 0, 1 }; - stream->codec->extradata_size= 0; - stream->codec->extradata= NULL; + codec_context->extradata_size= 0; + codec_context->extradata= NULL; char pvalue[1024], *value = pvalue; strcpy(pvalue, mediaDesc->getSprops().c_str()); @@ -482,22 +487,33 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const if (packet_size) { uint8_t *dest = (uint8_t *)av_malloc(packet_size + sizeof(start_sequence) + - stream->codec->extradata_size + - FF_INPUT_BUFFER_PADDING_SIZE); + codec_context->extradata_size + +#if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0) + AV_INPUT_BUFFER_PADDING_SIZE +#else + FF_INPUT_BUFFER_PADDING_SIZE +#endif +); if(dest) { - if(stream->codec->extradata_size) { + if(codec_context->extradata_size) { // av_realloc? - memcpy(dest, stream->codec->extradata, stream->codec->extradata_size); - av_free(stream->codec->extradata); + memcpy(dest, codec_context->extradata, codec_context->extradata_size); + av_free(codec_context->extradata); } - memcpy(dest+stream->codec->extradata_size, start_sequence, sizeof(start_sequence)); - memcpy(dest+stream->codec->extradata_size+sizeof(start_sequence), decoded_packet, packet_size); - memset(dest+stream->codec->extradata_size+sizeof(start_sequence)+ - packet_size, 0, FF_INPUT_BUFFER_PADDING_SIZE); + memcpy(dest+codec_context->extradata_size, start_sequence, sizeof(start_sequence)); + memcpy(dest+codec_context->extradata_size+sizeof(start_sequence), decoded_packet, packet_size); + memset(dest+codec_context->extradata_size+sizeof(start_sequence)+ + packet_size, 0, +#if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0) + AV_INPUT_BUFFER_PADDING_SIZE +#else + FF_INPUT_BUFFER_PADDING_SIZE +#endif +); - stream->codec->extradata= dest; - stream->codec->extradata_size+= sizeof(start_sequence)+packet_size; + codec_context->extradata= dest; + codec_context->extradata_size+= sizeof(start_sequence)+packet_size; // } else { // av_log(codec, AV_LOG_ERROR, "Unable to allocate memory for extradata!"); // return AVERROR(ENOMEM); diff --git a/src/zm_sdp.h b/src/zm_sdp.h index 48a05b706..68e574d0f 100644 --- a/src/zm_sdp.h +++ b/src/zm_sdp.h @@ -31,13 +31,11 @@ #include #include -class SessionDescriptor -{ +class SessionDescriptor { protected: enum { PAYLOAD_TYPE_DYNAMIC=96 }; - struct StaticPayloadDesc - { + struct StaticPayloadDesc { int payloadType; const char payloadName[6]; #if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) @@ -50,8 +48,7 @@ protected: int autoChannels; }; - struct DynamicPayloadDesc - { + struct DynamicPayloadDesc { const char payloadName[32]; #if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) AVMediaType codecType; @@ -65,8 +62,7 @@ protected: }; public: - class ConnInfo - { + class ConnInfo { protected: std::string mNetworkType; std::string mAddressType; @@ -78,8 +74,7 @@ public: ConnInfo( const std::string &connInfo ); }; - class BandInfo - { + class BandInfo { protected: std::string mType; int mValue; @@ -88,8 +83,7 @@ public: BandInfo( const std::string &bandInfo ); }; - class MediaDescriptor - { + class MediaDescriptor { protected: std::string mType; int mPort; diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index c8704eae0..e6c4769b1 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -167,7 +167,11 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, video_out_ctx->time_base.den); if (oc->oformat->flags & AVFMT_GLOBALHEADER) { +#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) + video_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; +#else video_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; +#endif } Monitor::Orientation orientation = monitor->getOrientation(); @@ -274,7 +278,11 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in, if (audio_out_stream) { if (oc->oformat->flags & AVFMT_GLOBALHEADER) { - audio_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; +#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) + audio_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; +#else + audio_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; +#endif } } } // end if audio_in_stream From 625170bffcc31dbadd7b68bf916afc73ac109741 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 8 Nov 2017 11:17:30 -0500 Subject: [PATCH 31/47] fix getVideoStream to getVideoStreamHTML. Change how scaling works --- web/includes/functions.php | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index 8dcab3b42..2bb743681 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -339,11 +339,11 @@ function getVideoStreamHTML( $id, $src, $width, $height, $format, $title='' ) { } function outputImageStream( $id, $src, $width, $height, $title='' ) { - echo getImageStream( $id, $src, $width, $height, $title ); + echo getImageStreamHTML( $id, $src, $width, $height, $title ); } -function getImageStream( $id, $src, $width, $height, $title='' ) { +function getImageStreamHTML( $id, $src, $width, $height, $title='' ) { if ( canStreamIframe() ) { return '