2013-05-02 22:20:06 +08:00
< ? php
//
// ZoneMinder web timeline view file, $Date$, $Revision$
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
2016-12-26 23:23:16 +08:00
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
2013-05-02 22:20:06 +08:00
//
2017-05-19 02:04:24 +08:00
if ( ! canView ( 'Events' ) ) {
$view = 'error' ;
return ;
2013-05-02 22:20:06 +08:00
}
foreach ( getSkinIncludes ( 'includes/timeline_functions.php' ) as $includeFile )
2017-05-19 02:04:24 +08:00
require_once $includeFile ;
2013-05-02 22:20:06 +08:00
//
// Date/time formats used in charts
//
// These are the time axis range text. The first of each pair is the start date/time
// and the second is the last so often contains additional information
//
// When the chart range is years
2017-05-19 03:11:26 +08:00
define ( 'STRF_TL_AXIS_RANGE_YEAR1' , '%b %Y' );
define ( 'STRF_TL_AXIS_RANGE_YEAR2' , STRF_TL_AXIS_RANGE_YEAR1 );
2013-05-02 22:20:06 +08:00
// When the chart range is months
2017-07-14 05:34:45 +08:00
define ( 'STRF_TL_AXIS_RANGE_MONTH1' , '%b' );
define ( 'STRF_TL_AXIS_RANGE_MONTH2' , STRF_TL_AXIS_RANGE_MONTH1 . ' %Y' );
2013-05-02 22:20:06 +08:00
// When the chart range is days
2017-07-14 05:34:45 +08:00
define ( 'STRF_TL_AXIS_RANGE_DAY1' , '%d' );
define ( 'STRF_TL_AXIS_RANGE_DAY2' , STRF_TL_AXIS_RANGE_DAY1 . ' %b %Y' );
2013-05-02 22:20:06 +08:00
// When the chart range is less than a day
2017-07-14 05:34:45 +08:00
define ( 'STRF_TL_AXIS_RANGE_TIME1' , '%H:%M' );
define ( 'STRF_TL_AXIS_RANGE_TIME2' , STRF_TL_AXIS_RANGE_TIME1 . ', %d %b %Y' );
2013-05-02 22:20:06 +08:00
//
// These are the time axis tick labels
//
define ( " STRF_TL_AXIS_LABEL_YEAR " , " %Y " );
define ( " STRF_TL_AXIS_LABEL_MONTH " , " %M " );
define ( " STRF_TL_AXIS_LABEL_WEEK " , " %d/%m " );
define ( " STRF_TL_AXIS_LABEL_DAY " , " %d " );
define ( " STRF_TL_AXIS_LABEL_4HOUR " , " %H:00 " );
define ( " STRF_TL_AXIS_LABEL_HOUR " , " %H:00 " );
define ( " STRF_TL_AXIS_LABEL_10MINUTE " , " %H:%M " );
define ( " STRF_TL_AXIS_LABEL_MINUTE " , " %H:%M " );
define ( " STRF_TL_AXIS_LABEL_10SECOND " , " %S " );
define ( " STRF_TL_AXIS_LABEL_SECOND " , " %S " );
$mouseover = true ;
if ( ! isset ( $mouseover ) )
2017-05-19 02:04:24 +08:00
$mouseover = true ;
2013-05-02 22:20:06 +08:00
2017-05-19 02:04:24 +08:00
$mode = 'overlay' ;
2013-05-02 22:20:06 +08:00
if ( ! isset ( $mode ) )
2017-05-19 02:04:24 +08:00
$mode = 'overlay' ;
2013-05-02 22:20:06 +08:00
$minEventWidth = 3 ;
$maxEventWidth = 6 ;
$chart = array (
2017-07-14 05:34:45 +08:00
'width' => 700 ,
'height' => 460 ,
'image' => array (
'width' => 264 ,
'height' => 220 ,
'topOffset' => 20 ,
2017-05-19 03:11:26 +08:00
),
2017-07-14 05:34:45 +08:00
'imageText' => array (
'width' => 400 ,
'height' => 30 ,
'topOffset' => 20 ,
2017-05-19 03:11:26 +08:00
),
2017-07-14 05:34:45 +08:00
'graph' => array (
'width' => 600 ,
'height' => 160 ,
'topOffset' => 30 ,
2017-05-19 03:11:26 +08:00
),
2017-07-14 05:34:45 +08:00
'title' => array (
'topOffset' => 50
2017-05-19 03:11:26 +08:00
),
2017-07-14 05:34:45 +08:00
'key' => array (
'topOffset' => 50
2017-05-19 03:11:26 +08:00
),
2017-07-14 05:34:45 +08:00
'axes' => array (
'x' => array (
'height' => 20 ,
2017-05-19 03:11:26 +08:00
),
2017-07-14 05:34:45 +08:00
'y' => array (
'width' => 30 ,
2017-05-19 03:11:26 +08:00
),
2013-05-02 22:20:06 +08:00
),
2017-07-14 05:34:45 +08:00
'grid' => array (
'x' => array (
'major' => array (
'max' => 12 ,
'min' => 4 ,
2013-05-02 22:20:06 +08:00
),
2017-07-14 05:34:45 +08:00
'minor' => array (
'max' => 48 ,
'min' => 12 ,
2013-05-02 22:20:06 +08:00
),
2017-05-19 03:11:26 +08:00
),
2017-07-14 05:34:45 +08:00
'y' => array (
'major' => array (
'max' => 8 ,
'min' => 1 ,
2013-05-02 22:20:06 +08:00
),
2017-07-14 05:34:45 +08:00
'minor' => array (
'max' => 0 ,
'min' => 0 ,
2013-05-02 22:20:06 +08:00
),
2017-05-19 03:11:26 +08:00
),
2013-05-02 22:20:06 +08:00
),
);
$monitors = array ();
2017-05-19 02:04:24 +08:00
$monitorsSql = 'SELECT * FROM Monitors ORDER BY Sequence ASC' ;
2013-05-02 22:20:06 +08:00
//srand( 97981 );
2017-05-19 02:04:24 +08:00
foreach ( dbFetchAll ( $monitorsSql ) as $row ) {
//if ( empty($row['WebColour']) )
//{
//$row['WebColour'] = sprintf( "#%02x%02x%02x", rand( 0, 255 ), rand( 0, 255), rand( 0, 255 ) );
//}
$monitors [ $row [ 'Id' ]] = $row ;
2013-05-02 22:20:06 +08:00
}
2017-05-19 23:00:37 +08:00
# The as E, and joining with Monitors is required for the filterSQL filters.
2017-05-19 03:11:26 +08:00
$rangeSql = 'SELECT min(E.StartTime) AS MinTime, max(E.EndTime) AS MaxTime FROM Events AS E INNER JOIN Monitors AS M ON (E.MonitorId = M.Id) WHERE NOT isnull(E.StartTime) AND NOT isnull(E.EndTime)' ;
$eventsSql = 'SELECT * FROM Events AS E WHERE NOT isnull(StartTime)' ;
2013-05-02 22:20:06 +08:00
2017-05-19 02:04:24 +08:00
if ( ! empty ( $user [ 'MonitorIds' ]) ) {
$monFilterSql = ' AND MonitorId IN (' . $user [ 'MonitorIds' ] . ')' ;
2013-05-02 22:20:06 +08:00
2017-05-19 02:04:24 +08:00
$rangeSql .= $monFilterSql ;
$eventsSql .= $monFilterSql ;
2013-05-02 22:20:06 +08:00
}
if ( isset ( $_REQUEST [ 'filter' ]) )
2017-07-14 05:34:45 +08:00
$tree = parseFilterToTree ( $_REQUEST [ 'filter' ][ 'Query' ] );
2013-05-02 22:20:06 +08:00
else
2017-05-19 02:04:24 +08:00
$tree = false ;
2013-05-02 22:20:06 +08:00
if ( isset ( $_REQUEST [ 'range' ]) )
2017-05-19 03:11:26 +08:00
$range = validHtmlStr ( $_REQUEST [ 'range' ]);
2013-05-02 22:20:06 +08:00
if ( isset ( $_REQUEST [ 'minTime' ]) )
2017-05-19 03:11:26 +08:00
$minTime = validHtmlStr ( $_REQUEST [ 'minTime' ]);
2013-05-02 22:20:06 +08:00
if ( isset ( $_REQUEST [ 'midTime' ]) )
2017-05-19 03:11:26 +08:00
$midTime = validHtmlStr ( $_REQUEST [ 'midTime' ]);
2013-05-02 22:20:06 +08:00
if ( isset ( $_REQUEST [ 'maxTime' ]) )
2017-05-19 03:11:26 +08:00
$maxTime = validHtmlStr ( $_REQUEST [ 'maxTime' ]);
2013-05-02 22:20:06 +08:00
2017-05-19 02:04:24 +08:00
if ( isset ( $range ) ) {
2017-05-19 03:11:26 +08:00
$halfRange = ( int )( $range / 2 );
if ( isset ( $midTime ) ) {
$midTimeT = strtotime ( $midTime );
$minTimeT = $midTimeT - $halfRange ;
$maxTimeT = $midTimeT + $halfRange ;
if ( ! ( $range % 1 ) ) {
$maxTimeT -- ;
2013-05-02 22:20:06 +08:00
}
2017-05-19 03:11:26 +08:00
$minTime = strftime ( STRF_FMT_DATETIME_DB , $minTimeT );
$maxTime = strftime ( STRF_FMT_DATETIME_DB , $maxTimeT );
} elseif ( isset ( $minTime ) ) {
2013-05-02 22:20:06 +08:00
$minTimeT = strtotime ( $minTime );
2017-05-19 03:11:26 +08:00
$maxTimeT = $minTimeT + $range ;
2013-05-02 22:20:06 +08:00
$midTimeT = $minTimeT + $halfRange ;
$midTime = strftime ( STRF_FMT_DATETIME_DB , $midTimeT );
2017-05-19 03:11:26 +08:00
$maxTime = strftime ( STRF_FMT_DATETIME_DB , $maxTimeT );
} elseif ( isset ( $maxTime ) ) {
2013-05-02 22:20:06 +08:00
$maxTimeT = strtotime ( $maxTime );
2017-05-19 03:11:26 +08:00
$minTimeT = $maxTimeT - $range ;
2013-05-02 22:20:06 +08:00
$midTimeT = $minTimeT + $halfRange ;
2017-05-19 03:11:26 +08:00
$minTime = strftime ( STRF_FMT_DATETIME_DB , $minTimeT );
2013-05-02 22:20:06 +08:00
$midTime = strftime ( STRF_FMT_DATETIME_DB , $midTimeT );
2017-05-19 03:11:26 +08:00
}
} elseif ( isset ( $minTime ) && isset ( $maxTime ) ) {
$minTimeT = strtotime ( $minTime );
$maxTimeT = strtotime ( $maxTime );
$range = ( $maxTimeT - $minTimeT ) + 1 ;
$halfRange = ( int )( $range / 2 );
$midTimeT = $minTimeT + $halfRange ;
$midTime = strftime ( STRF_FMT_DATETIME_DB , $midTimeT );
2013-05-02 22:20:06 +08:00
}
2017-05-19 02:04:24 +08:00
if ( isset ( $minTime ) && isset ( $maxTime ) ) {
2017-05-19 03:11:26 +08:00
$tempMinTime = $tempMaxTime = $tempExpandable = false ;
extractDatetimeRange ( $tree , $tempMinTime , $tempMaxTime , $tempExpandable );
$filterSql = parseTreeToSQL ( $tree );
2013-05-02 22:20:06 +08:00
2017-05-19 03:11:26 +08:00
if ( $filterSql ) {
$filterSql = " and $filterSql " ;
$eventsSql .= $filterSql ;
}
2017-05-19 02:04:24 +08:00
} else {
2017-05-19 03:11:26 +08:00
$filterSql = parseTreeToSQL ( $tree );
$tempMinTime = $tempMaxTime = $tempExpandable = false ;
extractDatetimeRange ( $tree , $tempMinTime , $tempMaxTime , $tempExpandable );
if ( $filterSql ) {
$filterSql = " and $filterSql " ;
$rangeSql .= $filterSql ;
$eventsSql .= $filterSql ;
}
2013-05-02 22:20:06 +08:00
2017-05-19 03:11:26 +08:00
if ( ! isset ( $minTime ) || ! isset ( $maxTime ) ) {
// Dynamically determine range
$row = dbFetchOne ( $rangeSql );
2013-05-02 22:20:06 +08:00
2017-05-19 03:11:26 +08:00
if ( ! isset ( $minTime ) )
$minTime = $row [ 'MinTime' ];
if ( ! isset ( $maxTime ) )
$maxTime = $row [ 'MaxTime' ];
}
2013-05-02 22:20:06 +08:00
2017-05-19 03:11:26 +08:00
if ( empty ( $minTime ) )
$minTime = $tempMinTime ;
if ( empty ( $maxTime ) )
$maxTime = $tempMaxTime ;
if ( empty ( $maxTime ) )
$maxTime = " now " ;
$minTimeT = strtotime ( $minTime );
$maxTimeT = strtotime ( $maxTime );
$range = ( $maxTimeT - $minTimeT ) + 1 ;
$halfRange = ( int )( $range / 2 );
$midTimeT = $minTimeT + $halfRange ;
$midTime = strftime ( STRF_FMT_DATETIME_DB , $midTimeT );
2013-05-02 22:20:06 +08:00
}
//echo "MnT: $tempMinTime, MxT: $tempMaxTime, ExP: $tempExpandable<br>";
2017-05-19 02:04:24 +08:00
if ( $tree ) {
2017-05-19 03:11:26 +08:00
appendDatetimeRange ( $tree , $minTime , $maxTime );
2013-05-02 22:20:06 +08:00
2017-05-19 03:11:26 +08:00
$filterQuery = parseTreeToQuery ( $tree );
2017-05-19 02:04:24 +08:00
} else {
2017-05-19 03:11:26 +08:00
$filterQuery = false ;
2013-05-02 22:20:06 +08:00
}
$scales = array (
2017-07-14 05:34:45 +08:00
array ( 'name' => " year " , 'factor' => 60 * 60 * 24 * 365 , 'align' => 1 , 'zoomout' => 2 , 'label' => STRF_TL_AXIS_LABEL_YEAR ),
array ( 'name' => " month " , 'factor' => 60 * 60 * 24 * 30 , 'align' => 1 , 'zoomout' => 12 , 'label' => STRF_TL_AXIS_LABEL_MONTH ),
array ( 'name' => " week " , 'factor' => 60 * 60 * 24 * 7 , 'align' => 1 , 'zoomout' => 4.25 , 'label' => STRF_TL_AXIS_LABEL_WEEK , 'labelCheck' => " %W " ),
array ( 'name' => " day " , 'factor' => 60 * 60 * 24 , 'align' => 1 , 'zoomout' => 7 , 'label' => STRF_TL_AXIS_LABEL_DAY ),
array ( 'name' => " hour4 " , 'factor' => 60 * 60 , 'align' => 4 , 'zoomout' => 6 , 'label' => STRF_TL_AXIS_LABEL_4HOUR , 'labelCheck' => " %H " ),
array ( 'name' => " hour " , 'factor' => 60 * 60 , 'align' => 1 , 'zoomout' => 4 , 'label' => STRF_TL_AXIS_LABEL_HOUR , 'labelCheck' => " %H " ),
array ( 'name' => " minute10 " , 'factor' => 60 , 'align' => 10 , 'zoomout' => 6 , 'label' => STRF_TL_AXIS_LABEL_10MINUTE , 'labelCheck' => " %M " ),
array ( 'name' => " minute " , 'factor' => 60 , 'align' => 1 , 'zoomout' => 10 , 'label' => STRF_TL_AXIS_LABEL_MINUTE , 'labelCheck' => " %M " ),
array ( 'name' => " second10 " , 'factor' => 1 , 'align' => 10 , 'zoomout' => 6 , 'label' => STRF_TL_AXIS_LABEL_10SECOND ),
array ( 'name' => " second " , 'factor' => 1 , 'align' => 1 , 'zoomout' => 10 , 'label' => STRF_TL_AXIS_LABEL_SECOND ),
2013-05-02 22:20:06 +08:00
);
$majXScale = getDateScale ( $scales , $range , $chart [ 'grid' ][ 'x' ][ 'major' ][ 'min' ], $chart [ 'grid' ][ 'x' ][ 'major' ][ 'max' ] );
// Adjust the range etc for scale
$minTimeT -= $minTimeT % ( $majXScale [ 'factor' ] * $majXScale [ 'align' ]);
$minTime = strftime ( STRF_FMT_DATETIME_DB , $minTimeT );
$maxTimeT += (( $majXScale [ 'factor' ] * $majXScale [ 'align' ]) - $maxTimeT % ( $majXScale [ 'factor' ] * $majXScale [ 'align' ])) - 1 ;
if ( $maxTimeT > time () )
2017-05-19 03:11:26 +08:00
$maxTimeT = time ();
2013-05-02 22:20:06 +08:00
$maxTime = strftime ( STRF_FMT_DATETIME_DB , $maxTimeT );
$range = ( $maxTimeT - $minTimeT ) + 1 ;
$halfRange = ( int )( $range / 2 );
$midTimeT = $minTimeT + $halfRange ;
$midTime = strftime ( STRF_FMT_DATETIME_DB , $midTimeT );
//echo "R:$range<br>";
//echo "MnT:$minTime<br>";
//echo "MnTt:$minTimeT<br>";
//echo "MdT:$midTime<br>";
//echo "MdTt:$midTimeT<br>";
//echo "MxT:$maxTime<br>";
//echo "MxTt:$maxTimeT<br>";
2017-05-19 02:04:24 +08:00
if ( isset ( $minTime ) && isset ( $maxTime ) ) {
Feature h264 videostorage (#1882)
* Moved writing of configure options from Controller to Model. Fixes #191.
* Initial commit for saving events as videos :)
* Add zm_video.cpp to autotools
* Add zm_video.h to autotools
* Search for MP4V2 header file 3 times: mp4v2/mp4v2.h, mp4v2.h, mp4.h
* Fix serve memory leak
* Few minor code improvements
* Added the ability to override preset, tune, profile and few other improvements
* Correctly write SPS & PPS from x264 encoder headers
* Remove unnessecary SPS & PPS writing code
* Imported missing files from master to feature-h264-videostorage
* Audio support including fixes for dts/pts, split on keyframe and update to mkv extension to prevent ffmpeg problems writing rtsp audio to mp4 containter (header problem)
* Updates to make gcc happy
* Add html5 video control to timeline and event to support mkv playback
* Add zm_videostore.cpp to CMakeLists.txt
* Remove Modern Branch for now
* Fix minor bug
* Option handled added in master, removing duplicate declaration
* Add CaptureandRecord from zm_camera.h
* Putting placeholder in for CaptureAndRecord function
* Removed duplicate code and brackets
* add digest auth file for cmake
Conflicts:
src/CMakeLists.txt
* Add web dir back into Makefile.am
Revert "Removed web from SUBDIRS in Makefile.am"
This reverts commit d9bbcdf3a94cba4d8955fcd03bd965ed2772f34d.
* Add CaptureAndRecord to vlc, still need to make it record
* Resolve SegFault on videostore
* Swap to mp4 container
* mp4 changes
* spaces to tabs, hide video stuff if video writer is turned off
* Make timeline open event.mp4 instead of mkv
* Missed mkv in timeline.js
* Fix some issues from the merge conflict
* Resolve post merge build issues with braces
* Fix whitespace
* Update Jpeg and Video options for passthrough options
* Whitespace fix zm_camera.h
* Fix array mkssing comma
* Add support for Jpeg save options for h264 branch snapshot. Might remove altogether if snapshots not needed
* Update VideoStoreData memory size comment
* Change from config.use_mkv_storage to per monitor option VideoWriter from video branch
* Fix bracket issues post merge
* Clean up comments and add av_free_packet
* Convert from event_directory to event file as per Video branch
* Testing videojs for video playback
* Fixed a missing bracket post merge and also SQL_values now used for EventID and Monitors
* bring recent improvements in ffmpeg capture function into captureandrecord
* Remove pict from writeAudioFramePacket as not used
* Add translate options for h264 Storage options in Monitor and update en_gb file
* Cherry-Pick from iconnor - make it compile on ubuntu 15.04. Which is libav 56.1.0
Conflicts:
src/zm_ffmpeg.cpp
src/zm_remote_camera_rtsp.cpp
Conflicts:
distros/ubuntu1204/changelog
* Clean up videostore code and remove lots of unused code
* proof of concept for dynamic/automatic video rotation using video-js plugin zoomrotate
Conflicts:
web/skins/classic/views/event.php
* removed redundant field in sql query
Conflicts:
web/skins/classic/views/event.php
* local storage of video js plugin
* Beautify!
Make the code somewhat readable.
* added missing videojs.zoomrotate.js file
added missing videojs.zoomrotate.js file
* Typo
added missing "
* Added missing brackets
* fix to display thumbnails when only storing snapshot.jpg
* added control for video playback rate
Conflicts:
web/skins/classic/views/event.php
* dynamically create jpegs from video file for viewing in browser
* fix timeline view for SaveJPEGs monitors (without enabled VideoWriter)
* only expose monitor info which are being used in client
* fix segmentation fault in zma with ubuntu 14.04 and ffmpeg 2.5.8 (gcc 4.8)
when libx264 is not installed
* better way of detecting showing image or video in timeline and event view
instead of Monitor.VideoWriter, Event.DefaultVideo is used, so even if
VideoWriter/SaveJPEG option is changed, a valid image or video will always be
displayed for historical events in both timeline and event view
this also fixes loading videos in timeline view
* Fixes problem of crashing zmc when bad packet arrives causing av_interleaved_write_frame() to return non-zero (-22). Prefilters common packet issues. Add metadata title to generated video file
* Remove syslog.h
* fixed SaveJPEGs are not working
which is caused in errors introduced when merging with master
* Update README.md
* Fix build warnings specific to h264 branch, unused FrameImg, unused ret and int64_t snprintf issues
* Fix PRId64 issue in travis, builds locally fine, but I can see a gcc version issue here
* Fix PRId64 issue in travis, another try
* Try "STDC_FORMAT_MACROS" to see if that helps Travis on gcc 4.6.3
* Revert space removal around PRId64
* video branch ffmpeg 2.9 fixes
ffmpeg 2.9 patched removed SSE2 CPU
* Add FFMPEGInit back
* use webvvt to overlay timestamp (honoring Monitor.LabelFormat) to videos in timeline and event
also fixed bug which prevented seeking in timeline video preview
* ffmpeg 3.0 API build failure fixes
* Update README.md
* merge all the commits from the messed up iconnor_video branch
* fix whitespace
* revert
* whitespace fixes
* spelling fix
* put back some text
* add these back
* fix spelling mistake
* Steal some packet dumping routines from ffmpeg. Convert them to use our logging routines
* add a test and error message if the codec is not h264
* these have been removed in master
* add a view to check auth and just send the video
* add some comments, and dump filename and AVFormatContext on failure to write header
* add the toggle for RecordAudio so that the checkbox works to turn off Audio
* Must init videoStore in constuctor
* more debug and comments, return checking
* Fix dropped part of sql query.
* fix extra else and some whitespace
* Fix missing } from merge that was preventing building.
* fix tabs
* get rid of use of separator, just use \n
* Restore lost fixes for deprecation
* Why are these failing
* Respect record_audio flag when setting up video file so dont try and initiliase mp4 with unsupported audio
* Forgot that I was trying to solve case of stream is true and record_audio
is false.
* Pass swscale_ctx back in to getCachedContext or it will create new
context every frame and leak memory like a mofo.
* Add libx264-dev and libmp4v2-dev to build requires to save hassle of
ensuring they are installed before build.
* Merge my Rotation/Orientation work and fixes for bad h264 streams
* need arpa/inet for reverse lookups
* pull in the new byte range code for viewing videos
* Move our recording flag deeper into closeevent
* add braces and only call closeEvent if there is an event
* deprecate the z_frame_rate stuff which is deprecated in ffmpeg
* remark out some debugging
* fix for video on stream 1
* fix audio_stream to audio_st
* Ignore bad decodes
* fix problems with content-length causing viewing to not work in chrome/android
* change logic of sending file contents to handle an off by one and be more readable
* Some fixes pointed out by Maxim Romanov. Also simply the loading of events to not join the Monitors table
* fix to sql for timeline
* added RecordAudio to sql in README
* Use sub queries instead of joins to fix errors when using new mysql defaults.
* fix sql queries
* Dockerfile to build feature-h264-videostorage
* Must cast codec
* add php-acpu as a dependency
* require php5-acpu
* fix typo
* remove extra /
* Add a line for out-of-tree builds to do api/lib/Cake/bootstrap.php
* delete merge conflict files
* delete merge conflict files
2017-05-16 10:02:48 +08:00
$eventsSql .= " and EndTime >= ' $minTime ' and StartTime <= ' $maxTime ' " ;
2013-05-02 22:20:06 +08:00
}
2017-07-14 05:34:45 +08:00
$eventsSql .= ' order by Id asc' ;
2013-05-02 22:20:06 +08:00
//echo "ESQL: $eventsSql<br>";
$chart [ 'data' ] = array (
2017-07-14 05:34:45 +08:00
'x' => array (
'lo' => strtotime ( $minTime ),
'hi' => strtotime ( $maxTime ),
2017-05-19 03:11:26 +08:00
),
2017-07-14 05:34:45 +08:00
'y' => array (
'lo' => 0 ,
'hi' => 0 ,
2017-05-19 03:11:26 +08:00
)
2013-05-02 22:20:06 +08:00
);
$chart [ 'data' ][ 'x' ][ 'range' ] = ( $chart [ 'data' ][ 'x' ][ 'hi' ] - $chart [ 'data' ][ 'x' ][ 'lo' ]) + 1 ;
$chart [ 'data' ][ 'x' ][ 'density' ] = $chart [ 'data' ][ 'x' ][ 'range' ] / $chart [ 'graph' ][ 'width' ];
$monEventSlots = array ();
$monFrameSlots = array ();
$monitorIds = array ();
2017-07-14 05:34:45 +08:00
$events_result = dbQuery ( $eventsSql );
if ( ! $events_result ) {
Fatal ( " SQL-ERR " );
return ;
}
$first_event = $event = $events_result -> fetch ( PDO :: FETCH_ASSOC );
if ( $event ) {
do {
if ( ! isset ( $monitorIds [ $event [ 'MonitorId' ]]) )
$monitorIds [ $event [ 'MonitorId' ]] = true ;
2017-05-19 03:11:26 +08:00
2017-07-14 05:34:45 +08:00
if ( ! isset ( $monEventSlots [ $event [ 'MonitorId' ]]) )
$monEventSlots [ $event [ 'MonitorId' ]] = array ();
2017-05-19 03:11:26 +08:00
2017-07-14 05:34:45 +08:00
if ( ! isset ( $monFrameSlots [ $event [ 'MonitorId' ]]) )
$monFrameSlots [ $event [ 'MonitorId' ]] = array ();
2017-05-19 03:11:26 +08:00
2017-07-14 05:34:45 +08:00
$currEventSlots = & $monEventSlots [ $event [ 'MonitorId' ]];
$currFrameSlots = & $monFrameSlots [ $event [ 'MonitorId' ]];
2017-05-19 03:11:26 +08:00
2017-07-14 05:34:45 +08:00
$startTimeT = strtotime ( $event [ 'StartTime' ]);
$startIndex = $rawStartIndex = ( int )(( $startTimeT - $chart [ 'data' ][ 'x' ][ 'lo' ]) / $chart [ 'data' ][ 'x' ][ 'density' ]);
if ( $startIndex < 0 )
$startIndex = 0 ;
2017-05-19 03:11:26 +08:00
2017-07-14 05:34:45 +08:00
if ( isset ( $event [ 'EndTime' ]) )
$endTimeT = strtotime ( $event [ 'EndTime' ]);
else
$endTimeT = time ();
$endIndex = $rawEndIndex = ( int )(( $endTimeT - $chart [ 'data' ][ 'x' ][ 'lo' ]) / $chart [ 'data' ][ 'x' ][ 'density' ]);
2017-05-19 03:11:26 +08:00
2017-07-14 05:34:45 +08:00
if ( $endIndex >= $chart [ 'graph' ][ 'width' ] )
$endIndex = $chart [ 'graph' ][ 'width' ] - 1 ;
2017-05-19 03:11:26 +08:00
2017-07-14 05:34:45 +08:00
for ( $i = $startIndex ; $i <= $endIndex ; $i ++ ) {
if ( ! isset ( $currEventSlots [ $i ]) ) {
if ( $rawStartIndex == $rawEndIndex ) {
$offset = 1 ;
} else {
$offset = 1 + ( $event [ 'Frames' ] ? (( int )(( $event [ 'Frames' ] - 1 ) * (( $i - $rawStartIndex ) / ( $rawEndIndex - $rawStartIndex )))) : 0 );
}
$currEventSlots [ $i ] = array ( 'count' => 0 , 'width' => 1 , 'offset' => $offset , 'event' => $event );
2017-05-19 03:11:26 +08:00
} else {
2017-07-14 05:34:45 +08:00
$currEventSlots [ $i ][ 'count' ] ++ ;
2017-05-19 03:11:26 +08:00
}
2013-05-02 22:20:06 +08:00
}
2017-07-14 05:34:45 +08:00
if ( $event [ 'MaxScore' ] > 0 ) {
if ( $startIndex == $endIndex ) {
$framesSql = 'SELECT FrameId,Score FROM Frames WHERE EventId = ? AND Score > 0 ORDER BY Score DESC LIMIT 1' ;
$frame = dbFetchOne ( $framesSql , NULL , array ( $event [ 'Id' ]) );
$i = $startIndex ;
if ( ! isset ( $currFrameSlots [ $i ]) ) {
$currFrameSlots [ $i ] = array ( 'count' => 1 , 'value' => $event [ 'MaxScore' ], 'event' => $event , 'frame' => $frame );
2017-05-19 02:04:24 +08:00
} else {
2017-07-14 05:34:45 +08:00
$currFrameSlots [ $i ][ 'count' ] ++ ;
if ( $event [ 'MaxScore' ] > $currFrameSlots [ $i ][ 'value' ] ) {
$currFrameSlots [ $i ][ 'value' ] = $event [ 'MaxScore' ];
$currFrameSlots [ $i ][ 'event' ] = $event ;
$currFrameSlots [ $i ][ 'frame' ] = $frame ;
2017-05-19 03:11:26 +08:00
}
2013-05-02 22:20:06 +08:00
}
2017-07-14 05:34:45 +08:00
if ( $event [ 'MaxScore' ] > $chart [ 'data' ][ 'y' ][ 'hi' ] ) {
$chart [ 'data' ][ 'y' ][ 'hi' ] = $event [ 'MaxScore' ];
2013-05-02 22:20:06 +08:00
}
2017-07-14 05:34:45 +08:00
} else {
$framesSql = 'SELECT FrameId,Delta,unix_timestamp(TimeStamp) AS TimeT,Score FROM Frames WHERE EventId = ? AND Score > 0' ;
$result = dbQuery ( $framesSql , array ( $event [ 'Id' ] ) );
while ( $frame = dbFetchNext ( $result ) ) {
if ( $frame [ 'Score' ] == 0 )
continue ;
$frameTimeT = $frame [ 'TimeT' ];
$frameTimeT = $startTimeT + $frame [ 'Delta' ];
$frameIndex = ( int )(( $frameTimeT - $chart [ 'data' ][ 'x' ][ 'lo' ]) / $chart [ 'data' ][ 'x' ][ 'density' ]);
if ( $frameIndex < 0 )
continue ;
if ( $frameIndex >= $chart [ 'graph' ][ 'width' ] )
continue ;
if ( ! isset ( $currFrameSlots [ $frameIndex ]) ) {
$currFrameSlots [ $frameIndex ] = array ( 'count' => 1 , 'value' => $frame [ 'Score' ], 'event' => $event , 'frame' => $frame );
} else {
$currFrameSlots [ $frameIndex ][ 'count' ] ++ ;
if ( $frame [ 'Score' ] > $currFrameSlots [ $frameIndex ][ 'value' ] ) {
$currFrameSlots [ $frameIndex ][ 'value' ] = $frame [ 'Score' ];
$currFrameSlots [ $frameIndex ][ 'event' ] = $event ;
$currFrameSlots [ $frameIndex ][ 'frame' ] = $frame ;
}
}
if ( $frame [ 'Score' ] > $chart [ 'data' ][ 'y' ][ 'hi' ] ) {
$chart [ 'data' ][ 'y' ][ 'hi' ] = $frame [ 'Score' ];
}
} // end foreach frame
}
} // end if MaxScore > 0
} while ( $event = $events_result -> fetch ( PDO :: FETCH_ASSOC ) );
} # end if have first event
2013-05-02 22:20:06 +08:00
ksort ( $monitorIds , SORT_NUMERIC );
ksort ( $monEventSlots , SORT_NUMERIC );
ksort ( $monFrameSlots , SORT_NUMERIC );
// No longer needed?
2017-05-19 02:04:24 +08:00
if ( false ) {
2017-05-19 03:11:26 +08:00
// Add on missing frames
foreach ( array_keys ( $monFrameSlots ) as $monitorId ) {
unset ( $currFrameSlots );
$currFrameSlots = & $monFrameSlots [ $monitorId ];
for ( $i = 0 ; $i < $chart [ 'graph' ][ 'width' ]; $i ++ ) {
if ( isset ( $currFrameSlots [ $i ]) ) {
if ( ! isset ( $currFrameSlots [ $i ][ 'frame' ]) ) {
$framesSql = " select FrameId,Score from Frames where EventId = ? and Score > 0 order by FrameId limit 1 " ;
$currFrameSlots [ $i ][ 'frame' ] = dbFetchOne ( $framesSql , NULL , array ( $currFrameSlots [ $i ][ 'event' ][ 'Id' ] ) );
2013-05-02 22:20:06 +08:00
}
2017-05-19 03:11:26 +08:00
}
2013-05-02 22:20:06 +08:00
}
2017-05-19 03:11:26 +08:00
}
2013-05-02 22:20:06 +08:00
}
$chart [ 'data' ][ 'y' ][ 'range' ] = ( $chart [ 'data' ][ 'y' ][ 'hi' ] - $chart [ 'data' ][ 'y' ][ 'lo' ]) + 1 ;
$chart [ 'data' ][ 'y' ][ 'density' ] = $chart [ 'data' ][ 'y' ][ 'range' ] / $chart [ 'graph' ][ 'height' ];
$majYScale = getYScale ( $chart [ 'data' ][ 'y' ][ 'range' ], $chart [ 'grid' ][ 'y' ][ 'major' ][ 'min' ], $chart [ 'grid' ][ 'y' ][ 'major' ][ 'max' ] );
$maxWidth = 0 ;
$maxHeight = 0 ;
2017-05-19 02:04:24 +08:00
foreach ( array_keys ( $monitorIds ) as $monitorId ) {
2017-05-19 03:11:26 +08:00
if ( $maxWidth < $monitors [ $monitorId ][ 'Width' ] )
$maxWidth = $monitors [ $monitorId ][ 'Width' ];
if ( $maxHeight < $monitors [ $monitorId ][ 'Height' ] )
$maxHeight = $monitors [ $monitorId ][ 'Height' ];
2013-05-02 22:20:06 +08:00
}
//print_r( $monEventSlots );
// Optimise boxes
2017-05-19 02:04:24 +08:00
foreach ( array_keys ( $monEventSlots ) as $monitorId ) {
2017-05-19 03:11:26 +08:00
unset ( $currEventSlots );
$currEventSlots = & $monEventSlots [ $monitorId ];
for ( $i = 0 ; $i < $chart [ 'graph' ][ 'width' ]; $i ++ ) {
if ( isset ( $currEventSlots [ $i ]) ) {
if ( isset ( $currSlot ) ) {
if ( $currSlot [ 'event' ][ 'Id' ] == $currEventSlots [ $i ][ 'event' ][ 'Id' ] ) {
if ( $currSlot [ 'width' ] < $maxEventWidth ) {
// Merge slots for the same long event
$currSlot [ 'width' ] ++ ;
unset ( $currEventSlots [ $i ] );
continue ;
} elseif ( $currSlot [ 'offset' ] < $currEventSlots [ $i ][ 'offset' ] ) {
// Split very long events
$currEventSlots [ $i ][ 'frame' ] = array ( 'FrameId' => $currEventSlots [ $i ][ 'offset' ] );
}
} elseif ( $currSlot [ 'width' ] < $minEventWidth ) {
// Merge multiple small events
$currSlot [ 'width' ] ++ ;
unset ( $currEventSlots [ $i ] );
continue ;
2013-05-02 22:20:06 +08:00
}
2017-05-19 03:11:26 +08:00
}
$currSlot = & $currEventSlots [ $i ];
} else {
unset ( $currSlot );
2013-05-02 22:20:06 +08:00
}
2017-05-19 03:11:26 +08:00
}
if ( isset ( $currSlot ) )
unset ( $currSlot );
2013-05-02 22:20:06 +08:00
}
//print_r( $monEventSlots );
// Stack events
$frameSlots = array ();
$frameMonitorIds = array_keys ( $monFrameSlots );
2017-05-19 02:04:24 +08:00
for ( $i = 0 ; $i < $chart [ 'graph' ][ 'width' ]; $i ++ ) {
2017-05-19 03:11:26 +08:00
foreach ( $frameMonitorIds as $frameMonitorId ) {
unset ( $currFrameSlots );
$currFrameSlots = & $monFrameSlots [ $frameMonitorId ];
if ( isset ( $currFrameSlots [ $i ]) ) {
if ( ! isset ( $frameSlots [ $i ]) ) {
$frameSlots [ $i ] = array ();
$frameSlots [ $i ][] = & $currFrameSlots [ $i ];
} else {
$slotCount = count ( $frameSlots [ $i ]);
for ( $j = 0 ; $j < $slotCount ; $j ++ ) {
if ( $currFrameSlots [ $i ][ 'value' ] > $frameSlots [ $i ][ $j ][ 'value' ] ) {
for ( $k = $slotCount ; $k > $j ; $k -- ) {
$frameSlots [ $i ][ $k ] = $frameSlots [ $i ][ $k - 1 ];
2013-05-02 22:20:06 +08:00
}
2017-05-19 03:11:26 +08:00
$frameSlots [ $i ][ $j ] = & $currFrameSlots [ $i ];
break 2 ;
}
2013-05-02 22:20:06 +08:00
}
2017-05-19 03:11:26 +08:00
$frameSlots [ $i ][] = & $currFrameSlots [ $i ];
}
2013-05-02 22:20:06 +08:00
}
2017-05-19 23:00:37 +08:00
} # end foreach MonitorId
2013-05-02 22:20:06 +08:00
}
//print_r( $monEventSlots );
//print_r( $monFrameSlots );
//print_r( $chart );
$graphHeight = $chart [ 'graph' ][ 'height' ];
2017-05-19 23:00:37 +08:00
if ( $mode == 'overlay' ) {
2017-05-19 03:11:26 +08:00
$minEventBarHeight = 10 ;
$maxEventBarHeight = 40 ;
2013-05-02 22:20:06 +08:00
2017-05-19 03:11:26 +08:00
if ( count ( $monitorIds ) ) {
$chart [ 'graph' ][ 'eventBarHeight' ] = $minEventBarHeight ;
while ( ( $chart [ 'graph' ][ 'eventsHeight' ] = (( $chart [ 'graph' ][ 'eventBarHeight' ] * count ( $monitorIds )) + ( count ( $monitorIds ) - 1 ))) < $maxEventBarHeight ) {
$chart [ 'graph' ][ 'eventBarHeight' ] ++ ;
2013-05-02 22:20:06 +08:00
}
2017-05-19 03:11:26 +08:00
} else {
$chart [ 'graph' ][ 'eventBarHeight' ] = $maxEventBarHeight ;
$chart [ 'graph' ][ 'eventsHeight' ] = $maxEventBarHeight ;
}
$chart [ 'graph' ][ 'activityHeight' ] = ( $graphHeight - $chart [ 'graph' ][ 'eventsHeight' ]);
$chart [ 'data' ][ 'y' ][ 'density' ] = $chart [ 'data' ][ 'y' ][ 'range' ] / $chart [ 'graph' ][ 'activityHeight' ];
$chart [ 'eventBars' ] = array ();
$top = $chart [ 'graph' ][ 'activityHeight' ];
foreach ( array_keys ( $monitorIds ) as $monitorId ) {
$chart [ 'eventBars' ][ $monitorId ] = array ( 'top' => $top );
$top += $chart [ 'graph' ][ 'eventBarHeight' ] + 1 ;
}
2017-05-19 23:00:37 +08:00
} else if ( $mode == 'split' ) {
2017-05-19 03:11:26 +08:00
$minActivityBarHeight = 30 ;
$minEventBarHeight = 10 ;
$maxEventBarHeight = 40 ;
if ( count ( $monitorIds ) ) {
$chart [ 'graph' ][ 'eventBarHeight' ] = $minEventBarHeight ;
$chart [ 'graph' ][ 'activityBarHeight' ] = $minActivityBarHeight ;
while ( ((( $chart [ 'graph' ][ 'eventBarHeight' ] + $chart [ 'graph' ][ 'activityBarHeight' ]) * count ( $monitorIds )) + (( 2 * count ( $monitorIds )) - 1 )) < $graphHeight ) {
$chart [ 'graph' ][ 'activityBarHeight' ] ++ ;
if ( $chart [ 'graph' ][ 'eventBarHeight' ] < $maxEventBarHeight ) {
$chart [ 'graph' ][ 'eventBarHeight' ] ++ ;
}
2013-05-02 22:20:06 +08:00
}
2017-05-19 03:11:26 +08:00
} else {
$chart [ 'graph' ][ 'eventBarHeight' ] = $maxEventBarHeight ;
$chart [ 'graph' ][ 'activityBarHeight' ] = $graphHeight - $chart [ 'graph' ][ 'eventBarHeight' ];
}
$chart [ 'data' ][ 'y' ][ 'density' ] = $chart [ 'data' ][ 'y' ][ 'range' ] / $chart [ 'graph' ][ 'activityBarHeight' ];
2013-05-02 22:20:06 +08:00
2017-05-19 23:00:37 +08:00
$chart [ 'activityBars' ] = array ();
2017-05-19 03:11:26 +08:00
$chart [ 'eventBars' ] = array ();
$top = 0 ;
$barCount = 1 ;
2017-05-19 23:00:37 +08:00
foreach ( array_keys ( $monitorIds ) as $monitorId ) {
2017-05-19 03:11:26 +08:00
$chart [ 'eventBars' ][ $monitorId ] = array ( 'top' => $top );
$chart [ 'eventBars' ][ $monitorId ] = array ( 'top' => $top + $chart [ 'graph' ][ 'activityBarHeight' ] + 1 );
$top += $chart [ 'graph' ][ 'activityBarHeight' ] + 1 + $chart [ 'graph' ][ 'eventBarHeight' ] + 1 ;
}
2013-05-02 22:20:06 +08:00
}
preg_match ( '/^(\d+)-(\d+)-(\d+) (\d+):(\d+)/' , $minTime , $startMatches );
preg_match ( '/^(\d+)-(\d+)-(\d+) (\d+):(\d+)/' , $maxTime , $endMatches );
2017-05-19 02:04:24 +08:00
if ( $startMatches [ 1 ] != $endMatches [ 1 ] ) {
2017-05-19 23:00:37 +08:00
// Different years
$title = strftime ( STRF_TL_AXIS_RANGE_YEAR1 , $chart [ 'data' ][ 'x' ][ 'lo' ] ) . " - " . strftime ( STRF_TL_AXIS_RANGE_YEAR2 , $chart [ 'data' ][ 'x' ][ 'hi' ] );
2017-05-19 02:04:24 +08:00
} elseif ( $startMatches [ 2 ] != $endMatches [ 2 ] ) {
2017-05-19 23:00:37 +08:00
// Different months
$title = strftime ( STRF_TL_AXIS_RANGE_MONTH1 , $chart [ 'data' ][ 'x' ][ 'lo' ] ) . " - " . strftime ( STRF_TL_AXIS_RANGE_MONTH2 , $chart [ 'data' ][ 'x' ][ 'hi' ] );
2017-05-19 02:04:24 +08:00
} elseif ( $startMatches [ 3 ] != $endMatches [ 3 ] ) {
2017-05-19 23:00:37 +08:00
// Different dates
$title = strftime ( STRF_TL_AXIS_RANGE_DAY1 , $chart [ 'data' ][ 'x' ][ 'lo' ] ) . " - " . strftime ( STRF_TL_AXIS_RANGE_DAY2 , $chart [ 'data' ][ 'x' ][ 'hi' ] );
2017-05-19 02:04:24 +08:00
} else {
2017-05-19 23:00:37 +08:00
// Different times
$title = strftime ( STRF_TL_AXIS_RANGE_TIME1 , $chart [ 'data' ][ 'x' ][ 'lo' ] ) . " - " . strftime ( STRF_TL_AXIS_RANGE_TIME2 , $chart [ 'data' ][ 'x' ][ 'hi' ] );
2013-05-02 22:20:06 +08:00
}
2017-05-19 02:04:24 +08:00
function drawXGrid ( $chart , $scale , $labelClass , $tickClass , $gridClass , $zoomClass = false ) {
2017-05-19 23:00:37 +08:00
$html = '' ;
ob_start ();
$labelCount = 0 ;
$lastTick = 0 ;
unset ( $lastLabel );
$labelCheck = isset ( $scale [ 'labelCheck' ]) ? $scale [ 'labelCheck' ] : $scale [ 'label' ];
2013-05-02 22:20:06 +08:00
?>
< div id = " xScale " >
< ? php
2017-05-19 23:00:37 +08:00
for ( $i = 0 ; $i < $chart [ 'graph' ][ 'width' ]; $i ++ ) {
$x = $i - 1 ;
$timeOffset = ( int )( $chart [ 'data' ][ 'x' ][ 'lo' ] + ( $i * $chart [ 'data' ][ 'x' ][ 'density' ]));
if ( $scale [ 'align' ] > 1 ) {
$label = ( int )( strftime ( $labelCheck , $timeOffset ) / $scale [ 'align' ]);
} else {
$label = strftime ( $labelCheck , $timeOffset );
}
if ( ! isset ( $lastLabel ) || ( $lastLabel != $label ) ) {
$labelCount ++ ;
}
if ( $labelCount >= $scale [ 'divisor' ] ) {
$labelCount = 0 ;
if ( isset ( $lastLabel ) ) {
if ( $labelClass ) {
2013-05-02 22:20:06 +08:00
?>
2014-12-05 07:44:23 +08:00
< div class = " <?php echo $labelClass ?> " style = " left: <?php echo $x -25 ?>px; " >< ? php echo strftime ( $scale [ 'label' ], $timeOffset ); ?> </div>
2013-05-02 22:20:06 +08:00
< ? php
2017-05-19 23:00:37 +08:00
}
if ( $tickClass ) {
2013-05-02 22:20:06 +08:00
?>
2014-12-05 07:44:23 +08:00
< div class = " <?php echo $tickClass ?> " style = " left: <?php echo $x ?>px; " ></ div >
2013-05-02 22:20:06 +08:00
< ? php
2017-05-19 23:00:37 +08:00
}
if ( $gridClass ) {
2013-05-02 22:20:06 +08:00
?>
2014-12-05 07:44:23 +08:00
< div class = " <?php echo $gridClass ?> " style = " left: <?php echo $x ?>px; " ></ div >
2013-05-02 22:20:06 +08:00
< ? php
2017-05-19 23:00:37 +08:00
}
if ( $scale [ 'name' ] != 'second' && $zoomClass ) {
$zoomMinTime = strftime ( STRF_FMT_DATETIME_DB , ( int )( $chart [ 'data' ][ 'x' ][ 'lo' ] + ( $lastTick * $chart [ 'data' ][ 'x' ][ 'density' ])) );
$zoomMaxTime = strftime ( STRF_FMT_DATETIME_DB , ( int )( $chart [ 'data' ][ 'x' ][ 'lo' ] + ( $i * $chart [ 'data' ][ 'x' ][ 'density' ])) );
2013-05-02 22:20:06 +08:00
?>
2015-05-10 21:10:30 +08:00
< div class = " <?php echo $zoomClass ?> " style = " left: <?php echo $lastTick -1 ?>px; width: <?php echo $i - $lastTick ?>px; " title = " <?php echo translate('ZoomIn') ?> " onclick = " tlZoomBounds( '<?php echo $zoomMinTime ?>', '<?php echo $zoomMaxTime ?>' ) " ></ div >
2013-05-02 22:20:06 +08:00
< ? php
}
2017-05-19 23:00:37 +08:00
$lastTick = $i ;
} # end if $lastLabel
2013-05-02 22:20:06 +08:00
}
2017-05-19 23:00:37 +08:00
$lastLabel = $label ;
} # end foreach width segment
if ( $zoomClass ) {
$zoomMinTime = strftime ( STRF_FMT_DATETIME_DB , ( int )( $chart [ 'data' ][ 'x' ][ 'lo' ] + ( $lastTick * $chart [ 'data' ][ 'x' ][ 'density' ])) );
$zoomMaxTime = strftime ( STRF_FMT_DATETIME_DB , ( int )( $chart [ 'data' ][ 'x' ][ 'lo' ] + ( $i * $chart [ 'data' ][ 'x' ][ 'density' ])) );
2013-05-02 22:20:06 +08:00
?>
2015-05-10 21:10:30 +08:00
< div class = " <?php echo $zoomClass ?> " style = " left: <?php echo $lastTick -1 ?>px; width: <?php echo $i - $lastTick ?>px; " title = " <?php echo translate('ZoomIn') ?> " onclick = " tlZoomBounds( '<?php echo $zoomMinTime ?>', '<?php echo $zoomMaxTime ?>' ) " ></ div >
2013-05-02 22:20:06 +08:00
< ? php
2017-05-19 23:00:37 +08:00
}
2013-05-02 22:20:06 +08:00
?>
</ div >
< ? php
2017-05-19 23:00:37 +08:00
return ( ob_get_clean () );
} # end function drawXGrid
2013-05-02 22:20:06 +08:00
2017-05-19 02:04:24 +08:00
function drawYGrid ( $chart , $scale , $labelClass , $tickClass , $gridClass ) {
2017-05-19 23:00:37 +08:00
ob_start ();
2013-05-02 22:20:06 +08:00
?>
2017-05-19 23:00:37 +08:00
< div id = " yScale " >
2013-05-02 22:20:06 +08:00
< ? php
2017-05-19 23:00:37 +08:00
for ( $i = 0 ; $i < $scale [ 'lines' ]; $i ++ ) {
$label = ( int )( $i * $scale [ 'divisor' ]);
$y = $chart [ 'graph' ][ 'eventsHeight' ] + ( int )(( $i * $scale [ 'divisor' ]) / $chart [ 'data' ][ 'y' ][ 'density' ]) - 1 ;
if ( $labelClass ) {
2013-05-02 22:20:06 +08:00
?>
2017-05-19 23:00:37 +08:00
< div class = " <?php echo $labelClass ?> " style = " top: <?php echo $chart['graph'] ['height']-( $y +8) ?>px; " >< ? php echo $label ?> </div>
2013-05-02 22:20:06 +08:00
< ? php
2017-05-19 23:00:37 +08:00
}
if ( $tickClass ) {
2013-05-02 22:20:06 +08:00
?>
2017-05-19 23:00:37 +08:00
< div class = " <?php echo $tickClass ?> " style = " top: <?php echo $chart['graph'] ['height']-( $y +2) ?>px; " ></ div >
2013-05-02 22:20:06 +08:00
< ? php
2017-05-19 23:00:37 +08:00
}
if ( $gridClass ) {
2013-05-02 22:20:06 +08:00
?>
2017-05-19 23:00:37 +08:00
< div class = " <?php echo $gridClass ?> " style = " top: <?php echo $chart['graph'] ['height']-( $y +2) ?>px;<?php echo $i <= 0?' border-top: solid 1px black;':'' ?> " ></ div >
2013-05-02 22:20:06 +08:00
< ? php
}
2017-05-19 23:00:37 +08:00
} # end foreach line segment
2013-05-02 22:20:06 +08:00
?>
2017-05-19 23:00:37 +08:00
</ div >
2013-05-02 22:20:06 +08:00
< ? php
2017-05-19 23:00:37 +08:00
return ( ob_get_clean () );
} # end function drawYGrid
2013-05-02 22:20:06 +08:00
2017-05-19 02:04:24 +08:00
function getSlotPreviewEventBehaviour ( $slot ) {
return ( " previewEvent( ' " . $slot [ 'event' ][ 'Id' ] . " ', ' " . getSlotFrame ( $slot ) . " ' ) " );
2013-05-02 22:20:06 +08:00
}
2017-05-19 02:04:24 +08:00
function getSlotShowEventBehaviour ( $slot ) {
global $monitors ;
2013-05-02 22:20:06 +08:00
2017-05-19 02:04:24 +08:00
$monitor = & $monitors [ $slot [ 'event' ][ 'MonitorId' ]];
2013-05-02 22:20:06 +08:00
2017-05-19 02:04:24 +08:00
return ( " showEvent( ' " . $slot [ 'event' ][ 'Id' ] . " ', ' " . getSlotFrame ( $slot ) . " ', ' " . reScale ( $monitor [ 'Width' ], $monitor [ 'DefaultScale' ], ZM_WEB_DEFAULT_SCALE ) . " ', ' " . reScale ( $monitor [ 'Height' ], $monitor [ 'DefaultScale' ], ZM_WEB_DEFAULT_SCALE ) . " ' ) " );
2013-05-02 22:20:06 +08:00
}
$focusWindow = true ;
2015-05-10 21:10:30 +08:00
xhtmlHeaders ( __FILE__ , translate ( 'Timeline' ) );
2013-05-02 22:20:06 +08:00
?>
< body >
< div id = " page " >
< div id = " header " >
< div id = " headerButtons " >
2015-05-10 21:10:30 +08:00
< ? php echo makePopupLink ( '?view=events&page=1' . htmlspecialchars ( $filterQuery ), 'zmEvents' , 'events' , translate ( 'List' ), canView ( 'Events' ) ) ?>
< a href = " # " onclick = " closeWindow(); " >< ? php echo translate ( 'Close' ) ?> </a>
2013-05-02 22:20:06 +08:00
</ div >
2015-05-10 21:10:30 +08:00
< h2 >< ? php echo translate ( 'Timeline' ) ?> </h2>
2013-05-02 22:20:06 +08:00
</ div >
< div id = " content " class = " chartSize " >
< div id = " topPanel " class = " graphWidth " >
< div id = " imagePanel " >
Feature h264 videostorage (#1882)
* Moved writing of configure options from Controller to Model. Fixes #191.
* Initial commit for saving events as videos :)
* Add zm_video.cpp to autotools
* Add zm_video.h to autotools
* Search for MP4V2 header file 3 times: mp4v2/mp4v2.h, mp4v2.h, mp4.h
* Fix serve memory leak
* Few minor code improvements
* Added the ability to override preset, tune, profile and few other improvements
* Correctly write SPS & PPS from x264 encoder headers
* Remove unnessecary SPS & PPS writing code
* Imported missing files from master to feature-h264-videostorage
* Audio support including fixes for dts/pts, split on keyframe and update to mkv extension to prevent ffmpeg problems writing rtsp audio to mp4 containter (header problem)
* Updates to make gcc happy
* Add html5 video control to timeline and event to support mkv playback
* Add zm_videostore.cpp to CMakeLists.txt
* Remove Modern Branch for now
* Fix minor bug
* Option handled added in master, removing duplicate declaration
* Add CaptureandRecord from zm_camera.h
* Putting placeholder in for CaptureAndRecord function
* Removed duplicate code and brackets
* add digest auth file for cmake
Conflicts:
src/CMakeLists.txt
* Add web dir back into Makefile.am
Revert "Removed web from SUBDIRS in Makefile.am"
This reverts commit d9bbcdf3a94cba4d8955fcd03bd965ed2772f34d.
* Add CaptureAndRecord to vlc, still need to make it record
* Resolve SegFault on videostore
* Swap to mp4 container
* mp4 changes
* spaces to tabs, hide video stuff if video writer is turned off
* Make timeline open event.mp4 instead of mkv
* Missed mkv in timeline.js
* Fix some issues from the merge conflict
* Resolve post merge build issues with braces
* Fix whitespace
* Update Jpeg and Video options for passthrough options
* Whitespace fix zm_camera.h
* Fix array mkssing comma
* Add support for Jpeg save options for h264 branch snapshot. Might remove altogether if snapshots not needed
* Update VideoStoreData memory size comment
* Change from config.use_mkv_storage to per monitor option VideoWriter from video branch
* Fix bracket issues post merge
* Clean up comments and add av_free_packet
* Convert from event_directory to event file as per Video branch
* Testing videojs for video playback
* Fixed a missing bracket post merge and also SQL_values now used for EventID and Monitors
* bring recent improvements in ffmpeg capture function into captureandrecord
* Remove pict from writeAudioFramePacket as not used
* Add translate options for h264 Storage options in Monitor and update en_gb file
* Cherry-Pick from iconnor - make it compile on ubuntu 15.04. Which is libav 56.1.0
Conflicts:
src/zm_ffmpeg.cpp
src/zm_remote_camera_rtsp.cpp
Conflicts:
distros/ubuntu1204/changelog
* Clean up videostore code and remove lots of unused code
* proof of concept for dynamic/automatic video rotation using video-js plugin zoomrotate
Conflicts:
web/skins/classic/views/event.php
* removed redundant field in sql query
Conflicts:
web/skins/classic/views/event.php
* local storage of video js plugin
* Beautify!
Make the code somewhat readable.
* added missing videojs.zoomrotate.js file
added missing videojs.zoomrotate.js file
* Typo
added missing "
* Added missing brackets
* fix to display thumbnails when only storing snapshot.jpg
* added control for video playback rate
Conflicts:
web/skins/classic/views/event.php
* dynamically create jpegs from video file for viewing in browser
* fix timeline view for SaveJPEGs monitors (without enabled VideoWriter)
* only expose monitor info which are being used in client
* fix segmentation fault in zma with ubuntu 14.04 and ffmpeg 2.5.8 (gcc 4.8)
when libx264 is not installed
* better way of detecting showing image or video in timeline and event view
instead of Monitor.VideoWriter, Event.DefaultVideo is used, so even if
VideoWriter/SaveJPEG option is changed, a valid image or video will always be
displayed for historical events in both timeline and event view
this also fixes loading videos in timeline view
* Fixes problem of crashing zmc when bad packet arrives causing av_interleaved_write_frame() to return non-zero (-22). Prefilters common packet issues. Add metadata title to generated video file
* Remove syslog.h
* fixed SaveJPEGs are not working
which is caused in errors introduced when merging with master
* Update README.md
* Fix build warnings specific to h264 branch, unused FrameImg, unused ret and int64_t snprintf issues
* Fix PRId64 issue in travis, builds locally fine, but I can see a gcc version issue here
* Fix PRId64 issue in travis, another try
* Try "STDC_FORMAT_MACROS" to see if that helps Travis on gcc 4.6.3
* Revert space removal around PRId64
* video branch ffmpeg 2.9 fixes
ffmpeg 2.9 patched removed SSE2 CPU
* Add FFMPEGInit back
* use webvvt to overlay timestamp (honoring Monitor.LabelFormat) to videos in timeline and event
also fixed bug which prevented seeking in timeline video preview
* ffmpeg 3.0 API build failure fixes
* Update README.md
* merge all the commits from the messed up iconnor_video branch
* fix whitespace
* revert
* whitespace fixes
* spelling fix
* put back some text
* add these back
* fix spelling mistake
* Steal some packet dumping routines from ffmpeg. Convert them to use our logging routines
* add a test and error message if the codec is not h264
* these have been removed in master
* add a view to check auth and just send the video
* add some comments, and dump filename and AVFormatContext on failure to write header
* add the toggle for RecordAudio so that the checkbox works to turn off Audio
* Must init videoStore in constuctor
* more debug and comments, return checking
* Fix dropped part of sql query.
* fix extra else and some whitespace
* Fix missing } from merge that was preventing building.
* fix tabs
* get rid of use of separator, just use \n
* Restore lost fixes for deprecation
* Why are these failing
* Respect record_audio flag when setting up video file so dont try and initiliase mp4 with unsupported audio
* Forgot that I was trying to solve case of stream is true and record_audio
is false.
* Pass swscale_ctx back in to getCachedContext or it will create new
context every frame and leak memory like a mofo.
* Add libx264-dev and libmp4v2-dev to build requires to save hassle of
ensuring they are installed before build.
* Merge my Rotation/Orientation work and fixes for bad h264 streams
* need arpa/inet for reverse lookups
* pull in the new byte range code for viewing videos
* Move our recording flag deeper into closeevent
* add braces and only call closeEvent if there is an event
* deprecate the z_frame_rate stuff which is deprecated in ffmpeg
* remark out some debugging
* fix for video on stream 1
* fix audio_stream to audio_st
* Ignore bad decodes
* fix problems with content-length causing viewing to not work in chrome/android
* change logic of sending file contents to handle an off by one and be more readable
* Some fixes pointed out by Maxim Romanov. Also simply the loading of events to not join the Monitors table
* fix to sql for timeline
* added RecordAudio to sql in README
* Use sub queries instead of joins to fix errors when using new mysql defaults.
* fix sql queries
* Dockerfile to build feature-h264-videostorage
* Must cast codec
* add php-acpu as a dependency
* require php5-acpu
* fix typo
* remove extra /
* Add a line for out-of-tree builds to do api/lib/Cake/bootstrap.php
* delete merge conflict files
* delete merge conflict files
2017-05-16 10:02:48 +08:00
< div id = " image " class = " imageHeight " >
< img id = " imageSrc " class = " imageWidth " src = " graphics/transparent.gif " alt = " <?php echo translate('ViewEvent') ?> " title = " <?php echo translate('ViewEvent') ?> " />
< ? php
2017-07-14 21:25:53 +08:00
if ( 0 ) {
Feature h264 videostorage (#1882)
* Moved writing of configure options from Controller to Model. Fixes #191.
* Initial commit for saving events as videos :)
* Add zm_video.cpp to autotools
* Add zm_video.h to autotools
* Search for MP4V2 header file 3 times: mp4v2/mp4v2.h, mp4v2.h, mp4.h
* Fix serve memory leak
* Few minor code improvements
* Added the ability to override preset, tune, profile and few other improvements
* Correctly write SPS & PPS from x264 encoder headers
* Remove unnessecary SPS & PPS writing code
* Imported missing files from master to feature-h264-videostorage
* Audio support including fixes for dts/pts, split on keyframe and update to mkv extension to prevent ffmpeg problems writing rtsp audio to mp4 containter (header problem)
* Updates to make gcc happy
* Add html5 video control to timeline and event to support mkv playback
* Add zm_videostore.cpp to CMakeLists.txt
* Remove Modern Branch for now
* Fix minor bug
* Option handled added in master, removing duplicate declaration
* Add CaptureandRecord from zm_camera.h
* Putting placeholder in for CaptureAndRecord function
* Removed duplicate code and brackets
* add digest auth file for cmake
Conflicts:
src/CMakeLists.txt
* Add web dir back into Makefile.am
Revert "Removed web from SUBDIRS in Makefile.am"
This reverts commit d9bbcdf3a94cba4d8955fcd03bd965ed2772f34d.
* Add CaptureAndRecord to vlc, still need to make it record
* Resolve SegFault on videostore
* Swap to mp4 container
* mp4 changes
* spaces to tabs, hide video stuff if video writer is turned off
* Make timeline open event.mp4 instead of mkv
* Missed mkv in timeline.js
* Fix some issues from the merge conflict
* Resolve post merge build issues with braces
* Fix whitespace
* Update Jpeg and Video options for passthrough options
* Whitespace fix zm_camera.h
* Fix array mkssing comma
* Add support for Jpeg save options for h264 branch snapshot. Might remove altogether if snapshots not needed
* Update VideoStoreData memory size comment
* Change from config.use_mkv_storage to per monitor option VideoWriter from video branch
* Fix bracket issues post merge
* Clean up comments and add av_free_packet
* Convert from event_directory to event file as per Video branch
* Testing videojs for video playback
* Fixed a missing bracket post merge and also SQL_values now used for EventID and Monitors
* bring recent improvements in ffmpeg capture function into captureandrecord
* Remove pict from writeAudioFramePacket as not used
* Add translate options for h264 Storage options in Monitor and update en_gb file
* Cherry-Pick from iconnor - make it compile on ubuntu 15.04. Which is libav 56.1.0
Conflicts:
src/zm_ffmpeg.cpp
src/zm_remote_camera_rtsp.cpp
Conflicts:
distros/ubuntu1204/changelog
* Clean up videostore code and remove lots of unused code
* proof of concept for dynamic/automatic video rotation using video-js plugin zoomrotate
Conflicts:
web/skins/classic/views/event.php
* removed redundant field in sql query
Conflicts:
web/skins/classic/views/event.php
* local storage of video js plugin
* Beautify!
Make the code somewhat readable.
* added missing videojs.zoomrotate.js file
added missing videojs.zoomrotate.js file
* Typo
added missing "
* Added missing brackets
* fix to display thumbnails when only storing snapshot.jpg
* added control for video playback rate
Conflicts:
web/skins/classic/views/event.php
* dynamically create jpegs from video file for viewing in browser
* fix timeline view for SaveJPEGs monitors (without enabled VideoWriter)
* only expose monitor info which are being used in client
* fix segmentation fault in zma with ubuntu 14.04 and ffmpeg 2.5.8 (gcc 4.8)
when libx264 is not installed
* better way of detecting showing image or video in timeline and event view
instead of Monitor.VideoWriter, Event.DefaultVideo is used, so even if
VideoWriter/SaveJPEG option is changed, a valid image or video will always be
displayed for historical events in both timeline and event view
this also fixes loading videos in timeline view
* Fixes problem of crashing zmc when bad packet arrives causing av_interleaved_write_frame() to return non-zero (-22). Prefilters common packet issues. Add metadata title to generated video file
* Remove syslog.h
* fixed SaveJPEGs are not working
which is caused in errors introduced when merging with master
* Update README.md
* Fix build warnings specific to h264 branch, unused FrameImg, unused ret and int64_t snprintf issues
* Fix PRId64 issue in travis, builds locally fine, but I can see a gcc version issue here
* Fix PRId64 issue in travis, another try
* Try "STDC_FORMAT_MACROS" to see if that helps Travis on gcc 4.6.3
* Revert space removal around PRId64
* video branch ffmpeg 2.9 fixes
ffmpeg 2.9 patched removed SSE2 CPU
* Add FFMPEGInit back
* use webvvt to overlay timestamp (honoring Monitor.LabelFormat) to videos in timeline and event
also fixed bug which prevented seeking in timeline video preview
* ffmpeg 3.0 API build failure fixes
* Update README.md
* merge all the commits from the messed up iconnor_video branch
* fix whitespace
* revert
* whitespace fixes
* spelling fix
* put back some text
* add these back
* fix spelling mistake
* Steal some packet dumping routines from ffmpeg. Convert them to use our logging routines
* add a test and error message if the codec is not h264
* these have been removed in master
* add a view to check auth and just send the video
* add some comments, and dump filename and AVFormatContext on failure to write header
* add the toggle for RecordAudio so that the checkbox works to turn off Audio
* Must init videoStore in constuctor
* more debug and comments, return checking
* Fix dropped part of sql query.
* fix extra else and some whitespace
* Fix missing } from merge that was preventing building.
* fix tabs
* get rid of use of separator, just use \n
* Restore lost fixes for deprecation
* Why are these failing
* Respect record_audio flag when setting up video file so dont try and initiliase mp4 with unsupported audio
* Forgot that I was trying to solve case of stream is true and record_audio
is false.
* Pass swscale_ctx back in to getCachedContext or it will create new
context every frame and leak memory like a mofo.
* Add libx264-dev and libmp4v2-dev to build requires to save hassle of
ensuring they are installed before build.
* Merge my Rotation/Orientation work and fixes for bad h264 streams
* need arpa/inet for reverse lookups
* pull in the new byte range code for viewing videos
* Move our recording flag deeper into closeevent
* add braces and only call closeEvent if there is an event
* deprecate the z_frame_rate stuff which is deprecated in ffmpeg
* remark out some debugging
* fix for video on stream 1
* fix audio_stream to audio_st
* Ignore bad decodes
* fix problems with content-length causing viewing to not work in chrome/android
* change logic of sending file contents to handle an off by one and be more readable
* Some fixes pointed out by Maxim Romanov. Also simply the loading of events to not join the Monitors table
* fix to sql for timeline
* added RecordAudio to sql in README
* Use sub queries instead of joins to fix errors when using new mysql defaults.
* fix sql queries
* Dockerfile to build feature-h264-videostorage
* Must cast codec
* add php-acpu as a dependency
* require php5-acpu
* fix typo
* remove extra /
* Add a line for out-of-tree builds to do api/lib/Cake/bootstrap.php
* delete merge conflict files
* delete merge conflict files
2017-05-16 10:02:48 +08:00
//due to chrome bug, has to enable https://code.google.com/p/chromium/issues/detail?id=472300
//crossorigin has to be added below to make caption work in chrome
?>
2017-05-19 03:11:26 +08:00
<!--
Feature h264 videostorage (#1882)
* Moved writing of configure options from Controller to Model. Fixes #191.
* Initial commit for saving events as videos :)
* Add zm_video.cpp to autotools
* Add zm_video.h to autotools
* Search for MP4V2 header file 3 times: mp4v2/mp4v2.h, mp4v2.h, mp4.h
* Fix serve memory leak
* Few minor code improvements
* Added the ability to override preset, tune, profile and few other improvements
* Correctly write SPS & PPS from x264 encoder headers
* Remove unnessecary SPS & PPS writing code
* Imported missing files from master to feature-h264-videostorage
* Audio support including fixes for dts/pts, split on keyframe and update to mkv extension to prevent ffmpeg problems writing rtsp audio to mp4 containter (header problem)
* Updates to make gcc happy
* Add html5 video control to timeline and event to support mkv playback
* Add zm_videostore.cpp to CMakeLists.txt
* Remove Modern Branch for now
* Fix minor bug
* Option handled added in master, removing duplicate declaration
* Add CaptureandRecord from zm_camera.h
* Putting placeholder in for CaptureAndRecord function
* Removed duplicate code and brackets
* add digest auth file for cmake
Conflicts:
src/CMakeLists.txt
* Add web dir back into Makefile.am
Revert "Removed web from SUBDIRS in Makefile.am"
This reverts commit d9bbcdf3a94cba4d8955fcd03bd965ed2772f34d.
* Add CaptureAndRecord to vlc, still need to make it record
* Resolve SegFault on videostore
* Swap to mp4 container
* mp4 changes
* spaces to tabs, hide video stuff if video writer is turned off
* Make timeline open event.mp4 instead of mkv
* Missed mkv in timeline.js
* Fix some issues from the merge conflict
* Resolve post merge build issues with braces
* Fix whitespace
* Update Jpeg and Video options for passthrough options
* Whitespace fix zm_camera.h
* Fix array mkssing comma
* Add support for Jpeg save options for h264 branch snapshot. Might remove altogether if snapshots not needed
* Update VideoStoreData memory size comment
* Change from config.use_mkv_storage to per monitor option VideoWriter from video branch
* Fix bracket issues post merge
* Clean up comments and add av_free_packet
* Convert from event_directory to event file as per Video branch
* Testing videojs for video playback
* Fixed a missing bracket post merge and also SQL_values now used for EventID and Monitors
* bring recent improvements in ffmpeg capture function into captureandrecord
* Remove pict from writeAudioFramePacket as not used
* Add translate options for h264 Storage options in Monitor and update en_gb file
* Cherry-Pick from iconnor - make it compile on ubuntu 15.04. Which is libav 56.1.0
Conflicts:
src/zm_ffmpeg.cpp
src/zm_remote_camera_rtsp.cpp
Conflicts:
distros/ubuntu1204/changelog
* Clean up videostore code and remove lots of unused code
* proof of concept for dynamic/automatic video rotation using video-js plugin zoomrotate
Conflicts:
web/skins/classic/views/event.php
* removed redundant field in sql query
Conflicts:
web/skins/classic/views/event.php
* local storage of video js plugin
* Beautify!
Make the code somewhat readable.
* added missing videojs.zoomrotate.js file
added missing videojs.zoomrotate.js file
* Typo
added missing "
* Added missing brackets
* fix to display thumbnails when only storing snapshot.jpg
* added control for video playback rate
Conflicts:
web/skins/classic/views/event.php
* dynamically create jpegs from video file for viewing in browser
* fix timeline view for SaveJPEGs monitors (without enabled VideoWriter)
* only expose monitor info which are being used in client
* fix segmentation fault in zma with ubuntu 14.04 and ffmpeg 2.5.8 (gcc 4.8)
when libx264 is not installed
* better way of detecting showing image or video in timeline and event view
instead of Monitor.VideoWriter, Event.DefaultVideo is used, so even if
VideoWriter/SaveJPEG option is changed, a valid image or video will always be
displayed for historical events in both timeline and event view
this also fixes loading videos in timeline view
* Fixes problem of crashing zmc when bad packet arrives causing av_interleaved_write_frame() to return non-zero (-22). Prefilters common packet issues. Add metadata title to generated video file
* Remove syslog.h
* fixed SaveJPEGs are not working
which is caused in errors introduced when merging with master
* Update README.md
* Fix build warnings specific to h264 branch, unused FrameImg, unused ret and int64_t snprintf issues
* Fix PRId64 issue in travis, builds locally fine, but I can see a gcc version issue here
* Fix PRId64 issue in travis, another try
* Try "STDC_FORMAT_MACROS" to see if that helps Travis on gcc 4.6.3
* Revert space removal around PRId64
* video branch ffmpeg 2.9 fixes
ffmpeg 2.9 patched removed SSE2 CPU
* Add FFMPEGInit back
* use webvvt to overlay timestamp (honoring Monitor.LabelFormat) to videos in timeline and event
also fixed bug which prevented seeking in timeline video preview
* ffmpeg 3.0 API build failure fixes
* Update README.md
* merge all the commits from the messed up iconnor_video branch
* fix whitespace
* revert
* whitespace fixes
* spelling fix
* put back some text
* add these back
* fix spelling mistake
* Steal some packet dumping routines from ffmpeg. Convert them to use our logging routines
* add a test and error message if the codec is not h264
* these have been removed in master
* add a view to check auth and just send the video
* add some comments, and dump filename and AVFormatContext on failure to write header
* add the toggle for RecordAudio so that the checkbox works to turn off Audio
* Must init videoStore in constuctor
* more debug and comments, return checking
* Fix dropped part of sql query.
* fix extra else and some whitespace
* Fix missing } from merge that was preventing building.
* fix tabs
* get rid of use of separator, just use \n
* Restore lost fixes for deprecation
* Why are these failing
* Respect record_audio flag when setting up video file so dont try and initiliase mp4 with unsupported audio
* Forgot that I was trying to solve case of stream is true and record_audio
is false.
* Pass swscale_ctx back in to getCachedContext or it will create new
context every frame and leak memory like a mofo.
* Add libx264-dev and libmp4v2-dev to build requires to save hassle of
ensuring they are installed before build.
* Merge my Rotation/Orientation work and fixes for bad h264 streams
* need arpa/inet for reverse lookups
* pull in the new byte range code for viewing videos
* Move our recording flag deeper into closeevent
* add braces and only call closeEvent if there is an event
* deprecate the z_frame_rate stuff which is deprecated in ffmpeg
* remark out some debugging
* fix for video on stream 1
* fix audio_stream to audio_st
* Ignore bad decodes
* fix problems with content-length causing viewing to not work in chrome/android
* change logic of sending file contents to handle an off by one and be more readable
* Some fixes pointed out by Maxim Romanov. Also simply the loading of events to not join the Monitors table
* fix to sql for timeline
* added RecordAudio to sql in README
* Use sub queries instead of joins to fix errors when using new mysql defaults.
* fix sql queries
* Dockerfile to build feature-h264-videostorage
* Must cast codec
* add php-acpu as a dependency
* require php5-acpu
* fix typo
* remove extra /
* Add a line for out-of-tree builds to do api/lib/Cake/bootstrap.php
* delete merge conflict files
* delete merge conflict files
2017-05-16 10:02:48 +08:00
< video id = " preview " width = " 100% " controls crossorigin = " anonymous " >
2017-07-14 05:34:45 +08:00
< source src = " <?php echo getEventDefaultVideoPath( $first_event ); ?> " type = " video/mp4 " >
Feature h264 videostorage (#1882)
* Moved writing of configure options from Controller to Model. Fixes #191.
* Initial commit for saving events as videos :)
* Add zm_video.cpp to autotools
* Add zm_video.h to autotools
* Search for MP4V2 header file 3 times: mp4v2/mp4v2.h, mp4v2.h, mp4.h
* Fix serve memory leak
* Few minor code improvements
* Added the ability to override preset, tune, profile and few other improvements
* Correctly write SPS & PPS from x264 encoder headers
* Remove unnessecary SPS & PPS writing code
* Imported missing files from master to feature-h264-videostorage
* Audio support including fixes for dts/pts, split on keyframe and update to mkv extension to prevent ffmpeg problems writing rtsp audio to mp4 containter (header problem)
* Updates to make gcc happy
* Add html5 video control to timeline and event to support mkv playback
* Add zm_videostore.cpp to CMakeLists.txt
* Remove Modern Branch for now
* Fix minor bug
* Option handled added in master, removing duplicate declaration
* Add CaptureandRecord from zm_camera.h
* Putting placeholder in for CaptureAndRecord function
* Removed duplicate code and brackets
* add digest auth file for cmake
Conflicts:
src/CMakeLists.txt
* Add web dir back into Makefile.am
Revert "Removed web from SUBDIRS in Makefile.am"
This reverts commit d9bbcdf3a94cba4d8955fcd03bd965ed2772f34d.
* Add CaptureAndRecord to vlc, still need to make it record
* Resolve SegFault on videostore
* Swap to mp4 container
* mp4 changes
* spaces to tabs, hide video stuff if video writer is turned off
* Make timeline open event.mp4 instead of mkv
* Missed mkv in timeline.js
* Fix some issues from the merge conflict
* Resolve post merge build issues with braces
* Fix whitespace
* Update Jpeg and Video options for passthrough options
* Whitespace fix zm_camera.h
* Fix array mkssing comma
* Add support for Jpeg save options for h264 branch snapshot. Might remove altogether if snapshots not needed
* Update VideoStoreData memory size comment
* Change from config.use_mkv_storage to per monitor option VideoWriter from video branch
* Fix bracket issues post merge
* Clean up comments and add av_free_packet
* Convert from event_directory to event file as per Video branch
* Testing videojs for video playback
* Fixed a missing bracket post merge and also SQL_values now used for EventID and Monitors
* bring recent improvements in ffmpeg capture function into captureandrecord
* Remove pict from writeAudioFramePacket as not used
* Add translate options for h264 Storage options in Monitor and update en_gb file
* Cherry-Pick from iconnor - make it compile on ubuntu 15.04. Which is libav 56.1.0
Conflicts:
src/zm_ffmpeg.cpp
src/zm_remote_camera_rtsp.cpp
Conflicts:
distros/ubuntu1204/changelog
* Clean up videostore code and remove lots of unused code
* proof of concept for dynamic/automatic video rotation using video-js plugin zoomrotate
Conflicts:
web/skins/classic/views/event.php
* removed redundant field in sql query
Conflicts:
web/skins/classic/views/event.php
* local storage of video js plugin
* Beautify!
Make the code somewhat readable.
* added missing videojs.zoomrotate.js file
added missing videojs.zoomrotate.js file
* Typo
added missing "
* Added missing brackets
* fix to display thumbnails when only storing snapshot.jpg
* added control for video playback rate
Conflicts:
web/skins/classic/views/event.php
* dynamically create jpegs from video file for viewing in browser
* fix timeline view for SaveJPEGs monitors (without enabled VideoWriter)
* only expose monitor info which are being used in client
* fix segmentation fault in zma with ubuntu 14.04 and ffmpeg 2.5.8 (gcc 4.8)
when libx264 is not installed
* better way of detecting showing image or video in timeline and event view
instead of Monitor.VideoWriter, Event.DefaultVideo is used, so even if
VideoWriter/SaveJPEG option is changed, a valid image or video will always be
displayed for historical events in both timeline and event view
this also fixes loading videos in timeline view
* Fixes problem of crashing zmc when bad packet arrives causing av_interleaved_write_frame() to return non-zero (-22). Prefilters common packet issues. Add metadata title to generated video file
* Remove syslog.h
* fixed SaveJPEGs are not working
which is caused in errors introduced when merging with master
* Update README.md
* Fix build warnings specific to h264 branch, unused FrameImg, unused ret and int64_t snprintf issues
* Fix PRId64 issue in travis, builds locally fine, but I can see a gcc version issue here
* Fix PRId64 issue in travis, another try
* Try "STDC_FORMAT_MACROS" to see if that helps Travis on gcc 4.6.3
* Revert space removal around PRId64
* video branch ffmpeg 2.9 fixes
ffmpeg 2.9 patched removed SSE2 CPU
* Add FFMPEGInit back
* use webvvt to overlay timestamp (honoring Monitor.LabelFormat) to videos in timeline and event
also fixed bug which prevented seeking in timeline video preview
* ffmpeg 3.0 API build failure fixes
* Update README.md
* merge all the commits from the messed up iconnor_video branch
* fix whitespace
* revert
* whitespace fixes
* spelling fix
* put back some text
* add these back
* fix spelling mistake
* Steal some packet dumping routines from ffmpeg. Convert them to use our logging routines
* add a test and error message if the codec is not h264
* these have been removed in master
* add a view to check auth and just send the video
* add some comments, and dump filename and AVFormatContext on failure to write header
* add the toggle for RecordAudio so that the checkbox works to turn off Audio
* Must init videoStore in constuctor
* more debug and comments, return checking
* Fix dropped part of sql query.
* fix extra else and some whitespace
* Fix missing } from merge that was preventing building.
* fix tabs
* get rid of use of separator, just use \n
* Restore lost fixes for deprecation
* Why are these failing
* Respect record_audio flag when setting up video file so dont try and initiliase mp4 with unsupported audio
* Forgot that I was trying to solve case of stream is true and record_audio
is false.
* Pass swscale_ctx back in to getCachedContext or it will create new
context every frame and leak memory like a mofo.
* Add libx264-dev and libmp4v2-dev to build requires to save hassle of
ensuring they are installed before build.
* Merge my Rotation/Orientation work and fixes for bad h264 streams
* need arpa/inet for reverse lookups
* pull in the new byte range code for viewing videos
* Move our recording flag deeper into closeevent
* add braces and only call closeEvent if there is an event
* deprecate the z_frame_rate stuff which is deprecated in ffmpeg
* remark out some debugging
* fix for video on stream 1
* fix audio_stream to audio_st
* Ignore bad decodes
* fix problems with content-length causing viewing to not work in chrome/android
* change logic of sending file contents to handle an off by one and be more readable
* Some fixes pointed out by Maxim Romanov. Also simply the loading of events to not join the Monitors table
* fix to sql for timeline
* added RecordAudio to sql in README
* Use sub queries instead of joins to fix errors when using new mysql defaults.
* fix sql queries
* Dockerfile to build feature-h264-videostorage
* Must cast codec
* add php-acpu as a dependency
* require php5-acpu
* fix typo
* remove extra /
* Add a line for out-of-tree builds to do api/lib/Cake/bootstrap.php
* delete merge conflict files
* delete merge conflict files
2017-05-16 10:02:48 +08:00
Your browser does not support the video tag .
</ video >
2017-05-19 03:11:26 +08:00
o -->
2017-07-14 21:25:53 +08:00
< ? php } ?>
Feature h264 videostorage (#1882)
* Moved writing of configure options from Controller to Model. Fixes #191.
* Initial commit for saving events as videos :)
* Add zm_video.cpp to autotools
* Add zm_video.h to autotools
* Search for MP4V2 header file 3 times: mp4v2/mp4v2.h, mp4v2.h, mp4.h
* Fix serve memory leak
* Few minor code improvements
* Added the ability to override preset, tune, profile and few other improvements
* Correctly write SPS & PPS from x264 encoder headers
* Remove unnessecary SPS & PPS writing code
* Imported missing files from master to feature-h264-videostorage
* Audio support including fixes for dts/pts, split on keyframe and update to mkv extension to prevent ffmpeg problems writing rtsp audio to mp4 containter (header problem)
* Updates to make gcc happy
* Add html5 video control to timeline and event to support mkv playback
* Add zm_videostore.cpp to CMakeLists.txt
* Remove Modern Branch for now
* Fix minor bug
* Option handled added in master, removing duplicate declaration
* Add CaptureandRecord from zm_camera.h
* Putting placeholder in for CaptureAndRecord function
* Removed duplicate code and brackets
* add digest auth file for cmake
Conflicts:
src/CMakeLists.txt
* Add web dir back into Makefile.am
Revert "Removed web from SUBDIRS in Makefile.am"
This reverts commit d9bbcdf3a94cba4d8955fcd03bd965ed2772f34d.
* Add CaptureAndRecord to vlc, still need to make it record
* Resolve SegFault on videostore
* Swap to mp4 container
* mp4 changes
* spaces to tabs, hide video stuff if video writer is turned off
* Make timeline open event.mp4 instead of mkv
* Missed mkv in timeline.js
* Fix some issues from the merge conflict
* Resolve post merge build issues with braces
* Fix whitespace
* Update Jpeg and Video options for passthrough options
* Whitespace fix zm_camera.h
* Fix array mkssing comma
* Add support for Jpeg save options for h264 branch snapshot. Might remove altogether if snapshots not needed
* Update VideoStoreData memory size comment
* Change from config.use_mkv_storage to per monitor option VideoWriter from video branch
* Fix bracket issues post merge
* Clean up comments and add av_free_packet
* Convert from event_directory to event file as per Video branch
* Testing videojs for video playback
* Fixed a missing bracket post merge and also SQL_values now used for EventID and Monitors
* bring recent improvements in ffmpeg capture function into captureandrecord
* Remove pict from writeAudioFramePacket as not used
* Add translate options for h264 Storage options in Monitor and update en_gb file
* Cherry-Pick from iconnor - make it compile on ubuntu 15.04. Which is libav 56.1.0
Conflicts:
src/zm_ffmpeg.cpp
src/zm_remote_camera_rtsp.cpp
Conflicts:
distros/ubuntu1204/changelog
* Clean up videostore code and remove lots of unused code
* proof of concept for dynamic/automatic video rotation using video-js plugin zoomrotate
Conflicts:
web/skins/classic/views/event.php
* removed redundant field in sql query
Conflicts:
web/skins/classic/views/event.php
* local storage of video js plugin
* Beautify!
Make the code somewhat readable.
* added missing videojs.zoomrotate.js file
added missing videojs.zoomrotate.js file
* Typo
added missing "
* Added missing brackets
* fix to display thumbnails when only storing snapshot.jpg
* added control for video playback rate
Conflicts:
web/skins/classic/views/event.php
* dynamically create jpegs from video file for viewing in browser
* fix timeline view for SaveJPEGs monitors (without enabled VideoWriter)
* only expose monitor info which are being used in client
* fix segmentation fault in zma with ubuntu 14.04 and ffmpeg 2.5.8 (gcc 4.8)
when libx264 is not installed
* better way of detecting showing image or video in timeline and event view
instead of Monitor.VideoWriter, Event.DefaultVideo is used, so even if
VideoWriter/SaveJPEG option is changed, a valid image or video will always be
displayed for historical events in both timeline and event view
this also fixes loading videos in timeline view
* Fixes problem of crashing zmc when bad packet arrives causing av_interleaved_write_frame() to return non-zero (-22). Prefilters common packet issues. Add metadata title to generated video file
* Remove syslog.h
* fixed SaveJPEGs are not working
which is caused in errors introduced when merging with master
* Update README.md
* Fix build warnings specific to h264 branch, unused FrameImg, unused ret and int64_t snprintf issues
* Fix PRId64 issue in travis, builds locally fine, but I can see a gcc version issue here
* Fix PRId64 issue in travis, another try
* Try "STDC_FORMAT_MACROS" to see if that helps Travis on gcc 4.6.3
* Revert space removal around PRId64
* video branch ffmpeg 2.9 fixes
ffmpeg 2.9 patched removed SSE2 CPU
* Add FFMPEGInit back
* use webvvt to overlay timestamp (honoring Monitor.LabelFormat) to videos in timeline and event
also fixed bug which prevented seeking in timeline video preview
* ffmpeg 3.0 API build failure fixes
* Update README.md
* merge all the commits from the messed up iconnor_video branch
* fix whitespace
* revert
* whitespace fixes
* spelling fix
* put back some text
* add these back
* fix spelling mistake
* Steal some packet dumping routines from ffmpeg. Convert them to use our logging routines
* add a test and error message if the codec is not h264
* these have been removed in master
* add a view to check auth and just send the video
* add some comments, and dump filename and AVFormatContext on failure to write header
* add the toggle for RecordAudio so that the checkbox works to turn off Audio
* Must init videoStore in constuctor
* more debug and comments, return checking
* Fix dropped part of sql query.
* fix extra else and some whitespace
* Fix missing } from merge that was preventing building.
* fix tabs
* get rid of use of separator, just use \n
* Restore lost fixes for deprecation
* Why are these failing
* Respect record_audio flag when setting up video file so dont try and initiliase mp4 with unsupported audio
* Forgot that I was trying to solve case of stream is true and record_audio
is false.
* Pass swscale_ctx back in to getCachedContext or it will create new
context every frame and leak memory like a mofo.
* Add libx264-dev and libmp4v2-dev to build requires to save hassle of
ensuring they are installed before build.
* Merge my Rotation/Orientation work and fixes for bad h264 streams
* need arpa/inet for reverse lookups
* pull in the new byte range code for viewing videos
* Move our recording flag deeper into closeevent
* add braces and only call closeEvent if there is an event
* deprecate the z_frame_rate stuff which is deprecated in ffmpeg
* remark out some debugging
* fix for video on stream 1
* fix audio_stream to audio_st
* Ignore bad decodes
* fix problems with content-length causing viewing to not work in chrome/android
* change logic of sending file contents to handle an off by one and be more readable
* Some fixes pointed out by Maxim Romanov. Also simply the loading of events to not join the Monitors table
* fix to sql for timeline
* added RecordAudio to sql in README
* Use sub queries instead of joins to fix errors when using new mysql defaults.
* fix sql queries
* Dockerfile to build feature-h264-videostorage
* Must cast codec
* add php-acpu as a dependency
* require php5-acpu
* fix typo
* remove extra /
* Add a line for out-of-tree builds to do api/lib/Cake/bootstrap.php
* delete merge conflict files
* delete merge conflict files
2017-05-16 10:02:48 +08:00
2017-05-19 23:00:37 +08:00
</ div >
2013-05-02 22:20:06 +08:00
</ div >
< div id = " dataPanel " >
< div id = " textPanel " >
< div id = " instruction " >
2015-05-10 21:10:30 +08:00
< p >< ? php echo translate ( 'TimelineTip1' ) ?> </p>
< p >< ? php echo translate ( 'TimelineTip2' ) ?> </p>
< p >< ? php echo translate ( 'TimelineTip3' ) ?> </p>
< p >< ? php echo translate ( 'TimelineTip4' ) ?> </p>
2013-08-16 00:58:08 +08:00
</ div >
2013-05-02 22:20:06 +08:00
< div id = " eventData " >
</ div >
</ div >
< div id = " navPanel " >
2015-05-10 21:10:30 +08:00
< input type = " button " title = " <?php echo translate('PanLeft') ?> " value = " << " onclick = " tlPan( '<?php echo $minTime ?>', '<?php echo $range ?>' ) " />
< input type = " button " title = " <?php echo translate('ZoomOut') ?> " value = " – " onclick = " tlZoomRange( '<?php echo $midTime ?>', '<?php echo (int)( $range * $majXScale['zoomout'] ) ?>' ) " />
< input type = " button " title = " <?php echo translate('PanRight') ?> " value = " >> " onclick = " tlPan( '<?php echo $maxTime ?>', '<?php echo $range ?>' ) " />
2013-05-02 22:20:06 +08:00
</ div >
</ div >
</ div >
< div id = " chartPanel " >
< div id = " chart " class = " graphSize " >
< ? php
2017-05-19 23:00:37 +08:00
if ( $mode == 'overlay' ) {
echo drawYGrid ( $chart , $majYScale , 'majLabelY' , 'majTickY' , 'majGridY graphWidth' );
2013-05-02 22:20:06 +08:00
}
2017-05-19 23:00:37 +08:00
echo drawXGrid ( $chart , $majXScale , 'majLabelX' , 'majTickX' , 'majGridX graphHeight' , 'zoom graphHeight' );
2013-05-02 22:20:06 +08:00
2017-05-19 23:00:37 +08:00
if ( $mode == 'overlay' ) {
2013-05-02 22:20:06 +08:00
?>
< div id = " activity " class = " activitySize " >
< ? php
2017-05-19 02:04:24 +08:00
foreach ( $frameSlots as $index => $slots ) {
2017-05-19 23:00:37 +08:00
foreach ( $slots as $slot ) {
$slotHeight = ( int )( $slot [ 'value' ] / $chart [ 'data' ][ 'y' ][ 'density' ]);
if ( $slotHeight <= 0 )
continue ;
if ( $mouseover ) {
$behaviours = array (
'onclick="' . getSlotShowEventBehaviour ( $slot ) . '"' ,
'onmouseover="' . getSlotPreviewEventBehaviour ( $slot ) . '"'
);
} else {
$behaviours = array (
'onclick="' . getSlotPreviewEventBehaviour ( $slot ) . '"'
);
}
2013-05-02 22:20:06 +08:00
?>
2014-12-05 07:44:23 +08:00
< div class = " activity monitorColour<?php echo $slot['event'] ['MonitorId'] ?> " style = " left: <?php echo $index ?>px; height: <?php echo $slotHeight ?>px; " < ? php echo join ( " " , $behaviours ) ?> ></div>
2013-05-02 22:20:06 +08:00
< ? php
2017-05-19 23:00:37 +08:00
}
2013-05-02 22:20:06 +08:00
}
?>
</ div >
< ? php
2017-05-19 23:00:37 +08:00
} elseif ( $mode == 'split' ) {
2017-05-19 02:04:24 +08:00
foreach ( array_keys ( $monFrameSlots ) as $monitorId ) {
2013-05-02 22:20:06 +08:00
?>
2017-05-19 02:04:24 +08:00
< div id = " activity<?php echo $monitorId ?> " >
2013-05-02 22:20:06 +08:00
< ? php
2017-05-19 02:04:24 +08:00
unset ( $currFrameSlots );
$currFrameSlots = & $monFrameSlots [ $monitorId ];
foreach ( $currFrameSlots as $index => $slot ) {
$slotHeight = ( int )( $slot [ 'value' ] / $chart [ 'data' ][ 'y' ][ 'density' ]);
if ( $slotHeight <= 0 )
continue ;
if ( $mouseover ) {
$behaviours = array (
'onclick="' . getSlotShowEventBehaviour ( $slot ) . '"' ,
'onmouseover="' . getSlotPreviewEventBehaviour ( $slot ) . '"'
);
} else {
$behaviours = array (
'onclick="' . getSlotPreviewEventBehaviour ( $slot ) . '"'
);
}
2013-05-02 22:20:06 +08:00
?>
2017-05-19 02:04:24 +08:00
< div class = " activity activity<?php echo $slot['event'] ['MonitorId'] ?> " style = " left: <?php echo $index ?>px; height: <?php echo $slotHeight ?>px; " < ? php echo join ( " " , $behaviours ) ?> ></div>
2013-05-02 22:20:06 +08:00
< ? php
2017-05-19 23:00:37 +08:00
} # end foreach $currFrameSlots
2017-05-19 02:04:24 +08:00
?>
</ div >
< ? php
2017-05-19 23:00:37 +08:00
} # end foreach $MonitorId
2013-05-02 22:20:06 +08:00
}
2017-05-19 02:04:24 +08:00
foreach ( array_keys ( $monEventSlots ) as $monitorId ) {
2013-05-02 22:20:06 +08:00
?>
2014-12-05 07:44:23 +08:00
< div id = " events<?php echo $monitorId ?> " class = " events eventsSize eventsPos<?php echo $monitorId ?> " >
2013-05-02 22:20:06 +08:00
< ? php
2017-05-19 02:04:24 +08:00
unset ( $currEventSlots );
$currEventSlots = & $monEventSlots [ $monitorId ];
for ( $i = 0 ; $i < $chart [ 'graph' ][ 'width' ]; $i ++ ) {
if ( isset ( $currEventSlots [ $i ]) ) {
unset ( $slot );
$slot = & $currEventSlots [ $i ];
2017-07-14 21:25:53 +08:00
if ( $mouseover ) {
2017-05-19 02:04:24 +08:00
$behaviours = array (
'onclick="' . getSlotShowEventBehaviour ( $slot ) . '"' ,
'onmouseover="' . getSlotPreviewEventBehaviour ( $slot ) . '"'
);
} else {
$behaviours = array (
'onclick="' . getSlotPreviewEventBehaviour ( $slot ) . '"'
);
}
2013-05-02 22:20:06 +08:00
?>
2014-12-05 07:44:23 +08:00
< div class = " event eventsHeight monitorColour<?php echo $monitorId ?> " style = " left: <?php echo $i ?>px; width: <?php echo $slot['width'] ?>px; " < ? php echo join ( " " , $behaviours ) ?> ></div>
2013-05-02 22:20:06 +08:00
< ? php
2017-05-19 23:00:37 +08:00
} # end if isset($currEventSlots[$i])
} # end foreach width segment
2013-05-02 22:20:06 +08:00
?>
</ div >
< ? php
}
?>
</ div >
</ div >
< div id = " chartLabels " class = " graphWidth " >
< div id = " key " >
< ? php
2017-05-19 02:04:24 +08:00
foreach ( array_keys ( $monEventSlots ) as $monitorId ) {
2013-05-02 22:20:06 +08:00
?>
2017-05-19 03:11:26 +08:00
< span class = " keyEntry " >< ? php echo $monitors [ $monitorId ][ 'Name' ] ?>
< img id = " keyBox<?php echo $monitorId ?> " class = " keyBox monitorColour<?php echo $monitorId ?> " src = " graphics/transparent.gif " alt = " <?php echo $monitors[$monitorId] ['Name'] ?> " />
</ span >
2013-05-02 22:20:06 +08:00
< ? php
}
?>
</ div >
2014-12-05 07:44:23 +08:00
< div id = " range " >< ? php echo $title ?> </div>
2013-05-02 22:20:06 +08:00
</ div >
</ div >
</ div >
2017-07-14 05:34:45 +08:00
< script src = " skins/<?php echo $skin ?>/js/moment.min.js " ></ script >
2013-05-02 22:20:06 +08:00
</ body >
</ html >