Merge branch 'master' into zma_to_thread
This commit is contained in:
commit
5fb56c9f57
|
@ -3,6 +3,7 @@
|
|||
module.exports = {
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es6": true,
|
||||
},
|
||||
"extends": ["google"],
|
||||
"overrides": [{
|
||||
|
|
|
@ -34,8 +34,8 @@ install:
|
|||
env:
|
||||
- SMPFLAGS=-j4 OS=el DIST=7
|
||||
- SMPFLAGS=-j4 OS=el DIST=8 DOCKER_REPO=knnniggett/packpack
|
||||
- SMPFLAGS=-j4 OS=fedora DIST=30
|
||||
- SMPFLAGS=-j4 OS=fedora DIST=31
|
||||
- SMPFLAGS=-j4 OS=fedora DIST=32
|
||||
- SMPFLAGS=-j4 OS=ubuntu DIST=trusty DOCKER_REPO=iconzm/packpack
|
||||
- SMPFLAGS=-j4 OS=ubuntu DIST=xenial DOCKER_REPO=iconzm/packpack
|
||||
- SMPFLAGS=-j4 OS=ubuntu DIST=bionic DOCKER_REPO=iconzm/packpack
|
||||
|
|
|
@ -901,7 +901,6 @@ configure_file(zmlinkcontent.sh.in "${CMAKE_CURRENT_BINARY_DIR}/zmlinkcontent.sh
|
|||
|
||||
# Create a target for man pages
|
||||
include(Pod2Man)
|
||||
ADD_MANPAGE_TARGET()
|
||||
|
||||
# Process subdirectories
|
||||
|
||||
|
|
|
@ -53,8 +53,7 @@ MACRO(POD2MAN PODFILE MANFILE SECTION MANPAGE_DEST_PREFIX)
|
|||
|
||||
SET(MANPAGE_TARGET "man-${MANFILE}")
|
||||
|
||||
ADD_CUSTOM_TARGET(${MANPAGE_TARGET} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${MANFILE}.${SECTION}.gz)
|
||||
ADD_DEPENDENCIES(man ${MANPAGE_TARGET})
|
||||
ADD_CUSTOM_TARGET(${MANPAGE_TARGET} ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${MANFILE}.${SECTION}.gz)
|
||||
|
||||
INSTALL(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/${MANFILE}.${SECTION}.gz
|
||||
|
|
|
@ -206,16 +206,20 @@ mv -f CakePHP-Enum-Behavior-%{ceb_version} ./web/api/app/Plugin/CakePHP-Enum-Beh
|
|||
./utils/zmeditconfigdata.sh ZM_OPT_FAST_DELETE no
|
||||
|
||||
%build
|
||||
# Disable LTO due to top level asm
|
||||
# See https://fedoraproject.org/wiki/LTOByDefault
|
||||
%define _lto_cflags %{nil}
|
||||
|
||||
%cmake3 \
|
||||
-DZM_WEB_USER="%{zmuid_final}" \
|
||||
-DZM_WEB_GROUP="%{zmgid_final}" \
|
||||
-DZM_TARGET_DISTRO="%{zmtargetdistro}" \
|
||||
.
|
||||
|
||||
%make_build
|
||||
%cmake3_build
|
||||
|
||||
%install
|
||||
%make_install
|
||||
%cmake3_install
|
||||
|
||||
desktop-file-install \
|
||||
--dir %{buildroot}%{_datadir}/applications \
|
||||
|
|
|
@ -3,7 +3,7 @@ Section: net
|
|||
Priority: optional
|
||||
Maintainer: Isaac Connor <isaac@zoneminder.com>
|
||||
Uploaders: Isaac Connor <isaac@zoneminder.com>
|
||||
Build-Depends: debhelper, dh-systemd, python3-sphinx, dh-linktree, dh-systemd, dh-apache2
|
||||
Build-Depends: debhelper, dh-systemd, sphinx-doc, dh-linktree, dh-systemd, dh-apache2
|
||||
,cmake
|
||||
,libx264-dev, libmp4v2-dev
|
||||
,libavdevice-dev
|
||||
|
|
|
@ -60,7 +60,7 @@ Add the following to the bottom of the file
|
|||
::
|
||||
|
||||
# ZoneMinder repository
|
||||
deb https://zmrepo.zoneminder.com/debian/release-1.34 stretch/
|
||||
deb https://zmrepo.zoneminder.com/debian/release-1.34 buster/
|
||||
|
||||
CTRL+o and <Enter> to save
|
||||
CTRL+x to exit
|
||||
|
|
|
@ -30,7 +30,7 @@ configure_file(zm.in "${CMAKE_CURRENT_BINARY_DIR}/zm" @ONLY)
|
|||
#configure_file(zmeventdump.in zmeventdump @ONLY)
|
||||
|
||||
# Generate man files for the perl scripts destined for the bin folder
|
||||
file(GLOB perlscripts "*.pl")
|
||||
file(GLOB perlscripts "${CMAKE_CURRENT_BINARY_DIR}/*.pl")
|
||||
FOREACH(PERLSCRIPT ${perlscripts})
|
||||
get_filename_component(PERLSCRIPTNAME ${PERLSCRIPT} NAME)
|
||||
POD2MAN(${PERLSCRIPT} zoneminder-${PERLSCRIPTNAME} 8 ${ZM_MANPAGE_DEST_PREFIX})
|
||||
|
|
|
@ -1513,6 +1513,26 @@ our @options = (
|
|||
type => $types{boolean},
|
||||
category => 'logging',
|
||||
},
|
||||
{
|
||||
name => 'ZM_WEB_NAVBAR_TYPE',
|
||||
default => 'normal',
|
||||
description => 'Style of the web console navigation bar',
|
||||
help => q`
|
||||
Choose between different navigation bar styles for the web
|
||||
console. The "normal" style has a menu across the top, which
|
||||
collapses to a pull down menu on small screens. The "collapsed"
|
||||
style is collapsed all the time. Instead of a menu across the
|
||||
top, menu items are accessed from the drop down menu on the
|
||||
right.
|
||||
`,
|
||||
type => {
|
||||
db_type => 'string',
|
||||
hint => 'normal|collapsed',
|
||||
pattern => qr|^([nc])|i,
|
||||
format => q( ($1 =~ /^n/) ? 'normal' : 'collapsed' )
|
||||
},
|
||||
category => 'web',
|
||||
},
|
||||
{
|
||||
name => 'ZM_WEB_TITLE',
|
||||
default => 'ZoneMinder',
|
||||
|
@ -1558,6 +1578,20 @@ our @options = (
|
|||
type => $types{string},
|
||||
category => 'web',
|
||||
},
|
||||
{
|
||||
name => 'ZM_HOME_ABOUT',
|
||||
default => 'yes',
|
||||
description => 'Whether to enable the ZoneMinder About menu.',
|
||||
help => q`
|
||||
When enabled, the ZoneMinder logo in the top left corner of the
|
||||
navigation bar becomes a menu with links to: the ZoneMinder
|
||||
website, ZoneMinder Documentation, and the ZoneMinder forum.
|
||||
End users wishing to rebrand their system may want to disable this
|
||||
as the menu items are currently hard coded.
|
||||
`,
|
||||
type => $types{boolean},
|
||||
category => 'web',
|
||||
},
|
||||
{
|
||||
name => 'ZM_WEB_CONSOLE_BANNER',
|
||||
default => '',
|
||||
|
|
|
@ -82,6 +82,13 @@ sub sendCmd {
|
|||
return $result;
|
||||
}
|
||||
|
||||
sub reboot {
|
||||
my $self = shift;
|
||||
Debug('Camera Rebot');
|
||||
my $cmd = '/admin/reboot.cgi?type=0';
|
||||
$self->sendCmd($cmd);
|
||||
}
|
||||
|
||||
sub reset {
|
||||
my $self = shift;
|
||||
Debug('Camera Reset');
|
||||
|
|
|
@ -1059,6 +1059,7 @@ sub delete_empty_directories {
|
|||
}
|
||||
} # end sub delete_empty_directories
|
||||
|
||||
# The idea is that the youngest file in the event directory gives us the event starttime
|
||||
sub time_of_youngest_file {
|
||||
my $dir = shift;
|
||||
|
||||
|
@ -1067,14 +1068,13 @@ sub time_of_youngest_file {
|
|||
return;
|
||||
}
|
||||
my $youngest = (stat($dir))[9];
|
||||
Debug("stat of $dir is $youngest");
|
||||
Debug("stat of dir $dir is $youngest");
|
||||
foreach my $file ( readdir( DIR ) ) {
|
||||
next if $file =~ /^\./;
|
||||
$_ = (stat($dir))[9];
|
||||
$youngest = $_ if $_ and ( $_ < $youngest );
|
||||
#Debug("stat of $dir is $_ < $youngest");
|
||||
Debug("Found younger file $file at $youngest");
|
||||
}
|
||||
Debug("stat of $dir is $youngest");
|
||||
return $youngest;
|
||||
} # end sub time_of_youngest_file
|
||||
|
||||
|
|
|
@ -97,10 +97,10 @@ void zmLoadConfig() {
|
|||
}
|
||||
|
||||
if ( staticConfig.SERVER_ID ) {
|
||||
Debug(3, "Multi-server configuration detected. Server is %d.", staticConfig.SERVER_ID);
|
||||
} else {
|
||||
Debug(3, "Single server configuration assumed because no Server ID or Name was specified.");
|
||||
}
|
||||
Debug(3, "Multi-server configuration detected. Server is %d.", staticConfig.SERVER_ID);
|
||||
} else {
|
||||
Debug(3, "Single server configuration assumed because no Server ID or Name was specified.");
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(staticConfig.capture_file_format, sizeof(staticConfig.capture_file_format), "%%s/%%0%dd-capture.jpg", config.event_image_digits);
|
||||
|
|
|
@ -653,9 +653,10 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a
|
|||
|
||||
// The idea is to write out 1/sec
|
||||
frame_data.push(new Frame(id, frames, frame_type, timestamp, delta_time, score));
|
||||
if ( write_to_db || (frame_data.size() > (unsigned int)monitor->get_capture_fps()) ) {
|
||||
Debug(1, "Adding %d frames to DB because write_to_db:%d or frames > fps %d",
|
||||
frame_data.size(), write_to_db, (unsigned int)monitor->get_capture_fps());
|
||||
double fps = monitor->get_capture_fps();
|
||||
if ( write_to_db || ( fps && (frame_data.size() > fps) ) ) {
|
||||
Debug(1, "Adding %d frames to DB because write_to_db:%d or frames > fps %f",
|
||||
frame_data.size(), write_to_db, fps);
|
||||
WriteDbFrames();
|
||||
last_db_frame = frames;
|
||||
Debug(1, "Adding %d frames to DB, done", frame_data.size());
|
||||
|
|
|
@ -158,7 +158,6 @@ class Event {
|
|||
static void EmptyPreAlarmFrames() {
|
||||
while ( pre_alarm_count > 0 ) {
|
||||
int i = pre_alarm_count - 1;
|
||||
Debug(1, "EmptyreAlarmFrame: %d", i);
|
||||
delete pre_alarm_data[i].image;
|
||||
pre_alarm_data[i].image = NULL;
|
||||
if ( pre_alarm_data[i].alarm_frame ) {
|
||||
|
@ -179,7 +178,6 @@ Debug(1, "EmptyreAlarmFrame: %d", i);
|
|||
pre_alarm_count++;
|
||||
}
|
||||
void SavePreAlarmFrames() {
|
||||
Debug(1, "SavePreAlarmFrame: %d", pre_alarm_count);
|
||||
for ( int i = 0; i < pre_alarm_count; i++ ) {
|
||||
AddFrame(
|
||||
pre_alarm_data[i].image,
|
||||
|
|
|
@ -187,13 +187,13 @@ bool EventStream::loadEventData(uint64_t event_id) {
|
|||
|
||||
if ( storage_path[0] == '/' )
|
||||
snprintf(event_data->path, sizeof(event_data->path),
|
||||
"%s/%ld/%02d/%02d/%02d/%02d/%02d/%02d",
|
||||
"%s/%d/%02d/%02d/%02d/%02d/%02d/%02d",
|
||||
storage_path, event_data->monitor_id,
|
||||
event_time->tm_year-100, event_time->tm_mon+1, event_time->tm_mday,
|
||||
event_time->tm_hour, event_time->tm_min, event_time->tm_sec);
|
||||
else
|
||||
snprintf(event_data->path, sizeof(event_data->path),
|
||||
"%s/%s/%ld/%02d/%02d/%02d/%02d/%02d/%02d",
|
||||
"%s/%s/%d/%02d/%02d/%02d/%02d/%02d/%02d",
|
||||
staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id,
|
||||
event_time->tm_year-100, event_time->tm_mon+1, event_time->tm_mday,
|
||||
event_time->tm_hour, event_time->tm_min, event_time->tm_sec);
|
||||
|
@ -201,23 +201,23 @@ bool EventStream::loadEventData(uint64_t event_id) {
|
|||
struct tm *event_time = localtime(&event_data->start_time);
|
||||
if ( storage_path[0] == '/' )
|
||||
snprintf(event_data->path, sizeof(event_data->path),
|
||||
"%s/%ld/%04d-%02d-%02d/%" PRIu64,
|
||||
"%s/%d/%04d-%02d-%02d/%" PRIu64,
|
||||
storage_path, event_data->monitor_id,
|
||||
event_time->tm_year+1900, event_time->tm_mon+1, event_time->tm_mday,
|
||||
event_data->event_id);
|
||||
else
|
||||
snprintf(event_data->path, sizeof(event_data->path),
|
||||
"%s/%s/%ld/%04d-%02d-%02d/%" PRIu64,
|
||||
"%s/%s/%d/%04d-%02d-%02d/%" PRIu64,
|
||||
staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id,
|
||||
event_time->tm_year+1900, event_time->tm_mon+1, event_time->tm_mday,
|
||||
event_data->event_id);
|
||||
|
||||
} else {
|
||||
if ( storage_path[0] == '/' )
|
||||
snprintf(event_data->path, sizeof(event_data->path), "%s/%ld/%" PRIu64,
|
||||
snprintf(event_data->path, sizeof(event_data->path), "%s/%d/%" PRIu64,
|
||||
storage_path, event_data->monitor_id, event_data->event_id);
|
||||
else
|
||||
snprintf(event_data->path, sizeof(event_data->path), "%s/%s/%ld/%" PRIu64,
|
||||
snprintf(event_data->path, sizeof(event_data->path), "%s/%s/%d/%" PRIu64,
|
||||
staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id,
|
||||
event_data->event_id);
|
||||
}
|
||||
|
@ -566,11 +566,11 @@ bool EventStream::checkEventLoaded() {
|
|||
|
||||
if ( curr_frame_id <= 0 ) {
|
||||
snprintf(sql, sizeof(sql),
|
||||
"SELECT `Id` FROM `Events` WHERE `MonitorId` = %ld AND `Id` < %" PRIu64 " ORDER BY `Id` DESC LIMIT 1",
|
||||
"SELECT `Id` FROM `Events` WHERE `MonitorId` = %d AND `Id` < %" PRIu64 " ORDER BY `Id` DESC LIMIT 1",
|
||||
event_data->monitor_id, event_data->event_id);
|
||||
} else if ( (unsigned int)curr_frame_id > event_data->frame_count ) {
|
||||
snprintf(sql, sizeof(sql),
|
||||
"SELECT `Id` FROM `Events` WHERE `MonitorId` = %ld AND `Id` > %" PRIu64 " ORDER BY `Id` ASC LIMIT 1",
|
||||
"SELECT `Id` FROM `Events` WHERE `MonitorId` = %d AND `Id` > %" PRIu64 " ORDER BY `Id` ASC LIMIT 1",
|
||||
event_data->monitor_id, event_data->event_id);
|
||||
} else {
|
||||
// No event change required
|
||||
|
@ -810,29 +810,38 @@ bool EventStream::sendFrame(int delta_us) {
|
|||
|
||||
if ( send_raw ) {
|
||||
#if HAVE_SENDFILE
|
||||
fprintf(stdout, "Content-Length: %d\r\n\r\n", (int)filestat.st_size);
|
||||
if ( 0 > fprintf(stdout, "Content-Length: %d\r\n\r\n", (int)filestat.st_size) ) {
|
||||
fclose(fdj); /* Close the file handle */
|
||||
Info("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
if ( zm_sendfile(fileno(stdout), fileno(fdj), 0, (int)filestat.st_size) != (int)filestat.st_size ) {
|
||||
/* sendfile() failed, use standard way instead */
|
||||
img_buffer_size = fread(img_buffer, 1, sizeof(temp_img_buffer), fdj);
|
||||
if ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) {
|
||||
fclose(fdj); /* Close the file handle */
|
||||
Error("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno));
|
||||
Info("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#else
|
||||
fprintf(stdout, "Content-Length: %d\r\n\r\n", img_buffer_size);
|
||||
if ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) {
|
||||
if (
|
||||
(0 > fprintf(stdout, "Content-Length: %d\r\n\r\n", img_buffer_size) )
|
||||
||
|
||||
( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 )
|
||||
) {
|
||||
fclose(fdj); /* Close the file handle */
|
||||
Error("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno));
|
||||
Info("Unable to send raw frame %u: %s", curr_frame_id, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
fclose(fdj); /* Close the file handle */
|
||||
} else {
|
||||
Debug(3, "Content length: %d", img_buffer_size);
|
||||
fprintf(stdout, "Content-Length: %d\r\n\r\n", img_buffer_size);
|
||||
if ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) {
|
||||
if (
|
||||
(0 > fprintf(stdout, "Content-Length: %d\r\n\r\n", img_buffer_size) )
|
||||
||
|
||||
( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) ) {
|
||||
Error("Unable to send stream frame: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ class EventStream : public StreamBase {
|
|||
|
||||
struct EventData {
|
||||
uint64_t event_id;
|
||||
unsigned long monitor_id;
|
||||
unsigned int monitor_id;
|
||||
unsigned long storage_id;
|
||||
unsigned long frame_count;
|
||||
time_t start_time;
|
||||
|
|
|
@ -171,6 +171,7 @@ FfmpegCamera::FfmpegCamera(
|
|||
Panic("Unexpected colours: %d", colours);
|
||||
}
|
||||
|
||||
frame_buffer = NULL;
|
||||
// sws_scale needs 32bit aligned width and an extra 16 bytes padding, so recalculate imagesize, which was width*height*bytes_per_pixel
|
||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||
alignment = 32;
|
||||
|
@ -182,8 +183,13 @@ FfmpegCamera::FfmpegCamera(
|
|||
linesize = FFALIGN(av_image_get_linesize(imagePixFormat, width, 0), alignment);
|
||||
imagesize = avpicture_get_size(imagePixFormat, width, height);
|
||||
#endif
|
||||
if ( linesize != width * colours ) {
|
||||
Debug(1, "linesize %d != width %d * colours %d = %d, allocating frame_buffer", linesize, width, colours, width*colours);
|
||||
frame_buffer = (uint8_t *)av_malloc(imagesize);
|
||||
}
|
||||
|
||||
Debug(1, "ffmpegcamera: width %d height %d linesize %d colours %d imagesize %d", width, height, linesize, colours, imagesize);
|
||||
Debug(1, "ffmpegcamera: width %d height %d linesize %d colours %d image linesize %d imagesize %d",
|
||||
width, height, linesize, colours, width*colours, imagesize);
|
||||
} // FfmpegCamera::FfmpegCamera
|
||||
|
||||
FfmpegCamera::~FfmpegCamera() {
|
||||
|
@ -580,19 +586,23 @@ int FfmpegCamera::transfer_to_image(
|
|||
AVFrame *output_frame,
|
||||
AVFrame *input_frame
|
||||
) {
|
||||
uint8_t* directbuffer;
|
||||
uint8_t* image_buffer; // pointer to buffer in image
|
||||
uint8_t* buffer; // pointer to either image_buffer or frame_buffer
|
||||
|
||||
/* Request a writeable buffer of the target image */
|
||||
directbuffer = image.WriteBuffer(width, height, colours, subpixelorder);
|
||||
if ( directbuffer == NULL ) {
|
||||
image_buffer = image.WriteBuffer(width, height, colours, subpixelorder);
|
||||
if ( image_buffer == NULL ) {
|
||||
Error("Failed requesting writeable buffer for the captured image.");
|
||||
return -1;
|
||||
}
|
||||
// if image_buffer was allocated then use it.
|
||||
buffer = frame_buffer ? frame_buffer : image_buffer;
|
||||
|
||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||
// From what I've read, we should align the linesizes to 32bit so that ffmpeg can use SIMD instructions too.
|
||||
int size = av_image_fill_arrays(
|
||||
output_frame->data, output_frame->linesize,
|
||||
directbuffer, imagePixFormat, width, height,
|
||||
buffer, imagePixFormat, width, height,
|
||||
alignment
|
||||
);
|
||||
if ( size < 0 ) {
|
||||
|
@ -607,9 +617,10 @@ int FfmpegCamera::transfer_to_image(
|
|||
Error("Bad linesize expected %d got %d", linesize, output_frame->linesize[0]);
|
||||
}
|
||||
#else
|
||||
avpicture_fill((AVPicture *)output_frame, directbuffer,
|
||||
avpicture_fill((AVPicture *)output_frame, buffer,
|
||||
imagePixFormat, width, height);
|
||||
#endif
|
||||
|
||||
#if HAVE_LIBSWSCALE
|
||||
if ( !mConvertContext ) {
|
||||
mConvertContext = sws_getContext(
|
||||
|
@ -654,21 +665,33 @@ int FfmpegCamera::transfer_to_image(
|
|||
);
|
||||
return -1;
|
||||
}
|
||||
Debug(4, "Able to convert format %u %s linesize %d,%d height %d to format %u %s linesize %d,%d at frame %d codec %u %s %dx%d ",
|
||||
input_frame->format, av_get_pix_fmt_name((AVPixelFormat)input_frame->format),
|
||||
input_frame->linesize[0], input_frame->linesize[1], mVideoCodecContext->height,
|
||||
imagePixFormat,
|
||||
av_get_pix_fmt_name(imagePixFormat),
|
||||
output_frame->linesize[0], output_frame->linesize[1],
|
||||
frameCount,
|
||||
mVideoCodecContext->pix_fmt, av_get_pix_fmt_name(mVideoCodecContext->pix_fmt),
|
||||
output_frame->width,
|
||||
output_frame->height
|
||||
);
|
||||
Debug(4, "Able to convert format %u %s linesize %d,%d height %d to format %u %s linesize %d,%d at frame %d codec %u %s %dx%d ",
|
||||
input_frame->format, av_get_pix_fmt_name((AVPixelFormat)input_frame->format),
|
||||
input_frame->linesize[0], input_frame->linesize[1], mVideoCodecContext->height,
|
||||
imagePixFormat,
|
||||
av_get_pix_fmt_name(imagePixFormat),
|
||||
output_frame->linesize[0], output_frame->linesize[1],
|
||||
frameCount,
|
||||
mVideoCodecContext->pix_fmt, av_get_pix_fmt_name(mVideoCodecContext->pix_fmt),
|
||||
output_frame->width,
|
||||
output_frame->height
|
||||
);
|
||||
#else // HAVE_LIBSWSCALE
|
||||
Fatal("You must compile ffmpeg with the --enable-swscale "
|
||||
"option to use ffmpeg cameras");
|
||||
#endif // HAVE_LIBSWSCALE
|
||||
if ( buffer != image_buffer ) {
|
||||
Debug(1, "Copying image-buffer to buffer");
|
||||
// Have to copy contents of image_buffer to directbuffer.
|
||||
// Since linesize isn't the same have to copy line by line
|
||||
uint8_t *image_buffer_ptr = image_buffer;
|
||||
int row_size = output_frame->width * colours;
|
||||
for ( int i = 0; i < output_frame->height; i++ ) {
|
||||
memcpy(image_buffer_ptr, buffer, row_size);
|
||||
image_buffer_ptr += row_size;
|
||||
buffer += output_frame->linesize[0];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
} // end int FfmpegCamera::transfer_to_image
|
||||
|
||||
|
|
|
@ -78,6 +78,7 @@ class FfmpegCamera : public Camera {
|
|||
#if HAVE_LIBSWSCALE
|
||||
struct SwsContext *mConvertContext;
|
||||
#endif
|
||||
uint8_t *frame_buffer;
|
||||
|
||||
int error_count;
|
||||
|
||||
|
|
232
src/zm_image.cpp
232
src/zm_image.cpp
|
@ -122,7 +122,7 @@ Image::Image() {
|
|||
blend = fptr_blend;
|
||||
}
|
||||
|
||||
Image::Image( const char *filename ) {
|
||||
Image::Image(const char *filename) {
|
||||
if ( !initialised )
|
||||
Initialise();
|
||||
width = 0;
|
||||
|
@ -141,7 +141,7 @@ Image::Image( const char *filename ) {
|
|||
update_function_pointers();
|
||||
}
|
||||
|
||||
Image::Image( int p_width, int p_height, int p_colours, int p_subpixelorder, uint8_t *p_buffer, unsigned int p_padding) {
|
||||
Image::Image(int p_width, int p_height, int p_colours, int p_subpixelorder, uint8_t *p_buffer, unsigned int p_padding) {
|
||||
if ( !initialised )
|
||||
Initialise();
|
||||
width = p_width;
|
||||
|
@ -166,7 +166,7 @@ Image::Image( int p_width, int p_height, int p_colours, int p_subpixelorder, uin
|
|||
update_function_pointers();
|
||||
}
|
||||
|
||||
Image::Image( int p_width, int p_linesize, int p_height, int p_colours, int p_subpixelorder, uint8_t *p_buffer, unsigned int p_padding) {
|
||||
Image::Image(int p_width, int p_linesize, int p_height, int p_colours, int p_subpixelorder, uint8_t *p_buffer, unsigned int p_padding) {
|
||||
if ( !initialised )
|
||||
Initialise();
|
||||
width = p_width;
|
||||
|
@ -194,7 +194,6 @@ Image::Image( int p_width, int p_linesize, int p_height, int p_colours, int p_su
|
|||
Image::Image(const AVFrame *frame) {
|
||||
text[0] = '\0';
|
||||
width = frame->width;
|
||||
linesize = frame->linesize[0];
|
||||
height = frame->height;
|
||||
pixels = width*height;
|
||||
|
||||
|
@ -202,7 +201,15 @@ Image::Image(const AVFrame *frame) {
|
|||
colours = ZM_COLOUR_RGB32;
|
||||
subpixelorder = ZM_SUBPIX_ORDER_RGBA;
|
||||
|
||||
size = linesize * height;
|
||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||
size = av_image_get_buffer_size(AV_PIX_FMT_RGBA, width, height, 32);
|
||||
// av_image_get_linesize isn't aligned, so we have to do that.
|
||||
linesize = FFALIGN(av_image_get_linesize(AV_PIX_FMT_RGBA, width, 0), 32);
|
||||
#else
|
||||
linesize = FFALIGN(av_image_get_linesize(AV_PIX_FMT_RGBA, width, 0), 1);
|
||||
size = avpicture_get_size(AV_PIX_FMT_RGBA, width, height);
|
||||
#endif
|
||||
|
||||
buffer = 0;
|
||||
holdbuffer = 0;
|
||||
AllocImgBuffer(size);
|
||||
|
@ -344,7 +351,7 @@ void Image::Initialise() {
|
|||
(*fptr_blend)(blend1,blend2,blendres,128,12.0);
|
||||
|
||||
/* Compare results with expected results */
|
||||
for ( int i=0; i < 128; i ++ ) {
|
||||
for ( int i=0; i < 128; i++ ) {
|
||||
if ( abs(blendexp[i] - blendres[i]) > 3 ) {
|
||||
Panic("Blend function failed self-test: Results differ from the expected results. Column %u Expected %u Got %u",i,blendexp[i],blendres[i]);
|
||||
}
|
||||
|
@ -444,7 +451,7 @@ void Image::Initialise() {
|
|||
}
|
||||
|
||||
/* Run the delta8 RGBA function */
|
||||
(*fptr_delta8_rgba)(delta8_1,delta8_2,delta8_rgba_res,32);
|
||||
(*fptr_delta8_rgba)(delta8_1,delta8_2,delta8_rgba_res, 32);
|
||||
|
||||
/* Compare results with expected results */
|
||||
for ( int i=0; i < 32; i++ ) {
|
||||
|
@ -490,9 +497,17 @@ void Image::Initialise() {
|
|||
}
|
||||
|
||||
/* Requests a writeable buffer to the image. This is safer than buffer() because this way we can guarantee that a buffer of required size exists */
|
||||
uint8_t* Image::WriteBuffer(const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder) {
|
||||
uint8_t* Image::WriteBuffer(
|
||||
const unsigned int p_width,
|
||||
const unsigned int p_height,
|
||||
const unsigned int p_colours,
|
||||
const unsigned int p_subpixelorder) {
|
||||
|
||||
if ( p_colours != ZM_COLOUR_GRAY8 && p_colours != ZM_COLOUR_RGB24 && p_colours != ZM_COLOUR_RGB32 ) {
|
||||
if ( p_colours != ZM_COLOUR_GRAY8
|
||||
&&
|
||||
p_colours != ZM_COLOUR_RGB24
|
||||
&&
|
||||
p_colours != ZM_COLOUR_RGB32 ) {
|
||||
Error("WriteBuffer called with unexpected colours: %d", p_colours);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -503,6 +518,7 @@ uint8_t* Image::WriteBuffer(const unsigned int p_width, const unsigned int p_hei
|
|||
}
|
||||
|
||||
if ( p_width != width || p_height != height || p_colours != colours || p_subpixelorder != subpixelorder ) {
|
||||
|
||||
unsigned int newsize = (p_width * p_height) * p_colours;
|
||||
|
||||
if ( buffer == NULL ) {
|
||||
|
@ -523,6 +539,7 @@ uint8_t* Image::WriteBuffer(const unsigned int p_width, const unsigned int p_hei
|
|||
width = p_width;
|
||||
height = p_height;
|
||||
colours = p_colours;
|
||||
linesize = p_width * p_colours;
|
||||
subpixelorder = p_subpixelorder;
|
||||
pixels = height*width;
|
||||
size = newsize;
|
||||
|
@ -574,14 +591,15 @@ void Image::AssignDirect(
|
|||
width = p_width;
|
||||
height = p_height;
|
||||
colours = p_colours;
|
||||
linesize = width*colours;
|
||||
linesize = width * colours;
|
||||
subpixelorder = p_subpixelorder;
|
||||
pixels = height*width;
|
||||
size = new_buffer_size; // was pixels*colours, but we already calculated it above as new_buffer_size
|
||||
|
||||
/* Copy into the held buffer */
|
||||
if ( new_buffer != buffer )
|
||||
if ( new_buffer != buffer ) {
|
||||
(*fptr_imgbufcpy)(buffer, new_buffer, size);
|
||||
}
|
||||
|
||||
/* Free the new buffer */
|
||||
DumpBuffer(new_buffer, p_buffertype);
|
||||
|
@ -602,11 +620,15 @@ void Image::AssignDirect(
|
|||
buffertype = p_buffertype;
|
||||
buffer = new_buffer;
|
||||
}
|
||||
update_function_pointers();
|
||||
} // end void Image::AssignDirect
|
||||
|
||||
}
|
||||
|
||||
void Image::Assign(const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder, const uint8_t* new_buffer, const size_t buffer_size) {
|
||||
void Image::Assign(
|
||||
const unsigned int p_width,
|
||||
const unsigned int p_height,
|
||||
const unsigned int p_colours,
|
||||
const unsigned int p_subpixelorder,
|
||||
const uint8_t* new_buffer,
|
||||
const size_t buffer_size) {
|
||||
unsigned int new_size = (p_width * p_height) * p_colours;
|
||||
|
||||
if ( new_buffer == NULL ) {
|
||||
|
@ -656,21 +678,28 @@ void Image::Assign(const unsigned int p_width, const unsigned int p_height, cons
|
|||
update_function_pointers();
|
||||
}
|
||||
|
||||
void Image::Assign( const Image &image ) {
|
||||
unsigned int new_size = (image.width * image.height) * image.colours;
|
||||
void Image::Assign(const Image &image) {
|
||||
unsigned int new_size = image.height * image.linesize;
|
||||
|
||||
if ( image.buffer == NULL ) {
|
||||
Error("Attempt to assign image with an empty buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
if ( image.colours != ZM_COLOUR_GRAY8 && image.colours != ZM_COLOUR_RGB24 && image.colours != ZM_COLOUR_RGB32 ) {
|
||||
Error("Attempt to assign image with unexpected colours per pixel: %d",image.colours);
|
||||
if ( image.colours != ZM_COLOUR_GRAY8
|
||||
&&
|
||||
image.colours != ZM_COLOUR_RGB24
|
||||
&&
|
||||
image.colours != ZM_COLOUR_RGB32 ) {
|
||||
Error("Attempt to assign image with unexpected colours per pixel: %d", image.colours);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !buffer || image.width != width || image.height != height
|
||||
|| image.colours != colours || image.subpixelorder != subpixelorder) {
|
||||
if ( !buffer
|
||||
|| image.width != width || image.height != height
|
||||
|| image.colours != colours || image.subpixelorder != subpixelorder
|
||||
|| image.linesize != linesize
|
||||
) {
|
||||
|
||||
if ( holdbuffer && buffer ) {
|
||||
if ( new_size > allocation ) {
|
||||
|
@ -690,13 +719,19 @@ void Image::Assign( const Image &image ) {
|
|||
colours = image.colours;
|
||||
subpixelorder = image.subpixelorder;
|
||||
size = new_size;
|
||||
linesize = image.linesize;
|
||||
}
|
||||
|
||||
if ( image.buffer != buffer )
|
||||
(*fptr_imgbufcpy)(buffer, image.buffer, size);
|
||||
}
|
||||
|
||||
Image *Image::HighlightEdges( Rgb colour, unsigned int p_colours, unsigned int p_subpixelorder, const Box *limits ) {
|
||||
Image *Image::HighlightEdges(
|
||||
Rgb colour,
|
||||
unsigned int p_colours,
|
||||
unsigned int p_subpixelorder,
|
||||
const Box *limits
|
||||
) {
|
||||
if ( colours != ZM_COLOUR_GRAY8 ) {
|
||||
Panic("Attempt to highlight image edges when colours = %d", colours);
|
||||
}
|
||||
|
@ -705,7 +740,7 @@ Image *Image::HighlightEdges( Rgb colour, unsigned int p_colours, unsigned int p
|
|||
colour = rgb_convert(colour, p_subpixelorder);
|
||||
|
||||
/* Create a new image of the target format */
|
||||
Image *high_image = new Image( width, height, p_colours, p_subpixelorder );
|
||||
Image *high_image = new Image(width, height, p_colours, p_subpixelorder);
|
||||
uint8_t* high_buff = high_image->WriteBuffer(width, height, p_colours, p_subpixelorder);
|
||||
|
||||
/* Set image to all black */
|
||||
|
@ -723,10 +758,13 @@ Image *Image::HighlightEdges( Rgb colour, unsigned int p_colours, unsigned int p
|
|||
for ( unsigned int x = lo_x; x <= hi_x; x++, p++, phigh++ ) {
|
||||
bool edge = false;
|
||||
if ( *p ) {
|
||||
edge = (x > 0 && !*(p-1)) || (x < (width-1) && !*(p+1)) || (y > 0 && !*(p-width)) || (y < (height-1) && !*(p+width));
|
||||
#if 0
|
||||
if ( !edge && x > 0 && !*(p-1) ) edge = true;
|
||||
if ( !edge && x < (width-1) && !*(p+1) ) edge = true;
|
||||
if ( !edge && y > 0 && !*(p-width) ) edge = true;
|
||||
if ( !edge && y < (height-1) && !*(p+width) ) edge = true;
|
||||
#endif
|
||||
}
|
||||
if ( edge ) {
|
||||
*phigh = colour;
|
||||
|
@ -740,10 +778,13 @@ Image *Image::HighlightEdges( Rgb colour, unsigned int p_colours, unsigned int p
|
|||
for ( unsigned int x = lo_x; x <= hi_x; x++, p++, phigh += 3 ) {
|
||||
bool edge = false;
|
||||
if ( *p ) {
|
||||
edge = (x > 0 && !*(p-1)) || (x < (width-1) && !*(p+1)) || (y > 0 && !*(p-width)) || (y < (height-1) && !*(p+width));
|
||||
#if 0
|
||||
if ( !edge && x > 0 && !*(p-1) ) edge = true;
|
||||
if ( !edge && x < (width-1) && !*(p+1) ) edge = true;
|
||||
if ( !edge && y > 0 && !*(p-width) ) edge = true;
|
||||
if ( !edge && y < (height-1) && !*(p+width) ) edge = true;
|
||||
#endif
|
||||
}
|
||||
if ( edge ) {
|
||||
RED_PTR_RGBA(phigh) = RED_VAL_RGBA(colour);
|
||||
|
@ -759,10 +800,13 @@ Image *Image::HighlightEdges( Rgb colour, unsigned int p_colours, unsigned int p
|
|||
for ( unsigned int x = lo_x; x <= hi_x; x++, p++, phigh++ ) {
|
||||
bool edge = false;
|
||||
if ( *p ) {
|
||||
edge = (x > 0 && !*(p-1)) || (x < (width-1) && !*(p+1)) || (y > 0 && !*(p-width)) || (y < (height-1) && !*(p+width));
|
||||
#if 0
|
||||
if ( !edge && x > 0 && !*(p-1) ) edge = true;
|
||||
if ( !edge && x < (width-1) && !*(p+1) ) edge = true;
|
||||
if ( !edge && y > 0 && !*(p-width) ) edge = true;
|
||||
if ( !edge && y < (height-1) && !*(p+width) ) edge = true;
|
||||
#endif
|
||||
}
|
||||
if ( edge ) {
|
||||
*phigh = colour;
|
||||
|
@ -774,9 +818,9 @@ Image *Image::HighlightEdges( Rgb colour, unsigned int p_colours, unsigned int p
|
|||
return high_image;
|
||||
}
|
||||
|
||||
bool Image::ReadRaw( const char *filename ) {
|
||||
bool Image::ReadRaw(const char *filename) {
|
||||
FILE *infile;
|
||||
if ( (infile = fopen( filename, "rb" )) == NULL ) {
|
||||
if ( (infile = fopen(filename, "rb")) == NULL ) {
|
||||
Error("Can't open %s: %s", filename, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
@ -871,16 +915,13 @@ bool Image::ReadJpeg(const char *filename, unsigned int p_colours, unsigned int
|
|||
Debug(9, "Image dimensions differ. Old: %ux%u New: %ux%u", width, height, new_width, new_height);
|
||||
}
|
||||
|
||||
switch (p_colours) {
|
||||
switch ( p_colours ) {
|
||||
case ZM_COLOUR_GRAY8:
|
||||
{
|
||||
cinfo->out_color_space = JCS_GRAYSCALE;
|
||||
new_colours = ZM_COLOUR_GRAY8;
|
||||
new_subpixelorder = ZM_SUBPIX_ORDER_NONE;
|
||||
break;
|
||||
}
|
||||
case ZM_COLOUR_RGB32:
|
||||
{
|
||||
#ifdef JCS_EXTENSIONS
|
||||
new_colours = ZM_COLOUR_RGB32;
|
||||
if ( p_subpixelorder == ZM_SUBPIX_ORDER_BGRA ) {
|
||||
|
@ -901,10 +942,8 @@ bool Image::ReadJpeg(const char *filename, unsigned int p_colours, unsigned int
|
|||
#else
|
||||
Warning("libjpeg-turbo is required for reading a JPEG directly into a RGB32 buffer, reading into a RGB24 buffer instead.");
|
||||
#endif
|
||||
}
|
||||
case ZM_COLOUR_RGB24:
|
||||
default:
|
||||
{
|
||||
new_colours = ZM_COLOUR_RGB24;
|
||||
if ( p_subpixelorder == ZM_SUBPIX_ORDER_BGR ) {
|
||||
#ifdef JCS_EXTENSIONS
|
||||
|
@ -928,8 +967,7 @@ cinfo->out_color_space = JCS_RGB;
|
|||
new_subpixelorder = ZM_SUBPIX_ORDER_RGB;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} // end switch p_colours
|
||||
|
||||
if ( WriteBuffer(new_width, new_height, new_colours, new_subpixelorder) == NULL ) {
|
||||
Error("Failed requesting writeable buffer for reading JPEG image.");
|
||||
|
@ -940,11 +978,10 @@ cinfo->out_color_space = JCS_RGB;
|
|||
|
||||
jpeg_start_decompress(cinfo);
|
||||
|
||||
JSAMPROW row_pointer; /* pointer to a single row */
|
||||
int row_stride = width * colours; /* physical row width in buffer */
|
||||
JSAMPROW row_pointer = buffer;
|
||||
while ( cinfo->output_scanline < cinfo->output_height ) {
|
||||
row_pointer = &buffer[cinfo->output_scanline * row_stride];
|
||||
jpeg_read_scanlines(cinfo, &row_pointer, 1);
|
||||
row_pointer += linesize;
|
||||
}
|
||||
|
||||
jpeg_finish_decompress(cinfo);
|
||||
|
@ -958,16 +995,16 @@ cinfo->out_color_space = JCS_RGB;
|
|||
// Note quality=zero means default
|
||||
|
||||
bool Image::WriteJpeg(const char *filename, int quality_override) const {
|
||||
return Image::WriteJpeg(filename, quality_override, (timeval){0,0});
|
||||
return Image::WriteJpeg(filename, quality_override, (timeval){0,0}, false);
|
||||
}
|
||||
bool Image::WriteJpeg(const char *filename) const {
|
||||
return Image::WriteJpeg(filename, 0, (timeval){0,0});
|
||||
return Image::WriteJpeg(filename, 0, (timeval){0,0}, false);
|
||||
}
|
||||
bool Image::WriteJpeg(const char *filename, bool on_blocking_abort) const {
|
||||
return Image::WriteJpeg(filename, 0, (timeval){0,0}, on_blocking_abort);
|
||||
}
|
||||
bool Image::WriteJpeg(const char *filename, struct timeval timestamp) const {
|
||||
return Image::WriteJpeg(filename, 0, timestamp);
|
||||
return Image::WriteJpeg(filename, 0, timestamp, false);
|
||||
}
|
||||
|
||||
bool Image::WriteJpeg(const char *filename, int quality_override, struct timeval timestamp) const {
|
||||
|
@ -1038,13 +1075,16 @@ bool Image::WriteJpeg(const char *filename, int quality_override, struct timeval
|
|||
case ZM_COLOUR_RGB32:
|
||||
#ifdef JCS_EXTENSIONS
|
||||
cinfo->input_components = 4;
|
||||
if ( subpixelorder == ZM_SUBPIX_ORDER_BGRA ) {
|
||||
if ( subpixelorder == ZM_SUBPIX_ORDER_RGBA ) {
|
||||
cinfo->in_color_space = JCS_EXT_RGBX;
|
||||
} else if ( subpixelorder == ZM_SUBPIX_ORDER_BGRA ) {
|
||||
cinfo->in_color_space = JCS_EXT_BGRX;
|
||||
} else if ( subpixelorder == ZM_SUBPIX_ORDER_ARGB ) {
|
||||
cinfo->in_color_space = JCS_EXT_XRGB;
|
||||
} else if ( subpixelorder == ZM_SUBPIX_ORDER_ABGR ) {
|
||||
cinfo->in_color_space = JCS_EXT_XBGR;
|
||||
} else {
|
||||
Warning("Unknwon subpixelorder %d", subpixelorder);
|
||||
/* Assume RGBA */
|
||||
cinfo->in_color_space = JCS_EXT_RGBX;
|
||||
}
|
||||
|
@ -1114,16 +1154,12 @@ cinfo->out_color_space = JCS_RGB;
|
|||
jpeg_write_marker(cinfo, EXIF_CODE, (const JOCTET *)exiftimes, sizeof(exiftimes));
|
||||
}
|
||||
|
||||
JSAMPROW row_pointer; /* pointer to a single row */
|
||||
int row_stride = linesize;
|
||||
//cinfo->image_width * colours; /* physical row width in buffer */
|
||||
JSAMPROW row_pointer = buffer; /* pointer to a single row */
|
||||
while ( cinfo->next_scanline < cinfo->image_height ) {
|
||||
row_pointer = &buffer[cinfo->next_scanline * row_stride];
|
||||
jpeg_write_scanlines(cinfo, &row_pointer, 1);
|
||||
row_pointer += linesize;
|
||||
}
|
||||
|
||||
jpeg_finish_compress(cinfo);
|
||||
|
||||
fclose(outfile);
|
||||
|
||||
return true;
|
||||
|
@ -1237,11 +1273,10 @@ cinfo->out_color_space = JCS_RGB;
|
|||
|
||||
jpeg_start_decompress(cinfo);
|
||||
|
||||
JSAMPROW row_pointer; /* pointer to a single row */
|
||||
int row_stride = width * colours; /* physical row width in buffer */
|
||||
JSAMPROW row_pointer = buffer; /* pointer to a single row */
|
||||
while ( cinfo->output_scanline < cinfo->output_height ) {
|
||||
row_pointer = &buffer[cinfo->output_scanline * row_stride];
|
||||
jpeg_read_scanlines(cinfo, &row_pointer, 1);
|
||||
row_pointer += linesize;
|
||||
}
|
||||
|
||||
jpeg_finish_decompress(cinfo);
|
||||
|
@ -1273,7 +1308,7 @@ bool Image::EncodeJpeg(JOCTET *outbuffer, int *outbuffer_size, int quality_overr
|
|||
cinfo->image_width = width; /* image width and height, in pixels */
|
||||
cinfo->image_height = height;
|
||||
|
||||
switch (colours) {
|
||||
switch ( colours ) {
|
||||
case ZM_COLOUR_GRAY8:
|
||||
cinfo->input_components = 1;
|
||||
cinfo->in_color_space = JCS_GRAYSCALE;
|
||||
|
@ -1281,13 +1316,16 @@ bool Image::EncodeJpeg(JOCTET *outbuffer, int *outbuffer_size, int quality_overr
|
|||
case ZM_COLOUR_RGB32:
|
||||
#ifdef JCS_EXTENSIONS
|
||||
cinfo->input_components = 4;
|
||||
if ( subpixelorder == ZM_SUBPIX_ORDER_BGRA ) {
|
||||
if ( subpixelorder == ZM_SUBPIX_ORDER_RGBA ) {
|
||||
cinfo->in_color_space = JCS_EXT_RGBX;
|
||||
} else if ( subpixelorder == ZM_SUBPIX_ORDER_BGRA ) {
|
||||
cinfo->in_color_space = JCS_EXT_BGRX;
|
||||
} else if ( subpixelorder == ZM_SUBPIX_ORDER_ARGB ) {
|
||||
cinfo->in_color_space = JCS_EXT_XRGB;
|
||||
} else if ( subpixelorder == ZM_SUBPIX_ORDER_ABGR ) {
|
||||
cinfo->in_color_space = JCS_EXT_XBGR;
|
||||
} else {
|
||||
Warning("unknown subpixelorder %d", subpixelorder);
|
||||
/* Assume RGBA */
|
||||
cinfo->in_color_space = JCS_EXT_RGBX;
|
||||
}
|
||||
|
@ -1328,11 +1366,10 @@ cinfo->out_color_space = JCS_RGB;
|
|||
|
||||
jpeg_start_compress(cinfo, TRUE);
|
||||
|
||||
JSAMPROW row_pointer; /* pointer to a single row */
|
||||
int row_stride = linesize; /* physical row width in buffer */
|
||||
JSAMPROW row_pointer = buffer;
|
||||
while ( cinfo->next_scanline < cinfo->image_height ) {
|
||||
row_pointer = &buffer[cinfo->next_scanline * row_stride];
|
||||
jpeg_write_scanlines(cinfo, &row_pointer, 1);
|
||||
row_pointer += linesize;
|
||||
}
|
||||
|
||||
jpeg_finish_compress(cinfo);
|
||||
|
@ -1617,7 +1654,6 @@ void Image::Overlay( const Image &image, unsigned int x, unsigned int y ) {
|
|||
} else {
|
||||
Error("Overlay called with unexpected colours: %d", colours);
|
||||
}
|
||||
Debug(1, "Overlay");
|
||||
} // end void Image::Overlay( const Image &image, unsigned int x, unsigned int y )
|
||||
|
||||
void Image::Blend( const Image &image, int transparency ) {
|
||||
|
@ -1661,7 +1697,7 @@ void Image::Blend( const Image &image, int transparency ) {
|
|||
AssignDirect(width, height, colours, subpixelorder, new_buffer, size, ZM_BUFTYPE_ZM);
|
||||
}
|
||||
|
||||
Image *Image::Merge( unsigned int n_images, Image *images[] ) {
|
||||
Image *Image::Merge(unsigned int n_images, Image *images[]) {
|
||||
if ( n_images == 1 ) return new Image(*images[0]);
|
||||
|
||||
unsigned int width = images[0]->width;
|
||||
|
@ -1690,7 +1726,7 @@ Image *Image::Merge( unsigned int n_images, Image *images[] ) {
|
|||
return result;
|
||||
}
|
||||
|
||||
Image *Image::Merge( unsigned int n_images, Image *images[], double weight ) {
|
||||
Image *Image::Merge(unsigned int n_images, Image *images[], double weight) {
|
||||
if ( n_images == 1 ) return new Image(*images[0]);
|
||||
|
||||
unsigned int width = images[0]->width;
|
||||
|
@ -1703,7 +1739,7 @@ Image *Image::Merge( unsigned int n_images, Image *images[], double weight ) {
|
|||
}
|
||||
}
|
||||
|
||||
Image *result = new Image( *images[0] );
|
||||
Image *result = new Image(*images[0]);
|
||||
unsigned int size = result->size;
|
||||
double factor = 1.0*weight;
|
||||
for ( unsigned int i = 1; i < n_images; i++ ) {
|
||||
|
@ -1732,7 +1768,7 @@ Image *Image::Highlight( unsigned int n_images, Image *images[], const Rgb thres
|
|||
}
|
||||
}
|
||||
|
||||
Image *result = new Image( width, height, images[0]->colours, images[0]->subpixelorder );
|
||||
Image *result = new Image(width, height, images[0]->colours, images[0]->subpixelorder);
|
||||
unsigned int size = result->size;
|
||||
for ( unsigned int c = 0; c < colours; c++ ) {
|
||||
unsigned int ref_colour_rgb = RGB_VAL(ref_colour,c);
|
||||
|
@ -2336,9 +2372,7 @@ void Image::Outline( Rgb colour, const Polygon &polygon ) {
|
|||
|
||||
double grad;
|
||||
|
||||
//Debug( 9, "dx: %.2lf, dy: %.2lf", dx, dy );
|
||||
if ( fabs(dx) <= fabs(dy) ) {
|
||||
//Debug( 9, "dx <= dy" );
|
||||
if ( y1 != y2 )
|
||||
grad = dx/dy;
|
||||
else
|
||||
|
@ -2348,9 +2382,7 @@ void Image::Outline( Rgb colour, const Polygon &polygon ) {
|
|||
int y, yinc = (y1<y2)?1:-1;
|
||||
grad *= yinc;
|
||||
if ( colours == ZM_COLOUR_GRAY8 ) {
|
||||
//Debug( 9, "x1:%d, x2:%d, y1:%d, y2:%d, gr:%.2f", x1, x2, y1, y2, grad );
|
||||
for ( x = x1, y = y1; y != y2; y += yinc, x += grad ) {
|
||||
//Debug( 9, "x:%.2f, y:%d", x, y );
|
||||
buffer[(y*width)+int(round(x))] = colour;
|
||||
}
|
||||
} else if ( colours == ZM_COLOUR_RGB24 ) {
|
||||
|
@ -2437,7 +2469,8 @@ void Image::Fill(Rgb colour, int density, const Polygon &polygon) {
|
|||
#ifndef ZM_DBG_OFF
|
||||
if ( logLevel() >= Logger::DEBUG9 ) {
|
||||
for ( int i = 0; i < n_global_edges; i++ ) {
|
||||
Debug( 9, "%d: min_y: %d, max_y:%d, min_x:%.2f, 1/m:%.2f", i, global_edges[i].min_y, global_edges[i].max_y, global_edges[i].min_x, global_edges[i]._1_m );
|
||||
Debug(9, "%d: min_y: %d, max_y:%d, min_x:%.2f, 1/m:%.2f",
|
||||
i, global_edges[i].min_y, global_edges[i].max_y, global_edges[i].min_x, global_edges[i]._1_m);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -2460,11 +2493,12 @@ void Image::Fill(Rgb colour, int density, const Polygon &polygon) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
qsort( active_edges, n_active_edges, sizeof(*active_edges), Edge::CompareX );
|
||||
qsort(active_edges, n_active_edges, sizeof(*active_edges), Edge::CompareX);
|
||||
#ifndef ZM_DBG_OFF
|
||||
if ( logLevel() >= Logger::DEBUG9 ) {
|
||||
for ( int i = 0; i < n_active_edges; i++ ) {
|
||||
Debug( 9, "%d - %d: min_y: %d, max_y:%d, min_x:%.2f, 1/m:%.2f", y, i, active_edges[i].min_y, active_edges[i].max_y, active_edges[i].min_x, active_edges[i]._1_m );
|
||||
Debug(9, "%d - %d: min_y: %d, max_y:%d, min_x:%.2f, 1/m:%.2f",
|
||||
y, i, active_edges[i].min_y, active_edges[i].max_y, active_edges[i].min_x, active_edges[i]._1_m );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -2505,7 +2539,7 @@ void Image::Fill(Rgb colour, int density, const Polygon &polygon) {
|
|||
for ( int i = n_active_edges-1; i >= 0; i-- ) {
|
||||
if ( y >= active_edges[i].max_y ) {
|
||||
// Or >= as per sheets
|
||||
Debug( 9, "Deleting active_edge" );
|
||||
Debug(9, "Deleting active_edge");
|
||||
if ( i < (n_active_edges-1) ) {
|
||||
//memcpy( &active_edges[i], &active_edges[i+1], sizeof(*active_edges)*(n_active_edges-i) );
|
||||
memmove( &active_edges[i], &active_edges[i+1], sizeof(*active_edges)*(n_active_edges-i) );
|
||||
|
@ -2518,27 +2552,21 @@ void Image::Fill(Rgb colour, int density, const Polygon &polygon) {
|
|||
} while ( n_global_edges || n_active_edges );
|
||||
}
|
||||
|
||||
void Image::Fill( Rgb colour, const Polygon &polygon ) {
|
||||
Fill( colour, 1, polygon );
|
||||
void Image::Fill(Rgb colour, const Polygon &polygon) {
|
||||
Fill(colour, 1, polygon);
|
||||
}
|
||||
|
||||
/* RGB32 compatible: complete */
|
||||
void Image::Rotate( int angle ) {
|
||||
|
||||
void Image::Rotate(int angle) {
|
||||
angle %= 360;
|
||||
|
||||
if ( !angle ) {
|
||||
if ( !angle || angle%90 ) {
|
||||
return;
|
||||
}
|
||||
if ( angle%90 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int new_height = height;
|
||||
unsigned int new_width = width;
|
||||
uint8_t* rotate_buffer = AllocBuffer(size);
|
||||
|
||||
switch( angle ) {
|
||||
switch ( angle ) {
|
||||
case 90 :
|
||||
{
|
||||
new_height = width;
|
||||
|
@ -2557,17 +2585,17 @@ void Image::Rotate( int angle ) {
|
|||
}
|
||||
} else if ( colours == ZM_COLOUR_RGB32 ) {
|
||||
Rgb* s_rptr = (Rgb*)s_ptr;
|
||||
for ( unsigned int i = new_width; i > 0; i-- ) {
|
||||
for ( unsigned int i = new_width; i; i-- ) {
|
||||
Rgb* d_rptr = (Rgb*)(rotate_buffer+((i-1)<<2));
|
||||
for ( unsigned int j = new_height; j > 0; j-- ) {
|
||||
for ( unsigned int j = new_height; j; j-- ) {
|
||||
*d_rptr = *s_rptr++;
|
||||
d_rptr += new_width;
|
||||
}
|
||||
}
|
||||
} else /* Assume RGB24 */ {
|
||||
for ( unsigned int i = new_width; i > 0; i-- ) {
|
||||
for ( unsigned int i = new_width; i; i-- ) {
|
||||
unsigned char *d_ptr = rotate_buffer+((i-1)*3);
|
||||
for ( unsigned int j = new_height; j > 0; j-- ) {
|
||||
for ( unsigned int j = new_height; j; j-- ) {
|
||||
*d_ptr = *s_ptr++;
|
||||
*(d_ptr+1) = *s_ptr++;
|
||||
*(d_ptr+2) = *s_ptr++;
|
||||
|
@ -2646,8 +2674,8 @@ void Image::Rotate( int angle ) {
|
|||
}
|
||||
}
|
||||
|
||||
AssignDirect( new_width, new_height, colours, subpixelorder, rotate_buffer, size, ZM_BUFTYPE_ZM);
|
||||
}
|
||||
AssignDirect(new_width, new_height, colours, subpixelorder, rotate_buffer, size, ZM_BUFTYPE_ZM);
|
||||
} // void Image::Rotate(int angle)
|
||||
|
||||
/* RGB32 compatible: complete */
|
||||
void Image::Flip( bool leftright ) {
|
||||
|
@ -2696,18 +2724,17 @@ void Image::Flip( bool leftright ) {
|
|||
unsigned char *s_ptr = buffer+(height*line_bytes);
|
||||
unsigned char *d_ptr = flip_buffer;
|
||||
|
||||
while( s_ptr > buffer ) {
|
||||
while ( s_ptr > buffer ) {
|
||||
s_ptr -= line_bytes;
|
||||
memcpy( d_ptr, s_ptr, line_bytes );
|
||||
memcpy(d_ptr, s_ptr, line_bytes);
|
||||
d_ptr += line_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
AssignDirect( width, height, colours, subpixelorder, flip_buffer, size, ZM_BUFTYPE_ZM);
|
||||
|
||||
AssignDirect(width, height, colours, subpixelorder, flip_buffer, size, ZM_BUFTYPE_ZM);
|
||||
}
|
||||
|
||||
void Image::Scale( unsigned int factor ) {
|
||||
void Image::Scale(unsigned int factor) {
|
||||
if ( !factor ) {
|
||||
Error("Bogus scale factor %d found", factor);
|
||||
return;
|
||||
|
@ -2767,7 +2794,7 @@ void Image::Scale( unsigned int factor ) {
|
|||
unsigned int last_h_index = 0;
|
||||
unsigned int last_w_index = 0;
|
||||
unsigned int h_index;
|
||||
for ( unsigned int y = 0; y < (unsigned int)height; y++ ) {
|
||||
for ( unsigned int y = 0; y < height; y++ ) {
|
||||
h_count += factor;
|
||||
h_index = h_count/ZM_SCALE_BASE;
|
||||
if ( h_index > last_h_index ) {
|
||||
|
@ -2776,7 +2803,7 @@ void Image::Scale( unsigned int factor ) {
|
|||
last_w_index = 0;
|
||||
|
||||
unsigned char *ps = &buffer[y*wc];
|
||||
for ( unsigned int x = 0; x < (unsigned int)width; x++ ) {
|
||||
for ( unsigned int x = 0; x < width; x++ ) {
|
||||
w_count += factor;
|
||||
w_index = w_count/ZM_SCALE_BASE;
|
||||
|
||||
|
@ -2795,7 +2822,7 @@ void Image::Scale( unsigned int factor ) {
|
|||
new_width = last_w_index;
|
||||
new_height = last_h_index;
|
||||
} // end foreach line
|
||||
AssignDirect( new_width, new_height, colours, subpixelorder, scale_buffer, scale_buffer_size, ZM_BUFTYPE_ZM);
|
||||
AssignDirect(new_width, new_height, colours, subpixelorder, scale_buffer, scale_buffer_size, ZM_BUFTYPE_ZM);
|
||||
}
|
||||
|
||||
void Image::Deinterlace_Discard() {
|
||||
|
@ -3473,7 +3500,7 @@ __attribute__((noinline)) void fast_delta8_bgr(const uint8_t* col1, const uint8_
|
|||
int r,g,b;
|
||||
const uint8_t* const max_ptr = result + count;
|
||||
|
||||
while(result < max_ptr) {
|
||||
while (result < max_ptr) {
|
||||
b = abs(col1[0] - col2[0]);
|
||||
g = abs(col1[1] - col2[1]);
|
||||
r = abs(col1[2] - col2[2]);
|
||||
|
@ -3502,7 +3529,7 @@ __attribute__((noinline)) void std_delta8_bgr(const uint8_t* col1, const uint8_t
|
|||
int r,g,b;
|
||||
const uint8_t* const max_ptr = result + count;
|
||||
|
||||
while(result < max_ptr) {
|
||||
while (result < max_ptr) {
|
||||
b = abs(col1[0] - col2[0]);
|
||||
g = abs(col1[1] - col2[1]);
|
||||
r = abs(col1[2] - col2[2]);
|
||||
|
@ -3520,7 +3547,7 @@ __attribute__((noinline)) void fast_delta8_rgba(const uint8_t* col1, const uint8
|
|||
int r,g,b;
|
||||
const uint8_t* const max_ptr = result + count;
|
||||
|
||||
while(result < max_ptr) {
|
||||
while (result < max_ptr) {
|
||||
r = abs(col1[0] - col2[0]);
|
||||
g = abs(col1[1] - col2[1]);
|
||||
b = abs(col1[2] - col2[2]);
|
||||
|
@ -3549,7 +3576,7 @@ __attribute__((noinline)) void std_delta8_rgba(const uint8_t* col1, const uint8_
|
|||
int r,g,b;
|
||||
const uint8_t* const max_ptr = result + count;
|
||||
|
||||
while(result < max_ptr) {
|
||||
while (result < max_ptr) {
|
||||
r = abs(col1[0] - col2[0]);
|
||||
g = abs(col1[1] - col2[1]);
|
||||
b = abs(col1[2] - col2[2]);
|
||||
|
@ -3567,7 +3594,7 @@ __attribute__((noinline)) void fast_delta8_bgra(const uint8_t* col1, const uint8
|
|||
int r,g,b;
|
||||
const uint8_t* const max_ptr = result + count;
|
||||
|
||||
while(result < max_ptr) {
|
||||
while (result < max_ptr) {
|
||||
b = abs(col1[0] - col2[0]);
|
||||
g = abs(col1[1] - col2[1]);
|
||||
r = abs(col1[2] - col2[2]);
|
||||
|
@ -3595,7 +3622,7 @@ __attribute__((noinline)) void std_delta8_bgra(const uint8_t* col1, const uint8_
|
|||
int r,g,b;
|
||||
const uint8_t* const max_ptr = result + count;
|
||||
|
||||
while(result < max_ptr) {
|
||||
while (result < max_ptr) {
|
||||
b = abs(col1[0] - col2[0]);
|
||||
g = abs(col1[1] - col2[1]);
|
||||
r = abs(col1[2] - col2[2]);
|
||||
|
@ -3613,7 +3640,7 @@ __attribute__((noinline)) void fast_delta8_argb(const uint8_t* col1, const uint8
|
|||
int r,g,b;
|
||||
const uint8_t* const max_ptr = result + count;
|
||||
|
||||
while(result < max_ptr) {
|
||||
while (result < max_ptr) {
|
||||
r = abs(col1[1] - col2[1]);
|
||||
g = abs(col1[2] - col2[2]);
|
||||
b = abs(col1[3] - col2[3]);
|
||||
|
@ -3636,12 +3663,13 @@ __attribute__((noinline)) void fast_delta8_argb(const uint8_t* col1, const uint8
|
|||
result += 4;
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((noinline)) void std_delta8_argb(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count) {
|
||||
/* Loop unrolling is used to work on 16 bytes (4 rgb32 pixels) at a time */
|
||||
int r,g,b;
|
||||
const uint8_t* const max_ptr = result + count;
|
||||
|
||||
while(result < max_ptr) {
|
||||
while (result < max_ptr) {
|
||||
r = abs(col1[1] - col2[1]);
|
||||
g = abs(col1[2] - col2[2]);
|
||||
b = abs(col1[3] - col2[3]);
|
||||
|
@ -3659,7 +3687,7 @@ __attribute__((noinline)) void fast_delta8_abgr(const uint8_t* col1, const uint8
|
|||
int r,g,b;
|
||||
const uint8_t* const max_ptr = result + count;
|
||||
|
||||
while(result < max_ptr) {
|
||||
while (result < max_ptr) {
|
||||
b = abs(col1[1] - col2[1]);
|
||||
g = abs(col1[2] - col2[2]);
|
||||
r = abs(col1[3] - col2[3]);
|
||||
|
@ -3686,7 +3714,7 @@ __attribute__((noinline)) void std_delta8_abgr(const uint8_t* col1, const uint8_
|
|||
int r,g,b;
|
||||
const uint8_t* const max_ptr = result + count;
|
||||
|
||||
while(result < max_ptr) {
|
||||
while (result < max_ptr) {
|
||||
b = abs(col1[1] - col2[1]);
|
||||
g = abs(col1[2] - col2[2]);
|
||||
r = abs(col1[3] - col2[3]);
|
||||
|
|
|
@ -169,7 +169,7 @@ protected:
|
|||
|
||||
public:
|
||||
Image();
|
||||
explicit Image( const char *filename );
|
||||
explicit Image(const char *filename);
|
||||
Image(int p_width, int p_height, int p_colours, int p_subpixelorder, uint8_t *p_buffer=0, unsigned int padding=0);
|
||||
Image(int p_width, int p_linesize, int p_height, int p_colours, int p_subpixelorder, uint8_t *p_buffer=0, unsigned int padding=0);
|
||||
explicit Image( const Image &p_image );
|
||||
|
@ -222,19 +222,32 @@ public:
|
|||
width = linesize = height = colours = size = pixels = subpixelorder = 0;
|
||||
}
|
||||
|
||||
void Assign( unsigned int p_width, unsigned int p_height, unsigned int p_colours, unsigned int p_subpixelorder, const uint8_t* new_buffer, const size_t buffer_size);
|
||||
void Assign( const Image &image );
|
||||
void Assign( const AVFrame *frame );
|
||||
void AssignDirect( const unsigned int p_width, const unsigned int p_height, const unsigned int p_colours, const unsigned int p_subpixelorder, uint8_t *new_buffer, const size_t buffer_size, const int p_buffertype);
|
||||
void Assign(
|
||||
unsigned int p_width,
|
||||
unsigned int p_height,
|
||||
unsigned int p_colours,
|
||||
unsigned int p_subpixelorder,
|
||||
const uint8_t* new_buffer,
|
||||
const size_t buffer_size);
|
||||
void Assign(const Image &image);
|
||||
void Assign(const AVFrame *frame);
|
||||
void AssignDirect(
|
||||
const unsigned int p_width,
|
||||
const unsigned int p_height,
|
||||
const unsigned int p_colours,
|
||||
const unsigned int p_subpixelorder,
|
||||
uint8_t *new_buffer,
|
||||
const size_t buffer_size,
|
||||
const int p_buffertype);
|
||||
|
||||
inline void CopyBuffer( const Image &image ) {
|
||||
inline void CopyBuffer(const Image &image) {
|
||||
Assign(image);
|
||||
}
|
||||
inline Image &operator=( const Image &image ) {
|
||||
inline Image &operator=(const Image &image) {
|
||||
Assign(image);
|
||||
return *this;
|
||||
}
|
||||
inline Image &operator=( const unsigned char *new_buffer ) {
|
||||
inline Image &operator=(const unsigned char *new_buffer) {
|
||||
(*fptr_imgbufcpy)(buffer, new_buffer, size);
|
||||
return *this;
|
||||
}
|
||||
|
|
|
@ -96,7 +96,7 @@ std::string CameraType_Strings[] = {
|
|||
"VNC",
|
||||
};
|
||||
|
||||
Monitor::MonitorLink::MonitorLink(int p_id, const char *p_name) :
|
||||
Monitor::MonitorLink::MonitorLink(unsigned int p_id, const char *p_name) :
|
||||
id(p_id),
|
||||
shared_data(NULL),
|
||||
trigger_data(NULL),
|
||||
|
@ -900,7 +900,7 @@ bool Monitor::connect() {
|
|||
for ( int i = 0; i < image_buffer_count; i++ ) {
|
||||
image_buffer[i].image_index = i;
|
||||
image_buffer[i].timestamp = &(shared_timestamps[i]);
|
||||
image_buffer[i].image = new Image(width, camera->LineSize(), height, camera->Colours(), camera->SubpixelOrder(), &(shared_images[i*camera->ImageSize()]));
|
||||
image_buffer[i].image = new Image(width, height, camera->Colours(), camera->SubpixelOrder(), &(shared_images[i*camera->ImageSize()]));
|
||||
image_buffer[i].image->HoldBuffer(true); /* Don't release the internal buffer or replace it with another */
|
||||
}
|
||||
if ( deinterlacing_value == 4 ) {
|
||||
|
@ -1629,7 +1629,7 @@ void Monitor::CheckAction() {
|
|||
if ( auto_resume_time && (now.tv_sec >= auto_resume_time) ) {
|
||||
Info("Auto resuming at count %d", image_count);
|
||||
shared_data->active = true;
|
||||
ref_image = *(image_buffer[shared_data->last_write_index].image);
|
||||
ref_image.Assign(*(image_buffer[shared_data->last_write_index].image));
|
||||
ready_count = image_count+(warmup_count/2);
|
||||
auto_resume_time = 0;
|
||||
}
|
||||
|
@ -1727,6 +1727,7 @@ bool Monitor::Analyse() {
|
|||
} // end if trigger_on
|
||||
|
||||
if ( signal_change ) {
|
||||
Debug(1, "Signal change");
|
||||
const char *signalText;
|
||||
if ( !signal ) {
|
||||
signalText = "Lost";
|
||||
|
@ -1754,8 +1755,7 @@ bool Monitor::Analyse() {
|
|||
noteSetMap[SIGNAL_CAUSE] = noteSet;
|
||||
shared_data->state = state = IDLE;
|
||||
shared_data->active = signal;
|
||||
ref_image = *snap_image;
|
||||
|
||||
ref_image.Assign(*snap_image);
|
||||
}// else
|
||||
|
||||
if ( signal ) {
|
||||
|
@ -1767,8 +1767,8 @@ bool Monitor::Analyse() {
|
|||
if ( snap->image ) {
|
||||
|
||||
// Get new score.
|
||||
Debug(3,"before DetectMotion packet index is %d", snap->image_index);
|
||||
motion_score = DetectMotion( *snap_image, zoneSet );
|
||||
Debug(3, "before DetectMotion packet index is %d", snap->image_index);
|
||||
motion_score = DetectMotion(*snap_image, zoneSet);
|
||||
|
||||
Debug(3, "After motion detection, last_motion_score(%d), new motion score(%d)", last_motion_score, motion_score);
|
||||
} else {
|
||||
|
@ -2785,7 +2785,7 @@ Monitor::Orientation Monitor::getOrientation() const { return orientation; }
|
|||
|
||||
// Wait for camera to get an image, and then assign it as the base reference image. So this should be done as the first task in the analysis thread startup.
|
||||
void Monitor::get_ref_image() {
|
||||
ZMPacket * snap;
|
||||
ZMPacket *snap;
|
||||
while ( ( (!( snap = packetqueue->get_analysis_packet()))
|
||||
|| ( snap->packet.stream_index != video_stream_id ) )
|
||||
&& !zm_terminate) {
|
||||
|
@ -2797,7 +2797,7 @@ void Monitor::get_ref_image() {
|
|||
return;
|
||||
|
||||
ref_image.Assign(width, height, camera->Colours(), camera->SubpixelOrder(), snap->image->Buffer(), camera->ImageSize());
|
||||
Debug(2,"Have image about to unlock");
|
||||
Debug(2, "Have ref image about to unlock");
|
||||
snap->unlock();
|
||||
}
|
||||
|
||||
|
|
|
@ -216,10 +216,10 @@ protected:
|
|||
uint64_t last_event_id;
|
||||
|
||||
public:
|
||||
MonitorLink(int p_id, const char *p_name);
|
||||
MonitorLink(unsigned int p_id, const char *p_name);
|
||||
~MonitorLink();
|
||||
|
||||
inline int Id() const { return id; }
|
||||
inline unsigned int Id() const { return id; }
|
||||
inline const char *Name() const { return name; }
|
||||
|
||||
inline bool isConnected() const { return connected && shared_data->valid; }
|
||||
|
@ -393,7 +393,7 @@ protected:
|
|||
|
||||
public:
|
||||
explicit Monitor();
|
||||
explicit Monitor(int p_id);
|
||||
explicit Monitor(unsigned int p_id);
|
||||
|
||||
~Monitor();
|
||||
|
||||
|
@ -407,7 +407,7 @@ public:
|
|||
}
|
||||
Camera *getCamera();
|
||||
|
||||
inline int Id() const { return id; }
|
||||
inline unsigned int Id() const { return id; }
|
||||
inline const char *Name() const { return name; }
|
||||
inline Storage *getStorage() {
|
||||
if ( ! storage ) {
|
||||
|
@ -463,7 +463,7 @@ public:
|
|||
|
||||
int GetOptSaveJPEGs() const { return savejpegs; }
|
||||
VideoWriter GetOptVideoWriter() const { return videowriter; }
|
||||
const std::vector<EncoderParameter_t>* GetOptEncoderParams() const { return &encoderparamsvec; }
|
||||
//const std::vector<EncoderParameter_t>* GetEncoderParams() const { return &encoderparamsvec; }
|
||||
const std::string &GetEncoderOptions() const { return encoderparams; }
|
||||
const int OutputCodec() const { return output_codec; }
|
||||
const std::string &Encoder() const { return encoder; }
|
||||
|
|
|
@ -330,11 +330,12 @@ bool MonitorStream::sendFrame(const char *filepath, struct timeval *timestamp) {
|
|||
struct timeval frameStartTime;
|
||||
gettimeofday(&frameStartTime, NULL);
|
||||
|
||||
fputs("--" BOUNDARY "\r\nContent-Type: image/jpeg\r\n", stdout);
|
||||
fprintf(stdout, "Content-Length: %d\r\n"
|
||||
"X-Timestamp: %d.%06d\r\n"
|
||||
"\r\n", img_buffer_size, (int)timestamp->tv_sec, (int)timestamp->tv_usec);
|
||||
if ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) {
|
||||
if (
|
||||
(0 > fprintf(stdout, "Content-Length: %d\r\nX-Timestamp: %d.%06d\r\n\r\n",
|
||||
img_buffer_size, (int)timestamp->tv_sec, (int)timestamp->tv_usec))
|
||||
||
|
||||
(fwrite(img_buffer, img_buffer_size, 1, stdout) != 1)
|
||||
) {
|
||||
if ( !zm_terminate )
|
||||
Warning("Unable to send stream frame: %s", strerror(errno));
|
||||
return false;
|
||||
|
@ -390,7 +391,7 @@ bool MonitorStream::sendFrame(Image *image, struct timeval *timestamp) {
|
|||
gettimeofday(&frameStartTime, NULL);
|
||||
|
||||
fputs("--ZoneMinderFrame\r\n", stdout);
|
||||
switch( type ) {
|
||||
switch ( type ) {
|
||||
case STREAM_JPEG :
|
||||
send_image->EncodeJpeg(img_buffer, &img_buffer_size);
|
||||
fputs("Content-Type: image/jpeg\r\n", stdout);
|
||||
|
@ -415,10 +416,12 @@ bool MonitorStream::sendFrame(Image *image, struct timeval *timestamp) {
|
|||
Error("Unexpected frame type %d", type);
|
||||
return false;
|
||||
}
|
||||
fprintf(stdout, "Content-Length: %d\r\n"
|
||||
"X-Timestamp: %d.%06d\r\n"
|
||||
"\r\n", img_buffer_size, (int)timestamp->tv_sec, (int)timestamp->tv_usec);
|
||||
if ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) {
|
||||
if (
|
||||
( 0 > fprintf(stdout, "Content-Length: %d\r\nX-Timestamp: %d.%06d\r\n\r\n",
|
||||
img_buffer_size, (int)timestamp->tv_sec, (int)timestamp->tv_usec) )
|
||||
||
|
||||
(fwrite(img_buffer, img_buffer_size, 1, stdout) != 1)
|
||||
) {
|
||||
if ( !zm_terminate ) {
|
||||
// If the pipe was closed, we will get signalled SIGPIPE to exit, which will set zm_terminate
|
||||
Warning("Unable to send stream frame: %s", strerror(errno));
|
||||
|
|
|
@ -44,19 +44,17 @@ class MonitorStream : public StreamBase {
|
|||
time_t ttl;
|
||||
int playback_buffer;
|
||||
bool delayed;
|
||||
|
||||
int frame_count;
|
||||
|
||||
protected:
|
||||
bool checkSwapPath( const char *path, bool create_path );
|
||||
|
||||
bool sendFrame( const char *filepath, struct timeval *timestamp );
|
||||
bool sendFrame( Image *image, struct timeval *timestamp );
|
||||
void processCommand( const CmdMsg *msg );
|
||||
void SingleImage( int scale=100 );
|
||||
void SingleImageRaw( int scale=100 );
|
||||
bool checkSwapPath(const char *path, bool create_path);
|
||||
bool sendFrame(const char *filepath, struct timeval *timestamp);
|
||||
bool sendFrame(Image *image, struct timeval *timestamp);
|
||||
void processCommand(const CmdMsg *msg);
|
||||
void SingleImage(int scale=100);
|
||||
void SingleImageRaw(int scale=100);
|
||||
#ifdef HAVE_ZLIB_H
|
||||
void SingleImageZip( int scale=100 );
|
||||
void SingleImageZip(int scale=100);
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
@ -64,14 +62,14 @@ class MonitorStream : public StreamBase {
|
|||
temp_image_buffer(NULL), temp_image_buffer_count(0), temp_read_index(0), temp_write_index(0),
|
||||
ttl(0), playback_buffer(0), delayed(false), frame_count(0) {
|
||||
}
|
||||
void setStreamBuffer( int p_playback_buffer ) {
|
||||
void setStreamBuffer(int p_playback_buffer) {
|
||||
playback_buffer = p_playback_buffer;
|
||||
}
|
||||
void setStreamTTL( time_t p_ttl ) {
|
||||
void setStreamTTL(time_t p_ttl) {
|
||||
ttl = p_ttl;
|
||||
}
|
||||
bool setStreamStart( int monitor_id ) {
|
||||
return loadMonitor( monitor_id );
|
||||
bool setStreamStart(int monitor_id) {
|
||||
return loadMonitor(monitor_id);
|
||||
}
|
||||
void runStream();
|
||||
};
|
||||
|
|
|
@ -40,16 +40,7 @@ VideoStream::MimeData VideoStream::mime_data[] = {
|
|||
};
|
||||
|
||||
void VideoStream::Initialise( ) {
|
||||
if ( logDebugging() ) {
|
||||
av_log_set_level( AV_LOG_DEBUG );
|
||||
} else {
|
||||
av_log_set_level( AV_LOG_QUIET );
|
||||
}
|
||||
|
||||
av_register_all( );
|
||||
#if LIBAVFORMAT_VERSION_CHECK(53, 13, 0, 19, 0)
|
||||
avformat_network_init();
|
||||
#endif
|
||||
FFMPEGInit();
|
||||
initialised = true;
|
||||
}
|
||||
|
||||
|
@ -57,23 +48,23 @@ void VideoStream::SetupFormat( ) {
|
|||
/* allocate the output media context */
|
||||
ofc = NULL;
|
||||
#if (LIBAVFORMAT_VERSION_CHECK(53, 2, 0, 2, 0) && (LIBAVFORMAT_VERSION_MICRO >= 100))
|
||||
avformat_alloc_output_context2( &ofc, NULL, format, filename );
|
||||
avformat_alloc_output_context2(&ofc, NULL, format, filename);
|
||||
#else
|
||||
AVFormatContext *s= avformat_alloc_context();
|
||||
if(!s) {
|
||||
Fatal( "avformat_alloc_context failed %d \"%s\"", (size_t)ofc, av_err2str((size_t)ofc) );
|
||||
AVFormatContext *s = avformat_alloc_context();
|
||||
if ( !s ) {
|
||||
Fatal("avformat_alloc_context failed %d \"%s\"", (size_t)ofc, av_err2str((size_t)ofc));
|
||||
return;
|
||||
}
|
||||
|
||||
AVOutputFormat *oformat;
|
||||
if (format) {
|
||||
if ( format ) {
|
||||
#if LIBAVFORMAT_VERSION_CHECK(52, 45, 0, 45, 0)
|
||||
oformat = av_guess_format(format, NULL, NULL);
|
||||
#else
|
||||
oformat = guess_format(format, NULL, NULL);
|
||||
#endif
|
||||
if (!oformat) {
|
||||
Fatal( "Requested output format '%s' is not a suitable output format", format );
|
||||
if ( !oformat ) {
|
||||
Fatal("Requested output format '%s' is not a suitable output format", format);
|
||||
}
|
||||
} else {
|
||||
#if LIBAVFORMAT_VERSION_CHECK(52, 45, 0, 45, 0)
|
||||
|
@ -81,40 +72,40 @@ void VideoStream::SetupFormat( ) {
|
|||
#else
|
||||
oformat = guess_format(NULL, filename, NULL);
|
||||
#endif
|
||||
if (!oformat) {
|
||||
Fatal( "Unable to find a suitable output format for '%s'", format );
|
||||
if ( !oformat ) {
|
||||
Fatal("Unable to find a suitable output format for '%s'", format);
|
||||
}
|
||||
}
|
||||
s->oformat = oformat;
|
||||
|
||||
if (s->oformat->priv_data_size > 0) {
|
||||
if ( s->oformat->priv_data_size > 0 ) {
|
||||
s->priv_data = av_mallocz(s->oformat->priv_data_size);
|
||||
if ( !(s->priv_data) ) {
|
||||
Fatal( "Could not allocate private data for output format." );
|
||||
Fatal("Could not allocate private data for output format.");
|
||||
}
|
||||
#if LIBAVFORMAT_VERSION_CHECK(52, 92, 0, 92, 0)
|
||||
if (s->oformat->priv_class) {
|
||||
if ( s->oformat->priv_class ) {
|
||||
*(const AVClass**)s->priv_data = s->oformat->priv_class;
|
||||
av_opt_set_defaults(s->priv_data);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
Debug(1,"No allocating priv_data");
|
||||
Debug(1, "No allocating priv_data");
|
||||
s->priv_data = NULL;
|
||||
}
|
||||
|
||||
if ( filename ) {
|
||||
snprintf( s->filename, sizeof(s->filename), "%s", filename );
|
||||
snprintf(s->filename, sizeof(s->filename), "%s", filename);
|
||||
}
|
||||
|
||||
ofc = s;
|
||||
#endif
|
||||
if ( !ofc ) {
|
||||
Fatal( "avformat_alloc_..._context failed: %d", ofc );
|
||||
Fatal("avformat_alloc_..._context failed: %d", ofc);
|
||||
}
|
||||
|
||||
of = ofc->oformat;
|
||||
Debug( 1, "Using output format: %s (%s)", of->name, of->long_name );
|
||||
Debug(1, "Using output format: %s (%s)", of->name, of->long_name);
|
||||
}
|
||||
|
||||
void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int height, int bitrate, double frame_rate ) {
|
||||
|
@ -130,13 +121,13 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei
|
|||
}
|
||||
break;
|
||||
case ZM_COLOUR_RGB32:
|
||||
if(subpixelorder == ZM_SUBPIX_ORDER_ARGB) {
|
||||
if ( subpixelorder == ZM_SUBPIX_ORDER_ARGB ) {
|
||||
/* ARGB subpixel order */
|
||||
pf = AV_PIX_FMT_ARGB;
|
||||
} else if(subpixelorder == ZM_SUBPIX_ORDER_ABGR) {
|
||||
} else if ( subpixelorder == ZM_SUBPIX_ORDER_ABGR ) {
|
||||
/* ABGR subpixel order */
|
||||
pf = AV_PIX_FMT_ABGR;
|
||||
} else if(subpixelorder == ZM_SUBPIX_ORDER_BGRA) {
|
||||
} else if ( subpixelorder == ZM_SUBPIX_ORDER_BGRA ) {
|
||||
/* BGRA subpixel order */
|
||||
pf = AV_PIX_FMT_BGRA;
|
||||
} else {
|
||||
|
@ -152,7 +143,7 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei
|
|||
break;
|
||||
}
|
||||
|
||||
if ( strcmp( "rtp", of->name ) == 0 ) {
|
||||
if ( strcmp("rtp", of->name) == 0 ) {
|
||||
// RTP must have a packet_size.
|
||||
// Not sure what this value should be really...
|
||||
ofc->packet_size = width*height;
|
||||
|
@ -169,12 +160,12 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei
|
|||
AVCodec *a = avcodec_find_encoder_by_name(codec_name);
|
||||
if ( a ) {
|
||||
codec_id = a->id;
|
||||
Debug( 1, "Using codec \"%s\"", codec_name );
|
||||
Debug(1, "Using codec \"%s\"", codec_name);
|
||||
} else {
|
||||
#if (LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 11, 0) && (LIBAVFORMAT_VERSION_MICRO >= 100))
|
||||
Debug( 1, "Could not find codec \"%s\". Using default \"%s\"", codec_name, avcodec_get_name( codec_id ) );
|
||||
Debug(1, "Could not find codec \"%s\". Using default \"%s\"", codec_name, avcodec_get_name(codec_id));
|
||||
#else
|
||||
Debug( 1, "Could not find codec \"%s\". Using default \"%d\"", codec_name, codec_id );
|
||||
Debug(1, "Could not find codec \"%s\". Using default \"%d\"", codec_name, codec_id);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -183,19 +174,19 @@ void VideoStream::SetupCodec( int colours, int subpixelorder, int width, int hei
|
|||
and initialize the codecs */
|
||||
ost = NULL;
|
||||
if ( codec_id != AV_CODEC_ID_NONE ) {
|
||||
codec = avcodec_find_encoder( codec_id );
|
||||
codec = avcodec_find_encoder(codec_id);
|
||||
if ( !codec ) {
|
||||
#if (LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 11, 0) && (LIBAVFORMAT_VERSION_MICRO >= 100))
|
||||
Fatal( "Could not find encoder for '%s'", avcodec_get_name( codec_id ) );
|
||||
Fatal("Could not find encoder for '%s'", avcodec_get_name(codec_id));
|
||||
#else
|
||||
Fatal( "Could not find encoder for '%d'", codec_id );
|
||||
Fatal("Could not find encoder for '%d'", codec_id);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if (LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 11, 0) && (LIBAVFORMAT_VERSION_MICRO >= 100))
|
||||
Debug( 1, "Found encoder for '%s'", avcodec_get_name( codec_id ) );
|
||||
Debug(1, "Found encoder for '%s'", avcodec_get_name(codec_id));
|
||||
#else
|
||||
Debug( 1, "Found encoder for '%d'", codec_id );
|
||||
Debug(1, "Found encoder for '%d'", codec_id);
|
||||
#endif
|
||||
|
||||
#if LIBAVFORMAT_VERSION_CHECK(53, 10, 0, 17, 0)
|
||||
|
|
|
@ -588,8 +588,8 @@ int RemoteCameraHttp::GetResponse() {
|
|||
static char *content_type_header;
|
||||
static char *boundary_header;
|
||||
static char *authenticate_header;
|
||||
static char subcontent_length_header[32];
|
||||
static char subcontent_type_header[64];
|
||||
static char subcontent_length_header[33];
|
||||
static char subcontent_type_header[65];
|
||||
|
||||
static char http_version[16];
|
||||
static char status_code[16];
|
||||
|
@ -860,25 +860,37 @@ int RemoteCameraHttp::GetResponse() {
|
|||
}
|
||||
}
|
||||
|
||||
Debug( 6, "%d: %s", subheader_len, subheader_ptr );
|
||||
Debug(6, "%d: %s", subheader_len, subheader_ptr);
|
||||
|
||||
if ( (crlf = mempbrk( subheader_ptr, "\r\n", subheader_len )) ) {
|
||||
if ( (crlf = mempbrk(subheader_ptr, "\r\n", subheader_len)) ) {
|
||||
//subheaders[n_subheaders++] = subheader_ptr;
|
||||
n_subheaders++;
|
||||
|
||||
if ( !boundary_header && (strncasecmp( subheader_ptr, content_boundary, content_boundary_len ) == 0) ) {
|
||||
if ( !boundary_header && (strncasecmp(subheader_ptr, content_boundary, content_boundary_len) == 0) ) {
|
||||
boundary_header = subheader_ptr;
|
||||
Debug( 4, "Got boundary subheader '%s'", subheader_ptr );
|
||||
} else if ( !subcontent_length_header[0] && (strncasecmp( subheader_ptr, content_length_match, content_length_match_len) == 0) ) {
|
||||
strncpy( subcontent_length_header, subheader_ptr+content_length_match_len, sizeof(subcontent_length_header) );
|
||||
*(subcontent_length_header+strcspn( subcontent_length_header, "\r\n" )) = '\0';
|
||||
Debug( 4, "Got content length subheader '%s'", subcontent_length_header );
|
||||
Debug(4, "Got boundary subheader '%s'", subheader_ptr);
|
||||
} else if (
|
||||
!subcontent_length_header[0]
|
||||
&&
|
||||
(strncasecmp(subheader_ptr, content_length_match, content_length_match_len) == 0)
|
||||
) {
|
||||
strncpy(
|
||||
subcontent_length_header,
|
||||
subheader_ptr+content_length_match_len,
|
||||
sizeof(subcontent_length_header)-1
|
||||
);
|
||||
*(subcontent_length_header+strcspn(subcontent_length_header, "\r\n")) = '\0';
|
||||
Debug(4, "Got content length subheader '%s'", subcontent_length_header);
|
||||
} else if ( !subcontent_type_header[0] && (strncasecmp( subheader_ptr, content_type_match, content_type_match_len) == 0) ) {
|
||||
strncpy( subcontent_type_header, subheader_ptr+content_type_match_len, sizeof(subcontent_type_header) );
|
||||
*(subcontent_type_header+strcspn( subcontent_type_header, "\r\n" )) = '\0';
|
||||
Debug( 4, "Got content type subheader '%s'", subcontent_type_header );
|
||||
strncpy(
|
||||
subcontent_type_header,
|
||||
subheader_ptr+content_type_match_len,
|
||||
sizeof(subcontent_type_header)-1
|
||||
);
|
||||
*(subcontent_type_header+strcspn(subcontent_type_header, "\r\n")) = '\0';
|
||||
Debug(4, "Got content type subheader '%s'", subcontent_type_header);
|
||||
} else {
|
||||
Debug( 6, "Got ignored subheader '%s' found", subheader_ptr );
|
||||
Debug(6, "Got ignored subheader '%s' found", subheader_ptr);
|
||||
}
|
||||
subheader_ptr = crlf;
|
||||
subheader_len -= buffer.consume( subheader_ptr-(char *)buffer );
|
||||
|
|
|
@ -104,13 +104,13 @@ protected:
|
|||
CmdMsg msg;
|
||||
|
||||
protected:
|
||||
bool loadMonitor( int monitor_id );
|
||||
bool loadMonitor(int monitor_id);
|
||||
bool checkInitialised();
|
||||
void updateFrameRate( double fps );
|
||||
Image *prepareImage( Image *image );
|
||||
bool sendTextFrame( const char *text );
|
||||
void updateFrameRate(double fps);
|
||||
Image *prepareImage(Image *image);
|
||||
bool sendTextFrame(const char *text);
|
||||
bool checkCommandQueue();
|
||||
virtual void processCommand( const CmdMsg *msg )=0;
|
||||
virtual void processCommand(const CmdMsg *msg)=0;
|
||||
|
||||
public:
|
||||
StreamBase():
|
||||
|
@ -135,13 +135,12 @@ public:
|
|||
lock_fd(0),
|
||||
paused(false),
|
||||
step(0)
|
||||
|
||||
{
|
||||
memset( &loc_sock_path, 0, sizeof(loc_sock_path) );
|
||||
memset( &loc_addr, 0, sizeof(loc_addr) );
|
||||
memset( &rem_sock_path, 0, sizeof(rem_sock_path) );
|
||||
memset( &rem_addr, 0, sizeof(rem_addr) );
|
||||
memset( &sock_path_lock, 0, sizeof(sock_path_lock) );
|
||||
memset(&loc_sock_path, 0, sizeof(loc_sock_path));
|
||||
memset(&loc_addr, 0, sizeof(loc_addr));
|
||||
memset(&rem_sock_path, 0, sizeof(rem_sock_path));
|
||||
memset(&rem_addr, 0, sizeof(rem_addr));
|
||||
memset(&sock_path_lock, 0, sizeof(sock_path_lock));
|
||||
|
||||
base_fps = 0.0;
|
||||
effective_fps = 0.0;
|
||||
|
@ -156,28 +155,28 @@ public:
|
|||
}
|
||||
virtual ~StreamBase();
|
||||
|
||||
void setStreamType( StreamType p_type ) {
|
||||
void setStreamType(StreamType p_type) {
|
||||
type = p_type;
|
||||
}
|
||||
void setStreamFormat( const char *p_format ) {
|
||||
void setStreamFormat(const char *p_format) {
|
||||
format = p_format;
|
||||
}
|
||||
void setStreamScale( int p_scale ) {
|
||||
void setStreamScale(int p_scale) {
|
||||
scale = p_scale;
|
||||
if ( ! scale )
|
||||
if ( !scale )
|
||||
scale = DEFAULT_SCALE;
|
||||
}
|
||||
void setStreamReplayRate( int p_rate ) {
|
||||
Debug(2,"Setting replay_rate %d", p_rate);
|
||||
void setStreamReplayRate(int p_rate) {
|
||||
Debug(2, "Setting replay_rate %d", p_rate);
|
||||
replay_rate = p_rate;
|
||||
}
|
||||
void setStreamMaxFPS( double p_maxfps ) {
|
||||
void setStreamMaxFPS(double p_maxfps) {
|
||||
maxfps = p_maxfps;
|
||||
}
|
||||
void setStreamBitrate( int p_bitrate ) {
|
||||
void setStreamBitrate(int p_bitrate) {
|
||||
bitrate = p_bitrate;
|
||||
}
|
||||
void setStreamQueue( int p_connkey ) {
|
||||
void setStreamQueue(int p_connkey) {
|
||||
connkey = p_connkey;
|
||||
}
|
||||
virtual void openComms();
|
||||
|
|
|
@ -330,7 +330,7 @@ __attribute__((noinline,__target__("sse2")))
|
|||
#endif
|
||||
void* sse2_aligned_memcpy(void* dest, const void* src, size_t bytes) {
|
||||
#if ((defined(__i386__) || defined(__x86_64__) || defined(ZM_KEEP_SSE)) && !defined(ZM_STRIP_SSE))
|
||||
if(bytes > 128) {
|
||||
if ( bytes > 128 ) {
|
||||
unsigned int remainder = bytes % 128;
|
||||
const uint8_t* lastsrc = (uint8_t*)src + (bytes - remainder);
|
||||
|
||||
|
@ -372,7 +372,7 @@ void* sse2_aligned_memcpy(void* dest, const void* src, size_t bytes) {
|
|||
}
|
||||
#else
|
||||
/* Non x86\x86-64 platform, use memcpy */
|
||||
memcpy(dest,src,bytes);
|
||||
memcpy(dest, src, bytes);
|
||||
#endif
|
||||
return dest;
|
||||
}
|
||||
|
|
|
@ -450,21 +450,39 @@ bool VideoStore::open() {
|
|||
}
|
||||
|
||||
zm_dump_stream_format(oc, 0, 0, 1);
|
||||
if (audio_out_stream) zm_dump_stream_format(oc, 1, 0, 1);
|
||||
if ( audio_out_stream ) zm_dump_stream_format(oc, 1, 0, 1);
|
||||
|
||||
AVDictionary *opts = NULL;
|
||||
// av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0);
|
||||
// Shiboleth reports that this may break seeking in mp4 before it downloads
|
||||
av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);
|
||||
// av_dict_set(&opts, "movflags",
|
||||
// "frag_keyframe+empty_moov+default_base_moof", 0);
|
||||
|
||||
std::string option_string = monitor->GetEncoderOptions();
|
||||
ret = av_dict_parse_string(&opts, option_string.c_str(), "=", ",\n", 0);
|
||||
if ( ret < 0 ) {
|
||||
Warning("Could not parse ffmpeg output options '%s'", option_string.c_str());
|
||||
}
|
||||
|
||||
const AVDictionaryEntry *movflags_entry = av_dict_get(opts, "movflags", NULL, AV_DICT_MATCH_CASE);
|
||||
if ( !movflags_entry ) {
|
||||
Debug(1, "setting movflags to frag_keyframe+empty_moov");
|
||||
// av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0);
|
||||
// Shiboleth reports that this may break seeking in mp4 before it downloads
|
||||
av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);
|
||||
// av_dict_set(&opts, "movflags",
|
||||
// "frag_keyframe+empty_moov+default_base_moof", 0);
|
||||
} else {
|
||||
Debug(1, "using movflags %s", movflags_entry->value);
|
||||
}
|
||||
if ( (ret = avformat_write_header(oc, &opts)) < 0 ) {
|
||||
// if ((ret = avformat_write_header(oc, &opts)) < 0) {
|
||||
Warning("Unable to set movflags to frag_custom+dash+delay_moov");
|
||||
/* Write the stream header, if any. */
|
||||
Warning("Unable to set movflags trying with defaults.");
|
||||
ret = avformat_write_header(oc, NULL);
|
||||
} else if ( av_dict_count(opts) != 0 ) {
|
||||
Warning("some options not set");
|
||||
Info("some options not used, turn on debugging for a list.");
|
||||
AVDictionaryEntry *e = NULL;
|
||||
while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) {
|
||||
Debug(1, "Encoder Option %s=>%s", e->key, e->value);
|
||||
if ( !e->value ) {
|
||||
av_dict_set(&opts, e->key, NULL, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( opts ) av_dict_free(&opts);
|
||||
if ( ret < 0 ) {
|
||||
|
|
|
@ -122,7 +122,7 @@ void Zone::Setup(
|
|||
} else {
|
||||
diag_path[0] = 0;
|
||||
}
|
||||
} // end Zone::Setup
|
||||
} // end Zone::Setup
|
||||
|
||||
Zone::~Zone() {
|
||||
delete[] label;
|
||||
|
@ -131,7 +131,7 @@ Zone::~Zone() {
|
|||
delete[] ranges;
|
||||
}
|
||||
|
||||
void Zone::RecordStats( const Event *event ) {
|
||||
void Zone::RecordStats(const Event *event) {
|
||||
static char sql[ZM_SQL_MED_BUFSIZ];
|
||||
db_mutex.lock();
|
||||
snprintf(sql, sizeof(sql),
|
||||
|
@ -142,7 +142,7 @@ void Zone::RecordStats( const Event *event ) {
|
|||
Error("Can't insert event stats: %s", mysql_error(&dbconn));
|
||||
}
|
||||
db_mutex.unlock();
|
||||
} // end void Zone::RecordStats( const Event *event )
|
||||
} // end void Zone::RecordStats( const Event *event )
|
||||
|
||||
bool Zone::CheckOverloadCount() {
|
||||
if ( overload_count ) {
|
||||
|
@ -151,40 +151,40 @@ bool Zone::CheckOverloadCount() {
|
|||
return false;
|
||||
}
|
||||
return true;
|
||||
} // end bool Zone::CheckOverloadCount()
|
||||
} // end bool Zone::CheckOverloadCount()
|
||||
|
||||
void Zone::SetScore(unsigned int nScore) {
|
||||
score = nScore;
|
||||
} // end void Zone::SetScore(unsigned int nScore)
|
||||
} // end void Zone::SetScore(unsigned int nScore)
|
||||
|
||||
void Zone::SetAlarmImage(const Image* srcImage) {
|
||||
delete image;
|
||||
image = new Image(*srcImage);
|
||||
} // end void Zone::SetAlarmImage( const Image* srcImage )
|
||||
} // end void Zone::SetAlarmImage( const Image* srcImage )
|
||||
|
||||
int Zone::GetOverloadCount() {
|
||||
return overload_count;
|
||||
} // end int Zone::GetOverloadCount()
|
||||
} // end int Zone::GetOverloadCount()
|
||||
|
||||
void Zone::SetOverloadCount(int nOverCount) {
|
||||
overload_count = nOverCount;
|
||||
} // end void Zone::SetOverloadCount(int nOverCount )
|
||||
} // end void Zone::SetOverloadCount(int nOverCount )
|
||||
|
||||
int Zone::GetOverloadFrames() {
|
||||
return overload_frames;
|
||||
} // end int Zone::GetOverloadFrames
|
||||
} // end int Zone::GetOverloadFrames
|
||||
|
||||
int Zone::GetExtendAlarmCount() {
|
||||
return extend_alarm_count;
|
||||
} // end int Zone::GetExtendAlarmCount()
|
||||
} // end int Zone::GetExtendAlarmCount()
|
||||
|
||||
void Zone::SetExtendAlarmCount(int nExtendAlarmCount) {
|
||||
extend_alarm_count = nExtendAlarmCount;
|
||||
} // end void Zone::SetExtendAlarmCount( int nExtendAlarmCount )
|
||||
} // end void Zone::SetExtendAlarmCount( int nExtendAlarmCount )
|
||||
|
||||
int Zone::GetExtendAlarmFrames() {
|
||||
return extend_alarm_frames;
|
||||
} // end int Zone::GetExtendAlarmFrames()
|
||||
} // end int Zone::GetExtendAlarmFrames()
|
||||
|
||||
bool Zone::CheckExtendAlarmCount() {
|
||||
Info("ExtendAlarm count: %d, ExtendAlarm frames: %d", extend_alarm_count, extend_alarm_frames);
|
||||
|
@ -194,7 +194,7 @@ bool Zone::CheckExtendAlarmCount() {
|
|||
return true;
|
||||
}
|
||||
return false;
|
||||
} // end bool Zone::CheckExtendAlarmCount
|
||||
} // end bool Zone::CheckExtendAlarmCount
|
||||
|
||||
bool Zone::CheckAlarms(const Image *delta_image) {
|
||||
ResetStats();
|
||||
|
@ -985,10 +985,14 @@ bool Zone::DumpSettings(char *output, bool /*verbose*/) {
|
|||
sprintf( output+strlen(output), " Max Blob Pixels : %d\n", max_blob_pixels );
|
||||
sprintf( output+strlen(output), " Min Blobs : %d\n", min_blobs );
|
||||
sprintf( output+strlen(output), " Max Blobs : %d\n", max_blobs );
|
||||
return( true );
|
||||
return true;
|
||||
}
|
||||
|
||||
void Zone::std_alarmedpixels(Image* pdiff_image, const Image* ppoly_image, unsigned int* pixel_count, unsigned int* pixel_sum) {
|
||||
void Zone::std_alarmedpixels(
|
||||
Image* pdiff_image,
|
||||
const Image* ppoly_image,
|
||||
unsigned int* pixel_count,
|
||||
unsigned int* pixel_sum) {
|
||||
uint32_t pixelsalarmed = 0;
|
||||
uint32_t pixelsdifference = 0;
|
||||
uint8_t calc_max_pixel_threshold = 255;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
if ( $_REQUEST['entity'] == 'navBar' ) {
|
||||
global $bandwidth_options, $user;
|
||||
$data = array();
|
||||
if ( ZM_OPT_USE_AUTH && (ZM_AUTH_RELAY == 'hashed') ) {
|
||||
$auth_hash = generateAuthHash(ZM_AUTH_HASH_IPS);
|
||||
|
@ -7,7 +8,14 @@ if ( $_REQUEST['entity'] == 'navBar' ) {
|
|||
$data['auth'] = $auth_hash;
|
||||
}
|
||||
}
|
||||
$data['message'] = getNavBarHtml('reload');
|
||||
// Each widget on the navbar has its own function
|
||||
// Call the functions we want to dynamically update
|
||||
$data['getBandwidthHTML'] = getBandwidthHTML($bandwidth_options, $user);
|
||||
$data['getSysLoadHTML'] = getSysLoadHTML();
|
||||
$data['getDbConHTML'] = getDbConHTML();
|
||||
$data['getStorageHTML'] = getStorageHTML();
|
||||
$data['getShmHTML'] = getShmHTML();
|
||||
|
||||
ajaxResponse($data);
|
||||
return;
|
||||
}
|
||||
|
@ -246,7 +254,7 @@ function collectData() {
|
|||
if ( isset($elementData['sql']) )
|
||||
$fieldSql[] = $elementData['sql'].' as '.$element;
|
||||
else
|
||||
$fieldSql[] = $element;
|
||||
$fieldSql[] = '`'.$element.'`';
|
||||
if ( isset($elementData['table']) && isset($elementData['join']) ) {
|
||||
$joinSql[] = 'left join '.$elementData['table'].' on '.$elementData['join'];
|
||||
}
|
||||
|
@ -286,7 +294,7 @@ function collectData() {
|
|||
|
||||
preg_match('/^`?(\w+)`?\s*(ASC|DESC)?( NULLS FIRST)?$/i', $sort_field, $matches);
|
||||
if ( count($matches) ) {
|
||||
if ( in_array($matches[1], $fieldSql) ) {
|
||||
if ( in_array($matches[1], $fieldSql) or in_array('`'.$matches[1].'`', $fieldSql) ) {
|
||||
$sql .= $matches[1];
|
||||
} else {
|
||||
ZM\Error('Sort field '.$matches[1].' from ' .$sort_field.' not in SQL Fields: '.join(',', $sort_field));
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
echo json_encode($message);
|
||||
echo json_encode($zone);
|
|
@ -0,0 +1,2 @@
|
|||
echo json_encode($message);
|
||||
echo json_encode($zone);
|
|
@ -0,0 +1,2 @@
|
|||
$xml = Xml::fromArray(array('response'=>$message, 'zone'=>$zone));
|
||||
echo $xml->asXML();
|
|
@ -0,0 +1,2 @@
|
|||
$xml = Xml::fromArray(array('response' => $message, 'zone'=>$zone));
|
||||
echo $xml->asXML();
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -380,54 +380,54 @@ class Event extends ZM_Object {
|
|||
$Event = $this;
|
||||
$eventPath = $Event->Path();
|
||||
|
||||
if ( $frame and ! is_array($frame) ) {
|
||||
if ( $frame and !is_array($frame) ) {
|
||||
# Must be an Id
|
||||
Logger::Debug("Assuming that $frame is an Id");
|
||||
$frame = array( 'FrameId'=>$frame, 'Type'=>'', 'Delta'=>0 );
|
||||
$frame = array('FrameId'=>$frame, 'Type'=>'', 'Delta'=>0);
|
||||
}
|
||||
|
||||
if ( ( ! $frame ) and file_exists($eventPath.'/snapshot.jpg') ) {
|
||||
if ( ( !$frame ) and file_exists($eventPath.'/snapshot.jpg') ) {
|
||||
# No frame specified, so look for a snapshot to use
|
||||
$captImage = 'snapshot.jpg';
|
||||
Logger::Debug("Frame not specified, using snapshot");
|
||||
$frame = array('FrameId'=>'snapshot', 'Type'=>'','Delta'=>0);
|
||||
Logger::Debug('Frame not specified, using snapshot');
|
||||
$frame = array('FrameId'=>'snapshot', 'Type'=>'', 'Delta'=>0);
|
||||
} else {
|
||||
$captImage = sprintf( '%0'.ZM_EVENT_IMAGE_DIGITS.'d-analyze.jpg', $frame['FrameId'] );
|
||||
$captImage = sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d-analyze.jpg', $frame['FrameId']);
|
||||
if ( ! file_exists( $eventPath.'/'.$captImage ) ) {
|
||||
$captImage = sprintf( '%0'.ZM_EVENT_IMAGE_DIGITS.'d-capture.jpg', $frame['FrameId'] );
|
||||
if ( ! file_exists( $eventPath.'/'.$captImage ) ) {
|
||||
$captImage = sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d-capture.jpg', $frame['FrameId']);
|
||||
if ( !file_exists($eventPath.'/'.$captImage) ) {
|
||||
# Generate the frame JPG
|
||||
if ( $Event->DefaultVideo() ) {
|
||||
$videoPath = $eventPath.'/'.$Event->DefaultVideo();
|
||||
|
||||
if ( ! file_exists( $videoPath ) ) {
|
||||
Error("Event claims to have a video file, but it does not seem to exist at $videoPath" );
|
||||
if ( !file_exists($videoPath) ) {
|
||||
Error('Event claims to have a video file, but it does not seem to exist at '.$videoPath);
|
||||
return '';
|
||||
}
|
||||
|
||||
#$command ='ffmpeg -v 0 -i '.$videoPath.' -vf "select=gte(n\\,'.$frame['FrameId'].'),setpts=PTS-STARTPTS" '.$eventPath.'/'.$captImage;
|
||||
$command ='ffmpeg -ss '. $frame['Delta'] .' -i '.$videoPath.' -frames:v 1 '.$eventPath.'/'.$captImage;
|
||||
Logger::Debug( "Running $command" );
|
||||
Logger::Debug('Running '.$command);
|
||||
$output = array();
|
||||
$retval = 0;
|
||||
exec( $command, $output, $retval );
|
||||
exec($command, $output, $retval);
|
||||
Logger::Debug("Retval: $retval, output: " . implode("\n", $output));
|
||||
} else {
|
||||
Error("Can't create frame images from video because there is no video file for event ".$Event->Id().' at ' .$Event->Path() );
|
||||
Error('Can\'t create frame images from video because there is no video file for event '.$Event->Id().' at ' .$Event->Path());
|
||||
}
|
||||
} // end if capture file exists
|
||||
} // end if analyze file exists
|
||||
} // end if frame or snapshot
|
||||
|
||||
$captPath = $eventPath.'/'.$captImage;
|
||||
if ( ! file_exists($captPath) ) {
|
||||
Error("Capture file does not exist at $captPath");
|
||||
if ( !file_exists($captPath) ) {
|
||||
Error('Capture file does not exist at '.$captPath);
|
||||
}
|
||||
|
||||
$analImage = sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d-analyse.jpg', $frame['FrameId']);
|
||||
$analPath = $eventPath.'/'.$analImage;
|
||||
|
||||
$alarmFrame = $frame['Type']=='Alarm';
|
||||
$alarmFrame = $frame['Type'] == 'Alarm';
|
||||
|
||||
$hasAnalImage = $alarmFrame && file_exists($analPath) && filesize($analPath);
|
||||
$isAnalImage = $hasAnalImage && !$captureOnly;
|
||||
|
@ -443,8 +443,8 @@ class Event extends ZM_Object {
|
|||
$fraction = sprintf('%.3f', $scale/SCALE_BASE);
|
||||
$scale = (int)round($scale);
|
||||
|
||||
$thumbCaptPath = preg_replace( '/\.jpg$/', "-$scale.jpg", $captPath );
|
||||
$thumbAnalPath = preg_replace( '/\.jpg$/', "-$scale.jpg", $analPath );
|
||||
$thumbCaptPath = preg_replace('/\.jpg$/', "-$scale.jpg", $captPath);
|
||||
$thumbAnalPath = preg_replace('/\.jpg$/', "-$scale.jpg", $analPath);
|
||||
|
||||
if ( $isAnalImage ) {
|
||||
$imagePath = $analPath;
|
||||
|
@ -457,7 +457,7 @@ class Event extends ZM_Object {
|
|||
$thumbFile = $thumbPath;
|
||||
if ( $overwrite || ! file_exists($thumbFile) || ! filesize($thumbFile) ) {
|
||||
// Get new dimensions
|
||||
list( $imageWidth, $imageHeight ) = getimagesize($imagePath);
|
||||
list($imageWidth, $imageHeight) = getimagesize($imagePath);
|
||||
$thumbWidth = $imageWidth * $fraction;
|
||||
$thumbHeight = $imageHeight * $fraction;
|
||||
|
||||
|
@ -484,7 +484,7 @@ class Event extends ZM_Object {
|
|||
);
|
||||
|
||||
return $imageData;
|
||||
}
|
||||
} # getImageSrc
|
||||
|
||||
public function link_to($text=null) {
|
||||
if ( !$text )
|
||||
|
|
|
@ -42,7 +42,13 @@ class ZM_Object {
|
|||
if ( $type == 'set' and is_array($args[0]) ) {
|
||||
$this->{$fn} = implode(',', $args[0]);
|
||||
} else if ( array_key_exists($fn, $this->defaults) && is_array($this->defaults[$fn]) && isset($this->defaults[$fn]['filter_regexp']) ) {
|
||||
$this->{$fn} = preg_replace($this->defaults[$fn]['filter_regexp'], '', $args[0]);
|
||||
if ( is_array($this->defaults[$fn]['filter_regexp']) ) {
|
||||
foreach ( $this->defaults[$fn]['filter_regexp'] as $regexp ) {
|
||||
$this->{$fn} = preg_replace($regexp, '', $args[0]);
|
||||
}
|
||||
} else {
|
||||
$this->{$fn} = preg_replace($this->defaults[$fn]['filter_regexp'], '', $args[0]);
|
||||
}
|
||||
} else {
|
||||
$this->{$fn} = $args[0];
|
||||
}
|
||||
|
@ -147,7 +153,7 @@ class ZM_Object {
|
|||
public function to_json() {
|
||||
$json = array();
|
||||
foreach ($this->defaults as $key => $value) {
|
||||
if ( is_callable(array($this, $key)) ) {
|
||||
if ( is_callable(array($this, $key), false) ) {
|
||||
$json[$key] = $this->$key();
|
||||
} else if ( property_exists($this, $key) ) {
|
||||
$json[$key] = $this->{$key};
|
||||
|
@ -159,31 +165,37 @@ class ZM_Object {
|
|||
}
|
||||
|
||||
public function set($data) {
|
||||
foreach ( $data as $k => $v ) {
|
||||
if ( method_exists($this, $k) ) {
|
||||
$this->{$k}($v);
|
||||
foreach ( $data as $field => $value ) {
|
||||
if ( method_exists($this, $field) and is_callable(array($this, $field), false) ) {
|
||||
$this->$field($value);
|
||||
} else {
|
||||
if ( is_array($v) ) {
|
||||
if ( is_array($value) ) {
|
||||
# perhaps should turn into a comma-separated string
|
||||
$this->{$k} = implode(',', $v);
|
||||
} else if ( is_string($v) ) {
|
||||
if ( array_key_exists($k, $this->defaults) && is_array($this->defaults[$k]) && isset($this->defaults[$k]['filter_regexp']) ) {
|
||||
$this->{$k} = preg_replace($this->defaults[$k]['filter_regexp'], '', trim($v));
|
||||
$this->{$field} = implode(',', $value);
|
||||
} else if ( is_string($value) ) {
|
||||
if ( array_key_exists($field, $this->defaults) && is_array($this->defaults[$field]) && isset($this->defaults[$field]['filter_regexp']) ) {
|
||||
if ( is_array($this->defaults[$field]['filter_regexp']) ) {
|
||||
foreach ( $this->defaults[$field]['filter_regexp'] as $regexp ) {
|
||||
$this->{$field} = preg_replace($regexp, '', trim($value));
|
||||
}
|
||||
} else {
|
||||
$this->{$field} = preg_replace($this->defaults[$field]['filter_regexp'], '', trim($value));
|
||||
}
|
||||
} else {
|
||||
$this->{$k} = trim($v);
|
||||
$this->{$field} = trim($value);
|
||||
}
|
||||
} else if ( is_integer($v) ) {
|
||||
$this->{$k} = $v;
|
||||
} else if ( is_bool($v) ) {
|
||||
$this->{$k} = $v;
|
||||
} else if ( is_null($v) ) {
|
||||
$this->{$k} = $v;
|
||||
} else if ( is_integer($value) ) {
|
||||
$this->{$field} = $value;
|
||||
} else if ( is_bool($value) ) {
|
||||
$this->{$field} = $value;
|
||||
} else if ( is_null($value) ) {
|
||||
$this->{$field} = $value;
|
||||
} else {
|
||||
Error("Unknown type $k => $v of var " . gettype($v));
|
||||
$this->{$k} = $v;
|
||||
Error("Unknown type $field => $value of var " . gettype($value));
|
||||
$this->{$field} = $value;
|
||||
}
|
||||
} # end if method_exists
|
||||
} # end foreach $data as $k=>$v
|
||||
} # end foreach $data as $field=>$value
|
||||
} # end function set($data)
|
||||
|
||||
/* types is an array of fields telling use that the input might be a checkbox so not present in the input, but therefore has a value
|
||||
|
@ -211,11 +223,20 @@ class ZM_Object {
|
|||
foreach ( $new_values as $field => $value ) {
|
||||
|
||||
if ( method_exists($this, $field) ) {
|
||||
|
||||
if ( array_key_exists($field, $this->defaults) && is_array($this->defaults[$field]) && isset($this->defaults[$field]['filter_regexp']) ) {
|
||||
if ( is_array($this->defaults[$field]['filter_regexp']) ) {
|
||||
foreach ( $this->defaults[$field]['filter_regexp'] as $regexp ) {
|
||||
$value = preg_replace($regexp, '', trim($value));
|
||||
}
|
||||
} else {
|
||||
$value = preg_replace($this->defaults[$field]['filter_regexp'], '', trim($value));
|
||||
}
|
||||
}
|
||||
|
||||
$old_value = $this->$field();
|
||||
Logger::Debug("Checking method $field () ".print_r($old_value,true).' => ' . print_r($value,true));
|
||||
if ( is_array($old_value) ) {
|
||||
$diff = array_recursive_diff($old_value, $value);
|
||||
Logger::Debug("Checking method $field () diff isi ".print_r($diff,true));
|
||||
if ( count($diff) ) {
|
||||
$changes[$field] = $value;
|
||||
}
|
||||
|
@ -224,25 +245,26 @@ class ZM_Object {
|
|||
}
|
||||
} else if ( property_exists($this, $field) ) {
|
||||
$type = (array_key_exists($field, $this->defaults) && is_array($this->defaults[$field])) ? $this->defaults[$field]['type'] : 'scalar';
|
||||
Logger::Debug("Checking field $field => current ".
|
||||
(is_array($this->{$field}) ? implode(',',$this->{$field}) : $this->{$field}) . ' ?= ' .
|
||||
(is_array($value) ? implode(',', $value) : $value)
|
||||
);
|
||||
if ( $type == 'set' ) {
|
||||
$old_value = is_array($this->$field) ? $this->$field : explode(',', $this->$field);
|
||||
$new_value = is_array($value) ? $value : explode(',', $value);
|
||||
|
||||
$diff = array_recursive_diff($old_value, $new_value);
|
||||
Logger::Debug("Checking value $field () diff isi ".print_r($diff,true));
|
||||
if ( count($diff) ) {
|
||||
$changes[$field] = $new_value;
|
||||
}
|
||||
|
||||
# Input might be a command separated string, or an array
|
||||
|
||||
|
||||
} else {
|
||||
if ( array_key_exists($field, $this->defaults) && is_array($this->defaults[$field]) && isset($this->defaults[$field]['filter_regexp']) ) {
|
||||
$value = preg_replace($this->defaults[$field]['filter_regexp'], '', trim($value));
|
||||
if ( is_array($this->defaults[$field]['filter_regexp']) ) {
|
||||
foreach ( $this->defaults[$field]['filter_regexp'] as $regexp ) {
|
||||
$value = preg_replace($regexp, '', trim($value));
|
||||
}
|
||||
} else {
|
||||
$value = preg_replace($this->defaults[$field]['filter_regexp'], '', trim($value));
|
||||
}
|
||||
}
|
||||
if ( $this->{$field} != $value ) {
|
||||
$changes[$field] = $value;
|
||||
|
@ -255,11 +277,6 @@ class ZM_Object {
|
|||
$default = $this->defaults[$field];
|
||||
}
|
||||
|
||||
Logger::Debug("Checking default $field => ".
|
||||
( is_array($default) ? implode(',',$default) : $default).
|
||||
' ' .
|
||||
( is_array($value) ? implode(',', $value) : $value)
|
||||
);
|
||||
if ( $default != $value ) {
|
||||
$changes[$field] = $value;
|
||||
}
|
||||
|
@ -275,7 +292,6 @@ class ZM_Object {
|
|||
$table = $class::$table;
|
||||
|
||||
if ( $new_values ) {
|
||||
//Logger::Debug("New values" . print_r($new_values, true));
|
||||
$this->set($new_values);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ class Storage extends ZM_Object {
|
|||
protected static $table = 'Storage';
|
||||
protected $defaults = array(
|
||||
'Id' => null,
|
||||
'Path' => '',
|
||||
'Path' => array('type'=>'text','filter_regexp'=>array('/[^\w\-\.\(\)\:\/ ]/','/\/$/')),
|
||||
'Name' => '',
|
||||
'Type' => 'local',
|
||||
'Url' => '',
|
||||
|
@ -26,7 +26,8 @@ class Storage extends ZM_Object {
|
|||
return ZM_Object::_find_one(get_class(), $parameters, $options);
|
||||
}
|
||||
|
||||
public function Path() {
|
||||
public function Path($new=null) {
|
||||
if ( $new ) $this->{'Path'} = $new;
|
||||
if ( isset($this->{'Path'}) and ( $this->{'Path'} != '' ) ) {
|
||||
return $this->{'Path'};
|
||||
} else if ( ! isset($this->{'Id'}) ) {
|
||||
|
@ -40,7 +41,9 @@ class Storage extends ZM_Object {
|
|||
}
|
||||
return $this->{'Name'};
|
||||
}
|
||||
public function Name() {
|
||||
public function Name($new=null) {
|
||||
if ( $new )
|
||||
$this->{'Name'} = $new;
|
||||
if ( isset($this->{'Name'}) and ( $this->{'Name'} != '' ) ) {
|
||||
return $this->{'Name'};
|
||||
} else if ( ! isset($this->{'Id'}) ) {
|
||||
|
|
|
@ -19,31 +19,22 @@
|
|||
//
|
||||
|
||||
// System edit actions
|
||||
if ( ! canEdit('System') ) {
|
||||
if ( !canEdit('System') ) {
|
||||
ZM\Warning('Need System permission to edit Storage');
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $action == 'Save' ) {
|
||||
if ( !empty($_REQUEST['id']) )
|
||||
$dbStorage = dbFetchOne('SELECT * FROM Storage WHERE Id=?', NULL, array($_REQUEST['id']));
|
||||
else
|
||||
$dbStorage = array();
|
||||
$storage = new ZM\Storage($_REQUEST['id']);
|
||||
|
||||
$types = array();
|
||||
$changes = getFormChanges($dbStorage, $_REQUEST['newStorage'], $types);
|
||||
$changes = $storage->changes($_REQUEST['newStorage']);
|
||||
|
||||
if ( count($changes) ) {
|
||||
if ( !empty($_REQUEST['id']) ) {
|
||||
dbQuery('UPDATE Storage SET '.implode(', ', $changes).' WHERE Id = ?', array($_REQUEST['id']));
|
||||
} else {
|
||||
dbQuery('INSERT INTO Storage set '.implode(', ', $changes));
|
||||
}
|
||||
$storage->save($changes);
|
||||
$refreshParent = true;
|
||||
}
|
||||
$view = 'none';
|
||||
} else {
|
||||
ZM\Error("Unknown action $action in saving Storage");
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
|
@ -585,14 +585,14 @@ function getFormChanges($values, $newValues, $types=false, $columns=false) {
|
|||
if ( !$types )
|
||||
$types = array();
|
||||
|
||||
foreach( $newValues as $key=>$value ) {
|
||||
foreach ( $newValues as $key=>$value ) {
|
||||
if ( $columns && !isset($columns[$key]) )
|
||||
continue;
|
||||
|
||||
if ( !isset($types[$key]) )
|
||||
$types[$key] = false;
|
||||
|
||||
switch( $types[$key] ) {
|
||||
switch ( $types[$key] ) {
|
||||
case 'set' :
|
||||
if ( is_array($newValues[$key]) ) {
|
||||
if ( (!isset($values[$key])) or ( join(',',$newValues[$key]) != $values[$key] ) ) {
|
||||
|
@ -669,6 +669,7 @@ function getFormChanges($values, $newValues, $types=false, $columns=false) {
|
|||
break;
|
||||
} // end switch
|
||||
} // end foreach newvalues
|
||||
|
||||
foreach ( $values as $key=>$value ) {
|
||||
if ( !empty($columns[$key]) ) {
|
||||
if ( !empty($types[$key]) ) {
|
||||
|
@ -2096,18 +2097,23 @@ function isVector(&$array) {
|
|||
|
||||
function checkJsonError($value) {
|
||||
if ( function_exists('json_last_error') ) {
|
||||
$value = var_export($value,true);
|
||||
switch( json_last_error() ) {
|
||||
$value = var_export($value, true);
|
||||
switch ( json_last_error() ) {
|
||||
case JSON_ERROR_DEPTH :
|
||||
ZM\Fatal("Unable to decode JSON string '$value', maximum stack depth exceeded");
|
||||
ZM\Error("Unable to decode JSON string '$value', maximum stack depth exceeded");
|
||||
break;
|
||||
case JSON_ERROR_CTRL_CHAR :
|
||||
ZM\Fatal("Unable to decode JSON string '$value', unexpected control character found");
|
||||
ZM\Error("Unable to decode JSON string '$value', unexpected control character found");
|
||||
break;
|
||||
case JSON_ERROR_STATE_MISMATCH :
|
||||
ZM\Fatal("Unable to decode JSON string '$value', invalid or malformed JSON");
|
||||
ZM\Error("Unable to decode JSON string '$value', invalid or malformed JSON");
|
||||
break;
|
||||
case JSON_ERROR_SYNTAX :
|
||||
ZM\Fatal("Unable to decode JSON string '$value', syntax error");
|
||||
ZM\Error("Unable to decode JSON string '$value', syntax error");
|
||||
break;
|
||||
default :
|
||||
ZM\Fatal("Unable to decode JSON string '$value', unexpected error ".json_last_error());
|
||||
ZM\Error("Unable to decode JSON string '$value', unexpected error ".json_last_error());
|
||||
break;
|
||||
case JSON_ERROR_NONE:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1,35 +1,33 @@
|
|||
<?php
|
||||
// ZM session start function support timestamp management
|
||||
function zm_session_start() {
|
||||
// Make sure use_strict_mode is enabled.
|
||||
// use_strict_mode is mandatory for security reasons.
|
||||
ini_set('session.use_strict_mode', 1);
|
||||
|
||||
$currentCookieParams = session_get_cookie_params();
|
||||
$currentCookieParams['lifetime'] = ZM_COOKIE_LIFETIME;
|
||||
if ( ini_get('session.name') != 'ZMSESSID' ) {
|
||||
// Make sure use_strict_mode is enabled.
|
||||
// use_strict_mode is mandatory for security reasons.
|
||||
ini_set('session.use_strict_mode', 1);
|
||||
|
||||
session_set_cookie_params(
|
||||
$currentCookieParams['lifetime'],
|
||||
$currentCookieParams['path'],
|
||||
$currentCookieParams['domain'],
|
||||
$currentCookieParams['secure'],
|
||||
true
|
||||
);
|
||||
$currentCookieParams = session_get_cookie_params();
|
||||
$currentCookieParams['lifetime'] = ZM_COOKIE_LIFETIME;
|
||||
$currentCookieParams['httponly'] = true;
|
||||
$currentCookieParams['samesite'] = 'Strict';
|
||||
|
||||
ini_set('session.name', 'ZMSESSID');
|
||||
ZM\Logger::Debug('Setting cookie parameters to lifetime('.$currentCookieParams['lifetime'].') path('.$currentCookieParams['path'].') domain ('.$currentCookieParams['domain'].') secure('.$currentCookieParams['secure'].') httpOnly(1) name:'.session_name());
|
||||
session_set_cookie_params($currentCookieParams);
|
||||
|
||||
ini_set('session.name', 'ZMSESSID');
|
||||
ZM\Logger::Debug('Setting cookie parameters to '.print_r($currentCookieParams, true));
|
||||
}
|
||||
session_start();
|
||||
$_SESSION['remoteAddr'] = $_SERVER['REMOTE_ADDR']; // To help prevent session hijacking
|
||||
$now = time();
|
||||
// Do not allow to use expired session ID
|
||||
if ( !empty($_SESSION['last_time']) && ($_SESSION['last_time'] < ($now - 180)) ) {
|
||||
ZM\Info('Destroying session due to timeout. ');
|
||||
ZM\Info('Destroying session due to timeout.');
|
||||
session_destroy();
|
||||
session_start();
|
||||
} else if ( !empty($_SESSION['generated_at']) ) {
|
||||
if ( $_SESSION['generated_at']<($now-(ZM_COOKIE_LIFETIME/2)) ) {
|
||||
ZM\Logger::Debug("Regenerating session because generated_at " . $_SESSION['generated_at'] . ' < ' . $now . '-'.ZM_COOKIE_LIFETIME.'/2 = '.($now-ZM_COOKIE_LIFETIME/2));
|
||||
ZM\Logger::Debug('Regenerating session because generated_at ' . $_SESSION['generated_at'] . ' < ' . $now . '-'.ZM_COOKIE_LIFETIME.'/2 = '.($now-ZM_COOKIE_LIFETIME/2));
|
||||
zm_session_regenerate_id();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -993,6 +993,18 @@ $OLANG = array(
|
|||
"loglevel=debug" Set verbosity of FFmpeg (quiet, panic, fatal, error, warning, info, verbose, debug)
|
||||
'
|
||||
),
|
||||
'OPTIONS_ENCODER_PARAMETERS' => array(
|
||||
'Help' => '
|
||||
Parameters passed to the encoding codec. name=value separated by either , or newline.~~
|
||||
For example to changing quality, use the crf option. 1 is best, 51 is worst 23 is default.~~
|
||||
~~
|
||||
crf=23~~
|
||||
~~
|
||||
You might want to alter the movflags value to support different behaviours. Some people have troubles viewing videos due to the frag_keyframe option, but that option is supposed to allow viewing of incomplete events. See
|
||||
[https://ffmpeg.org/ffmpeg-formats.html](https://ffmpeg.org/ffmpeg-formats.html)
|
||||
for more information. ZoneMinder\'s default is frag_keyframe,empty_moov~~
|
||||
',
|
||||
),
|
||||
'OPTIONS_DECODERHWACCELNAME' => array(
|
||||
'Help' => '
|
||||
This is equivalent to the ffmpeg -hwaccel command line option. With intel graphics support, use "vaapi". For NVIDIA cuda support use "cuda". To check for support, run ffmpeg -hwaccels on the command line.'
|
||||
|
|
|
@ -662,6 +662,11 @@ margin-left: 0;
|
|||
.nav-pills > li > a {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
ul.nav.nav-pills.flex-column {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.chosen-container {
|
||||
text-align: left;
|
||||
}
|
||||
|
@ -704,3 +709,7 @@ li.search-choice {
|
|||
.form-check-inline {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#dropdown_storage {
|
||||
background-color:#485460;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
textarea,
|
||||
input[name="newMonitor[Name]"],
|
||||
input[name="newMonitor[LabelFormat]"],
|
||||
input[name="newMonitor[ControlDevice]"],
|
||||
input[name="newMonitor[ControlAddress]"] {
|
||||
width: 100%;
|
||||
|
|
|
@ -26,3 +26,7 @@ input[name="newConfig[ZM_OPT_GOOG_RECAPTCHA_SITEKEY]"],
|
|||
input[name="newConfig[ZM_OPT_GOOG_RECAPTCHA_SECRETKEY]"] {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#options label {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
|
|
@ -4,11 +4,13 @@
|
|||
}
|
||||
#settingsPanel,
|
||||
#zonePoints {
|
||||
width: 600px;
|
||||
max-width: 600px;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
#zoneSettings {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#zoneSettings th,
|
||||
|
@ -132,5 +134,22 @@ width: 100%;
|
|||
input[name="newAlarmRgbR"],
|
||||
input[name="newAlarmRgbG"],
|
||||
input[name="newAlarmRgbB"] {
|
||||
width: 30%;
|
||||
width: 25%;
|
||||
}
|
||||
input[name="newZone[MinPixelThreshold]"],
|
||||
input[name="newZone[MaxPixelThreshold]"],
|
||||
input[name="newZone[FilterX]"],
|
||||
input[name="newZone[FilterY]"],
|
||||
input[name="newZone[MinFilterPixels]"],
|
||||
input[name="newZone[MaxFilterPixels]"],
|
||||
input[name="newZone[MinBlobPixels]"],
|
||||
input[name="newZone[MaxBlobPixels]"],
|
||||
input[name="newZone[MinBlobs]"],
|
||||
input[name="newZone[MaxBlobs]"],
|
||||
input[name="newZone[MinAlarmPixels]"],
|
||||
input[name="newZone[MaxAlarmPixels]"] {
|
||||
width: 90px;
|
||||
}
|
||||
input.ZonePoint {
|
||||
width: 75px;
|
||||
}
|
||||
|
|
|
@ -492,6 +492,10 @@ margin-left: 0px;
|
|||
border-radius: 0;
|
||||
}
|
||||
|
||||
.nav-pills .nav-link.active, .nav-pills .show>.nav-link {
|
||||
background-color: #337ab7;
|
||||
}
|
||||
|
||||
button,
|
||||
input[type=button],
|
||||
input[type=submit],
|
||||
|
|
|
@ -18,11 +18,13 @@
|
|||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
//
|
||||
|
||||
|
||||
function xhtmlHeaders($file, $title) {
|
||||
ob_start();
|
||||
|
||||
global $css;
|
||||
global $skin;
|
||||
global $view;
|
||||
global $cspNonce;
|
||||
|
||||
# This idea is that we always include the classic css files,
|
||||
# and then any different skin only needs to contain things that are different.
|
||||
|
@ -40,8 +42,6 @@ function xhtmlHeaders($file, $title) {
|
|||
$viewJsFile = getSkinFile('views/js/'.$basename.'.js');
|
||||
$viewJsPhpFile = getSkinFile('views/js/'.$basename.'.js.php');
|
||||
|
||||
extract($GLOBALS, EXTR_OVERWRITE);
|
||||
|
||||
function output_link_if_exists($files) {
|
||||
global $skin;
|
||||
$html = array();
|
||||
|
@ -50,7 +50,17 @@ function xhtmlHeaders($file, $title) {
|
|||
$html[] = '<link rel="stylesheet" href="'.cache_bust('skins/'.$skin.'/'.$file).'" type="text/css"/>';
|
||||
}
|
||||
}
|
||||
return implode("\n", $html);
|
||||
$html[] = ''; // So we ge a trailing \n
|
||||
return implode(PHP_EOL, $html);
|
||||
}
|
||||
|
||||
function output_cache_busted_stylesheet_links($files) {
|
||||
$html = array();
|
||||
foreach ( $files as $file ) {
|
||||
$html[] = '<link rel="stylesheet" href="'.cache_bust($file).'" type="text/css"/>';
|
||||
}
|
||||
$html[] = ''; // So we ge a trailing \n
|
||||
return implode(PHP_EOL, $html);
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
|
@ -58,10 +68,10 @@ function xhtmlHeaders($file, $title) {
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title><?php echo validHtmlStr(ZM_WEB_TITLE_PREFIX); ?> - <?php echo validHtmlStr($title) ?></title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title><?php echo validHtmlStr(ZM_WEB_TITLE_PREFIX) . ' - ' . validHtmlStr($title) ?></title>
|
||||
<?php
|
||||
if ( file_exists( "skins/$skin/css/$css/graphics/favicon.ico" ) ) {
|
||||
if ( file_exists("skins/$skin/css/$css/graphics/favicon.ico") ) {
|
||||
echo "
|
||||
<link rel=\"icon\" type=\"image/ico\" href=\"skins/$skin/css/$css/graphics/favicon.ico\"/>
|
||||
<link rel=\"shortcut icon\" href=\"skins/$skin/css/$css/graphics/favicon.ico\"/>
|
||||
|
@ -72,31 +82,28 @@ if ( file_exists( "skins/$skin/css/$css/graphics/favicon.ico" ) ) {
|
|||
<link rel="shortcut icon" href="graphics/favicon.ico"/>
|
||||
';
|
||||
}
|
||||
?>
|
||||
<link rel="stylesheet" href="css/reset.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="css/overlay.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="css/bootstrap.min.css" type="text/css"/>
|
||||
|
||||
<?php
|
||||
echo output_link_if_exists( array(
|
||||
echo output_cache_busted_stylesheet_links(array(
|
||||
'css/reset.css',
|
||||
'css/overlay.css',
|
||||
'css/bootstrap.min.css',
|
||||
));
|
||||
|
||||
echo output_link_if_exists(array(
|
||||
'css/base/skin.css',
|
||||
'css/base/views/'.$basename.'.css',
|
||||
'js/dateTimePicker/jquery-ui-timepicker-addon.css',
|
||||
'js/jquery-ui-1.12.1/jquery-ui.structure.min.css',
|
||||
)
|
||||
);
|
||||
));
|
||||
if ( $css != 'base' )
|
||||
echo output_link_if_exists( array(
|
||||
echo output_link_if_exists(array(
|
||||
'css/'.$css.'/skin.css',
|
||||
'css/'.$css.'/views/'.$basename.'.css',
|
||||
'css/'.$css.'/jquery-ui-theme.css',
|
||||
)
|
||||
);
|
||||
));
|
||||
?>
|
||||
|
||||
<link rel="stylesheet" href="skins/classic/js/jquery-ui-1.12.1/jquery-ui.theme.min.css" type="text/css"/>
|
||||
<!--Chosen can't be cache-busted because it loads sprites by relative path-->
|
||||
<link rel="stylesheet" href="skins/classic/js/chosen/chosen.min.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="skins/classic/js/jquery-ui-1.12.1/jquery-ui.theme.min.css" type="text/css"/>
|
||||
<?php #Chosen can't be cache-busted because it loads sprites by relative path ?>
|
||||
<link rel="stylesheet" href="skins/classic/js/chosen/chosen.min.css" type="text/css"/>
|
||||
<?php
|
||||
if ( $basename == 'watch' ) {
|
||||
echo output_link_if_exists(array('/css/base/views/control.css'));
|
||||
|
@ -114,10 +121,8 @@ if ( $css != 'base' )
|
|||
}
|
||||
?>
|
||||
</style>
|
||||
<?php
|
||||
?>
|
||||
|
||||
<?php if ( $basename != 'login' ) { ?>
|
||||
<?php if ( $basename != 'login' and $basename != 'postlogin' ) { ?>
|
||||
<script src="tools/mootools/mootools-core.js"></script>
|
||||
<script src="tools/mootools/mootools-more.js"></script>
|
||||
<script src="js/mootools.ext.js"></script>
|
||||
|
@ -131,6 +136,22 @@ if ( $css != 'base' )
|
|||
<script src="<?php echo cache_bust('js/Server.js'); ?>"></script>
|
||||
<script nonce="<?php echo $cspNonce; ?>">
|
||||
jQuery(document).ready(function() {
|
||||
// Workaround Bootstrap-Mootools conflict
|
||||
var bootstrapLoaded = (typeof jQuery().carousel == 'function');
|
||||
var mootoolsLoaded = (typeof MooTools != 'undefined');
|
||||
if (bootstrapLoaded && mootoolsLoaded) {
|
||||
Element.implement({
|
||||
hide: function() {
|
||||
return this;
|
||||
},
|
||||
show: function(v) {
|
||||
return this;
|
||||
},
|
||||
slide: function(v) {
|
||||
return this;
|
||||
}
|
||||
});
|
||||
}
|
||||
jQuery("#flip").click(function() {
|
||||
jQuery("#panel").slideToggle("slow");
|
||||
var flip = jQuery("#flip");
|
||||
|
@ -142,6 +163,26 @@ if ( $css != 'base' )
|
|||
Cookie.write('zmHeaderFlip', 'up', {duration: 10*365} );
|
||||
}
|
||||
});
|
||||
jQuery("#fbflip").click(function() {
|
||||
jQuery("#fbpanel").slideToggle("slow");
|
||||
var fbflip = jQuery("#fbflip");
|
||||
if ( fbflip.html() == 'keyboard_arrow_up' ) {
|
||||
fbflip.html('keyboard_arrow_down');
|
||||
Cookie.write('zmFilterBarFlip', 'down', {duration: 10*365} );
|
||||
} else {
|
||||
fbflip.html('keyboard_arrow_up');
|
||||
Cookie.write('zmFilterBarFlip', 'up', {duration: 10*365} );
|
||||
jQuery('.chosen').chosen("destroy");
|
||||
jQuery('.chosen').chosen();
|
||||
}
|
||||
});
|
||||
jQuery(document).click(function(event) {
|
||||
var target = jQuery(event.target);
|
||||
var _mobileMenuOpen = jQuery("#main-header-nav").hasClass("show");
|
||||
if (_mobileMenuOpen === true && !target.hasClass("navbar-toggler")) {
|
||||
jQuery("button.navbar-toggler").click();
|
||||
}
|
||||
});
|
||||
});
|
||||
var $j = jQuery.noConflict();
|
||||
// $j is now an alias to the jQuery function; creating the new alias is optional.
|
||||
|
@ -204,6 +245,7 @@ if ( $css != 'base' )
|
|||
?>
|
||||
</head>
|
||||
<?php
|
||||
echo ob_get_clean();
|
||||
} // end function xhtmlHeaders( $file, $title )
|
||||
|
||||
// Outputs an opening body tag, and any additional content that should go at the very top, like warnings and error messages.
|
||||
|
@ -223,12 +265,11 @@ function getBodyTopHTML() {
|
|||
}
|
||||
} // end function getBodyTopHTML
|
||||
|
||||
function getNavBarHTML($reload = null) {
|
||||
function getNavBarHTML() {
|
||||
# Provide a facility to turn off the headers if you put navbar=0 into the url
|
||||
if ( isset($_REQUEST['navbar']) and $_REQUEST['navbar']=='0' )
|
||||
if ( isset($_REQUEST['navbar']) and $_REQUEST['navbar'] == '0' )
|
||||
return '';
|
||||
|
||||
$versionClass = (ZM_DYN_DB_VERSION&&(ZM_DYN_DB_VERSION!=ZM_VERSION))?'errorText':'';
|
||||
global $running;
|
||||
global $user;
|
||||
global $bandwidth_options;
|
||||
|
@ -237,88 +278,465 @@ function getNavBarHTML($reload = null) {
|
|||
global $sortQuery;
|
||||
global $limitQuery;
|
||||
|
||||
if (!$sortQuery) {
|
||||
if ( !$sortQuery ) {
|
||||
parseSort();
|
||||
}
|
||||
if ( (!$filterQuery) and isset($_REQUEST['filter']) ) {
|
||||
parseFilter($_REQUEST['filter']);
|
||||
$filterQuery = $_REQUEST['filter']['query'];
|
||||
}
|
||||
if ( $reload === null ) {
|
||||
ob_start();
|
||||
if ( $running == null )
|
||||
$running = daemonCheck();
|
||||
if ( $running ) {
|
||||
$state = dbFetchOne('SELECT Name FROM States WHERE isActive=1', 'Name');
|
||||
if ( $state == 'default' )
|
||||
$state = '';
|
||||
}
|
||||
$status = $running ? ($state ? $state : translate('Running')) : translate('Stopped');
|
||||
?>
|
||||
<div class="navbar navbar-inverse navbar-static-top">
|
||||
<div class="container-fluid">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#main-header-nav" aria-expanded="false">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<div class="navbar-brand">
|
||||
<a href="<?php echo validHtmlStr(ZM_HOME_URL); ?>" target="<?php echo validHtmlStr(ZM_WEB_TITLE); ?>"><?php echo ZM_HOME_CONTENT ?></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="collapse navbar-collapse" id="main-header-nav">
|
||||
<ul class="nav navbar-nav">
|
||||
<?php
|
||||
if ( $user and $user['Username'] ) {
|
||||
if ( canView('Monitors') ) {
|
||||
ob_start();
|
||||
|
||||
if ( ZM_WEB_NAVBAR_TYPE == "normal" ) {
|
||||
echo getNormalNavBarHTML($running, $user, $bandwidth_options, $view, $filterQuery, $sortQuery, $limitQuery);
|
||||
} else {
|
||||
echo getCollapsedNavBarHTML($running, $user, $bandwidth_options, $view, $filterQuery, $sortQuery, $limitQuery);
|
||||
}
|
||||
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
//
|
||||
// The legacy navigation bar that collapses into a pulldown menu on small screens.
|
||||
//
|
||||
function getNormalNavBarHTML($running, $user, $bandwidth_options, $view, $filterQuery, $sortQuery, $limitQuery) {
|
||||
|
||||
$status = runtimeStatus($running);
|
||||
|
||||
?>
|
||||
<li><a href="?view=console"><?php echo translate('Console') ?></a></li>
|
||||
<?php
|
||||
} // end if canView('Monitors')
|
||||
if ( canView('System') ) {
|
||||
?>
|
||||
<li><a href="?view=options"><?php echo translate('Options') ?></a></li>
|
||||
<li>
|
||||
<?php
|
||||
if ( ZM\logToDatabase() > ZM\Logger::NOLOG ) {
|
||||
if ( ! ZM_RUN_AUDIT ) {
|
||||
# zmaudit can clean the logs, but if we aren't running it, then we should clean them regularly
|
||||
if ( preg_match('/^\d+$/', ZM_LOG_DATABASE_LIMIT) ) {
|
||||
# Number of lines, instead of an interval
|
||||
$rows = dbFetchOne('SELECT Count(*) AS `Rows` FROM `Logs`', 'Rows');
|
||||
if ( $rows > ZM_LOG_DATABASE_LIMIT ) {
|
||||
dbQuery('DELETE low_priority FROM `Logs` ORDER BY `TimeKey` ASC LIMIT ?', array($rows - ZM_LOG_DATABASE_LIMIT));
|
||||
}
|
||||
} else if ( preg_match('/^\d\s*(hour|minute|day|week|month|year)$/', ZM_LOG_DATABASE_LIMIT, $matches) ) {
|
||||
dbQuery('DELETE FROM `Logs` WHERE `TimeKey` < unix_timestamp( NOW() - interval '.ZM_LOG_DATABASE_LIMIT.') LIMIT 100');
|
||||
} else {
|
||||
ZM\Error('Potentially invalid value for ZM_LOG_DATABASE_LIMIT: ' . ZM_LOG_DATABASE_LIMIT);
|
||||
}
|
||||
}
|
||||
echo makePopupLink('?view=log', 'zmLog', 'log', '<span class="'.logState().'">'.translate('Log').'</span>');
|
||||
}
|
||||
?>
|
||||
</li>
|
||||
<?php
|
||||
} // end if canview(System)
|
||||
if ( ZM_OPT_X10 && canView('Devices') ) { ?>
|
||||
<li><a href="?view=devices">Devices</a></li>
|
||||
<div class="fixed-top container-fluid p-0">
|
||||
<nav class="navbar navbar-expand-md navbar-dark bg-dark justify-content-center flex-row">
|
||||
|
||||
<div class="navbar-brand justify-content-start align-self-start">
|
||||
<?php echo getNavBrandHTML() ?>
|
||||
</div>
|
||||
|
||||
<!-- the Navigation Bar Hamburger Button -->
|
||||
<div class="nav justify-content-end flex-grow-1">
|
||||
<button type="button" class="navbar-toggler" data-toggle="collapse" data-target="#main-header-nav" aria-expanded="false">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="collapse navbar-collapse" id="main-header-nav">
|
||||
<?php
|
||||
|
||||
// *** Build the navigation bar menu items ***
|
||||
if ( $user and $user['Username'] ) {
|
||||
echo '<ul class="navbar-nav align-self-start justify-content-center">';
|
||||
echo getConsoleHTML();
|
||||
echo getOptionsHTML();
|
||||
echo getLogHTML();
|
||||
echo getDevicesHTML();
|
||||
echo getGroupsHTML($view);
|
||||
echo getFilterHTML($view, $filterQuery, $sortQuery, $limitQuery);
|
||||
echo getCycleHTML($view);
|
||||
echo getMontageHTML($view);
|
||||
echo getMontageReviewHTML($view);
|
||||
echo getRprtEvntAuditHTML($view);
|
||||
echo getHeaderFlipHTML();
|
||||
echo '</ul>';
|
||||
|
||||
echo '<ul class="nav navbar-nav justify-content-end align-self-start flex-grow-1">';
|
||||
echo getAcctCircleHTML($user);
|
||||
echo getStatusBtnHTML($status);
|
||||
echo '</ul>';
|
||||
}
|
||||
?>
|
||||
<li><a href="?view=groups"<?php echo $view=='groups'?' class="selected"':''?>><?php echo translate('Groups') ?></a></li>
|
||||
<li><a href="?view=filter<?php echo $filterQuery.$sortQuery.$limitQuery ?>"<?php echo $view=='filter'?' class="selected"':''?>><?php echo translate('Filters') ?></a></li>
|
||||
</div>
|
||||
</nav><!-- End First Navbar -->
|
||||
|
||||
<nav class="navbar navbar-expand-md bg-dark justify-content-center p-0">
|
||||
<div class="container-fluid" id="panel"<?php echo ( isset($_COOKIE['zmHeaderFlip']) and $_COOKIE['zmHeaderFlip'] == 'down' ) ? 'style="display:none;"' : '' ?>>
|
||||
<?php
|
||||
|
||||
if ( (!ZM_OPT_USE_AUTH) or $user ) {
|
||||
|
||||
// *** Build the statistics shown on the navigation bar ***
|
||||
?>
|
||||
<div id="reload" class="container-fluid">
|
||||
<ul id="Bandwidth" class="navbar-nav justify-content-start">
|
||||
<?php echo getBandwidthHTML($bandwidth_options, $user) ?>
|
||||
</ul>
|
||||
|
||||
<ul class="navbar-nav list-inline justify-content-center">
|
||||
<?php
|
||||
echo getSysLoadHTML();
|
||||
echo getDbConHTML();
|
||||
echo getStorageHTML();
|
||||
echo getShmHTML();
|
||||
echo getLogIconHTML();
|
||||
?>
|
||||
</ul>
|
||||
|
||||
<ul id="Version" class="nav navbar-nav justify-content-end">
|
||||
<?php echo getZMVersionHTML() ?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php
|
||||
} // end if (!ZM_OPT_USE_AUTH) or $user )
|
||||
?>
|
||||
</div><!-- End Collapsible Panel -->
|
||||
</nav><!-- End Second Navbar -->
|
||||
|
||||
<nav class="navbar navbar-expand-md bg-dark justify-content-center p-0">
|
||||
<?php echo getConsoleBannerHTML() ?>
|
||||
</nav><!-- End Third Navbar -->
|
||||
</div>
|
||||
<?php
|
||||
} // end function getNormalNavBarHTML()
|
||||
|
||||
//
|
||||
// A new, slimmer navigation bar, permanently collapsed into a dropdown
|
||||
//
|
||||
function getCollapsedNavBarHTML($running, $user, $bandwidth_options, $view, $filterQuery, $sortQuery, $limitQuery) {
|
||||
|
||||
$status = runtimeStatus($running);
|
||||
|
||||
?>
|
||||
<div class="fixed-top container-fluid p-0">
|
||||
<nav class="navbar navbar-dark bg-dark px-1 flex-nowrap">
|
||||
|
||||
<div class="navbar-brand align-self-start px-0">
|
||||
<?php echo getNavBrandHTML() ?>
|
||||
</div>
|
||||
|
||||
<nav class="navbar navbar-expand-md align-self-start px-0">
|
||||
<ul class="nav navbar-nav list-group px-0">
|
||||
<?php
|
||||
|
||||
// *** Build the statistics shown on the navigation bar ***
|
||||
if ( (!ZM_OPT_USE_AUTH) or $user ) {
|
||||
?>
|
||||
<div id="reload" class="collapse navbar-collapse px-0">
|
||||
|
||||
<ul id="Version" class="pr-2">
|
||||
<?php echo getZMVersionHTML() ?>
|
||||
</ul>
|
||||
|
||||
<ul id="Bandwidth" class="px-2">
|
||||
<?php echo getBandwidthHTML($bandwidth_options, $user) ?>
|
||||
</ul>
|
||||
|
||||
<?php
|
||||
echo getSysLoadHTML();
|
||||
echo getDbConHTML();
|
||||
echo getStorageHTML();
|
||||
echo getShmHTML();
|
||||
echo getLogIconHTML();
|
||||
?>
|
||||
|
||||
</div>
|
||||
|
||||
<?php
|
||||
} // end if (!ZM_OPT_USE_AUTH) or $user )
|
||||
?>
|
||||
</nav>
|
||||
|
||||
<ul class="list-group list-group-horizontal ml-auto">
|
||||
<?php
|
||||
echo getAcctCircleHTML($user);
|
||||
echo getStatusBtnHTML($status);
|
||||
?>
|
||||
</ul>
|
||||
</ul>
|
||||
|
||||
<!-- the Navigation Bar Hamburger Button -->
|
||||
<?php if ( (!ZM_OPT_USE_AUTH) or $user ) { ?>
|
||||
<button type="button" class="navbar-toggler" data-toggle="collapse" data-target="#main-header-nav" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<?php } ?>
|
||||
|
||||
<div style="background-color:#485460" class="dropdown-menu dropdown-menu-right px-3" id="main-header-nav">
|
||||
<?php
|
||||
if ( $user and $user['Username'] ) {
|
||||
echo '<ul class="navbar-nav">';
|
||||
echo getConsoleHTML();
|
||||
echo getOptionsHTML();
|
||||
echo getLogHTML();
|
||||
echo getDevicesHTML();
|
||||
echo getGroupsHTML($view);
|
||||
echo getFilterHTML($view,$filterQuery,$sortQuery,$limitQuery);
|
||||
echo getCycleHTML($view);
|
||||
echo getMontageHTML($view);
|
||||
echo getMontageReviewHTML($view);
|
||||
echo getRprtEvntAuditHTML($view);
|
||||
echo '</ul>';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
||||
</nav><!-- End First Navbar -->
|
||||
|
||||
<nav class="navbar navbar-expand-md bg-dark justify-content-center p-0">
|
||||
<?php echo getConsoleBannerHTML() ?>
|
||||
</nav><!-- End Second Navbar -->
|
||||
</div>
|
||||
|
||||
<?php
|
||||
} // End function getCollapsedNavBarHTML
|
||||
|
||||
// Returns the html representing the current unix style system load
|
||||
function getSysLoadHTML() {
|
||||
$result = '';
|
||||
|
||||
$result .= '<li id="getSysLoadHTML" class="Load nav-item mx-2">'.PHP_EOL;
|
||||
$result .= '<i class="material-icons md-18">trending_up</i>'.PHP_EOL;
|
||||
$result .= ' '.translate('Load').': '.getLoad().PHP_EOL;
|
||||
$result .= '</li>'.PHP_EOL;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the current number of connections made to the database
|
||||
function getDbConHTML() {
|
||||
$result = '';
|
||||
|
||||
$connections = dbFetchOne('SHOW status WHERE variable_name=\'threads_connected\'', 'Value');
|
||||
$max_connections = dbFetchOne('SHOW variables WHERE variable_name=\'max_connections\'', 'Value');
|
||||
$percent_used = $max_connections ? 100 * $connections / $max_connections : 100;
|
||||
$class = ( $percent_used > 90 ) ? ' text-warning' : '';
|
||||
|
||||
$result .= '<li id="getDbConHTML" class="nav-item dropdown mx-2' .$class. '">'.PHP_EOL;
|
||||
$result .= '<i class="material-icons md-18 mr-1">storage</i>'.PHP_EOL;
|
||||
$result .= translate('DB'). ': ' .$connections. '/' .$max_connections.PHP_EOL;
|
||||
$result .= '</li>'.PHP_EOL;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns an html dropdown showing capacity of all storage areas
|
||||
function getStorageHTML() {
|
||||
$result='';
|
||||
|
||||
$func = function($S) {
|
||||
$class = '';
|
||||
if ( $S->disk_usage_percent() > 98 ) {
|
||||
$class = 'text-danger';
|
||||
} else if ( $S->disk_usage_percent() > 90 ) {
|
||||
$class = 'text-warning';
|
||||
}
|
||||
$title = human_filesize($S->disk_used_space()) . ' of ' . human_filesize($S->disk_total_space()).
|
||||
( ( $S->disk_used_space() != $S->event_disk_space() ) ? ' ' .human_filesize($S->event_disk_space()) . ' used by events' : '' );
|
||||
return '<a class="dropdown-item '.$class.'" title="'.$title.'" href="?view=options&tab=storage">'.$S->Name() . ': ' . $S->disk_usage_percent().'%' . '</a>';
|
||||
};
|
||||
|
||||
$storage_areas = ZM\Storage::find(array('Enabled'=>true));
|
||||
$num_storage_areas = count($storage_areas);
|
||||
|
||||
$full_warning = 0;
|
||||
$full_error = 0;
|
||||
foreach ( $storage_areas as $area ) {
|
||||
if ( $area->disk_usage_percent() > 98 ) { $full_error++; continue; }
|
||||
if ( $area->disk_usage_percent() > 90 ) $full_warning++;
|
||||
}
|
||||
|
||||
$class = '';
|
||||
if ( $full_error ) {
|
||||
$class = 'text-danger';
|
||||
} else if ( $full_warning ) {
|
||||
$class = 'text-warning';
|
||||
}
|
||||
|
||||
$result .= '<li id="getStorageHTML" class="nav-item dropdown mx-2">'.PHP_EOL;
|
||||
$result .= '<a class="dropdown-toggle mr-2 '.$class.'" href="#" id="dropdown_storage" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="material-icons md-18 mr-1">folder_shared</i>Storage</a>'.PHP_EOL;
|
||||
$result .= '<div class="dropdown-menu" id="dropdown_storage" aria-labelledby="dropdown_storage">'.PHP_EOL;
|
||||
|
||||
foreach ( $storage_areas as $area ) {
|
||||
$result .= $func($area).PHP_EOL;
|
||||
}
|
||||
$result .= '</div>'.PHP_EOL;
|
||||
$result .= '</li>'.PHP_EOL;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the current capacity of mapped memory filesystem (usually /dev/shm)
|
||||
function getShmHTML() {
|
||||
$result = '';
|
||||
|
||||
$shm_percent = getDiskPercent(ZM_PATH_MAP);
|
||||
$shm_total_space = disk_total_space(ZM_PATH_MAP);
|
||||
$shm_used = $shm_total_space - disk_free_space(ZM_PATH_MAP);
|
||||
|
||||
$class = '';
|
||||
if ( $shm_percent > 98 ) {
|
||||
$class = 'text-danger';
|
||||
} else if ( $shm_percent > 90 ) {
|
||||
$class = 'text-warning';
|
||||
}
|
||||
$result .= ' <li id="getShmHTML" class="nav-item dropdown mx-2' .$class. '" title="' .human_filesize($shm_used). ' of ' .human_filesize($shm_total_space). '">' .ZM_PATH_MAP. ': '.$shm_percent.'%</li>'.PHP_EOL;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the optional web console banner text
|
||||
function getConsoleBannerHTML() {
|
||||
$result = '';
|
||||
|
||||
if ( defined('ZM_WEB_CONSOLE_BANNER') and ZM_WEB_CONSOLE_BANNER != '' ) {
|
||||
$result .= '<h2 id="getConsoleBannerHTML">'.validHtmlStr(ZM_WEB_CONSOLE_BANNER).'</h2>';
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the current high,medium,low bandwidth setting
|
||||
function getBandwidthHTML($bandwidth_options, $user) {
|
||||
$result = '';
|
||||
|
||||
$result .= '<li id="getBandwidthHTML" class="nav-item dropdown">'.
|
||||
makePopupLink('?view=bandwidth', 'zmBandwidth', 'bandwidth', "<i class='material-icons md-18'>network_check</i> ".$bandwidth_options[$_COOKIE['zmBandwidth']] . ' ', ($user && $user['MaxBandwidth'] != 'low' )).
|
||||
'</li>'.PHP_EOL;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the version of ZoneMinder
|
||||
function getZMVersionHTML() {
|
||||
$result = '';
|
||||
|
||||
$class = (ZM_DYN_DB_VERSION&&(ZM_DYN_DB_VERSION!=ZM_VERSION))?'text-danger':'';
|
||||
$result .= '<li id="getZMVersionHTML" class="nav-item dropdown mx-2">'.
|
||||
makePopupLink('?view=version', 'zmVersion', 'version', '<span class="version ' .$class. '">v' .ZM_VERSION. '</span>', canEdit('System')).
|
||||
'</li>'.PHP_EOL;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the ZoneMinder logo and about menu
|
||||
function getNavBrandHTML() {
|
||||
$result = '';
|
||||
|
||||
if ( ZM_HOME_ABOUT ) {
|
||||
$result .= '<a id="getNavBrandHTML" class="dropdown" data-toggle="dropdown" href="#">ZoneMinder</a>'.PHP_EOL;
|
||||
$result .= '<ul style="background-color:#485460" class="dropdown-menu">'.PHP_EOL;
|
||||
$result .= '<li><a class="dropdown-item" href="https://zoneminder.com/" target="_blank">ZoneMinder</a></li>'.PHP_EOL;
|
||||
$result .= '<li><a class="dropdown-item" href="https://zoneminder.readthedocs.io/en/stable/" target="_blank">Documentation</a></li>'.PHP_EOL;
|
||||
$result .= '<li><a class="dropdown-item" href="https://forums.zoneminder.com/" target="_blank">Support</a></li>'.PHP_EOL;
|
||||
$result .= '</ul>'.PHP_EOL;
|
||||
} else {
|
||||
$result .= '<a id="getNavBrandHTML" href="' .validHtmlStr(ZM_HOME_URL). '" target="' .validHtmlStr(ZM_WEB_TITLE). '">' .ZM_HOME_CONTENT. '</a>'.PHP_EOL;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the Console menu item
|
||||
function getConsoleHTML() {
|
||||
$result = '';
|
||||
|
||||
if ( canView('Monitors') ) {
|
||||
$result .= '<li id="getConsoleHTML" class="nav-item dropdown"><a class="nav-link" href="?view=console">'.translate('Console').'</a></li>'.PHP_EOL;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the Options menu item
|
||||
function getOptionsHTML() {
|
||||
$result = '';
|
||||
|
||||
if ( canView('System') ) {
|
||||
$result .= '<li id="getOptionsHTML" class="nav-item dropdown"><a class="nav-link" href="?view=options">'.translate('Options').'</a></li>'.PHP_EOL;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the Log menu item
|
||||
function getLogHTML() {
|
||||
$result = '';
|
||||
|
||||
if ( canView('System') ) {
|
||||
if ( ZM\logToDatabase() > ZM\Logger::NOLOG ) {
|
||||
$logstate = logState();
|
||||
$class = ($logstate == 'ok') ? 'text-success' : ($logstate == 'alert' ? 'text-warning' : (($logstate == 'alarm' ? 'text-danger' : '')));
|
||||
$result .= '<li id="getLogHTML" class="nav-item dropdown mx-2">'.makePopupLink('?view=log', 'zmLog', 'log', '<span class="nav-link '.$class.'">'.translate('Log').'</span>').'</li>'.PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the log icon
|
||||
function getLogIconHTML() {
|
||||
$result = '';
|
||||
|
||||
if ( canView('System') ) {
|
||||
if ( ZM\logToDatabase() > ZM\Logger::NOLOG ) {
|
||||
$logstate = logState();
|
||||
$class = ( $logstate == 'alert' ) ? 'text-warning' : (( $logstate == 'alarm' ) ? 'text-danger' : '');
|
||||
$result .= '<li id="getLogIconHTML" class="nav-item dropdown">'.
|
||||
makePopupLink('?view=log', 'zmLog', 'log', '<span class="mx-1 ' .$class. '"><i class="material-icons md-18">report</i>'.translate('Log').'</span>').
|
||||
'</li>'.PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the X10 Devices menu item
|
||||
function getDevicesHTML() {
|
||||
$result = '';
|
||||
|
||||
if ( ZM_OPT_X10 && canView('Devices') ) {
|
||||
$result .= '<li id="getDevicesHTML" class="nav-item dropdown"><a class="nav-link" href="?view=devices">Devices</a></li>'.PHP_EOL;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the Groups menu item
|
||||
function getGroupsHTML($view) {
|
||||
$result = '';
|
||||
|
||||
$class = $view == 'groups' ? ' selected' : '';
|
||||
$result .= '<li id="getGroupsHTML" class="nav-item dropdown"><a class="nav-link'.$class.'" href="?view=groups">'. translate('Groups') .'</a></li>'.PHP_EOL;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the Filter menu item
|
||||
function getFilterHTML($view, $filterQuery, $sortQuery, $limitQuery) {
|
||||
$result = '';
|
||||
|
||||
$class = $view == 'filter' ? ' selected' : '';
|
||||
$result .= '<li id="getFilterHTML" class="nav-item dropdown"><a class="nav-link'.$class.'" href="?view=filter'.$filterQuery.$sortQuery.$limitQuery.'">'.translate('Filters').'</a></li>'.PHP_EOL;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the Cycle menu item
|
||||
function getCycleHTML($view) {
|
||||
$result = '';
|
||||
|
||||
if ( canView('Stream') ) {
|
||||
?>
|
||||
<li><a href="?view=cycle"<?php echo $view=='cycle'?' class="selected"':''?>><?php echo translate('Cycle') ?></a></li>
|
||||
<li><a href="?view=montage"<?php echo $view=='montage'?' class="selected"':''?>><?php echo translate('Montage') ?></a></li>
|
||||
<?php
|
||||
}
|
||||
$class = $view == 'cycle' ? ' selected' : '';
|
||||
$result .= '<li id="getCycleHTML" class="nav-item dropdown"><a class="nav-link'.$class.'" href="?view=cycle">' .translate('Cycle'). '</a></li>'.PHP_EOL;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the Montage menu item
|
||||
function getMontageHTML($view) {
|
||||
$result = '';
|
||||
|
||||
if ( canView('Stream') ) {
|
||||
$class = $view == 'cycle' ? ' selected' : '';
|
||||
$result .= '<li id="getMontageHTML" class="nav-item dropdown"><a class="nav-link'.$class.'" href="?view=montage">' .translate('Montage'). '</a></li>'.PHP_EOL;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the MontageReview menu item
|
||||
function getMontageReviewHTML($view) {
|
||||
$result = '';
|
||||
|
||||
if ( canView('Events') ) {
|
||||
if ( isset($_REQUEST['filter']['Query']['terms']['attr']) ) {
|
||||
|
@ -335,125 +753,93 @@ if ( $user and $user['Username'] ) {
|
|||
$montageReviewQuery = '&minTime='.$minTime.'&maxTime='.$maxTime;
|
||||
}
|
||||
}
|
||||
?>
|
||||
<li><a href="?view=montagereview<?php echo isset($montageReviewQuery)?'&fit=1'.$montageReviewQuery.'&live=0':'' ?>"<?php echo $view=='montagereview'?' class="selected"':''?>><?php echo translate('MontageReview')?></a></li>
|
||||
<li><a href="?view=report_event_audit"<?php echo $view=='report_event_audit'?' class="selected"':''?>><?php echo translate('ReportEventAudit') ?></a></li>
|
||||
<?php
|
||||
} // end if canView(Events)
|
||||
?>
|
||||
<li><a href="#"><i id="flip" class="material-icons md-18 pull-right">keyboard_arrow_<?php echo ( isset($_COOKIE['zmHeaderFlip']) and $_COOKIE['zmHeaderFlip'] == 'down') ? 'down' : 'up' ?></i></a></li>
|
||||
</ul>
|
||||
$live = isset($montageReviewQuery) ? '&fit=1'.$montageReviewQuery.'&live=0' : '';
|
||||
$class = $view == 'montagereview' ? ' selected' : '';
|
||||
$result .= '<li id="getMontageReviewHTML" class="nav-item dropdown"><a class="nav-link'.$class.'" href="?view=montagereview' .$live. '">'.translate('MontageReview').'</a></li>'.PHP_EOL;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
<div class="navbar-right">
|
||||
<?php
|
||||
// Returns the html representing the Audit Events Report menu item
|
||||
function getRprtEvntAuditHTML($view) {
|
||||
$result = '';
|
||||
|
||||
if ( canView('Events') ) {
|
||||
$class = $view == 'report_event_audit' ? ' selected' : '';
|
||||
$result .= '<li id="getRprtEvntAuditHTML" class="nav-item dropdown"><a class="nav-link'.$class.'" href="?view=report_event_audit">'.translate('ReportEventAudit').'</a></li>'.PHP_EOL;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the header collapse toggle menu item
|
||||
function getHeaderFlipHTML() {
|
||||
$result = '';
|
||||
|
||||
$header = ( isset($_COOKIE['zmHeaderFlip']) and $_COOKIE['zmHeaderFlip'] == 'down') ? 'down' : 'up';
|
||||
$result .= '<li id="getHeaderFlipHTML" class="nav-item dropdown"><a class="nav-link" href="#"><i id="flip" class="material-icons md-18">keyboard_arrow_' .$header. '</i></a></li>'.PHP_EOL;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the logged in user name and avatar
|
||||
function getAcctCircleHTML($user=null) {
|
||||
$result = '';
|
||||
|
||||
if ( ZM_OPT_USE_AUTH and $user ) {
|
||||
?>
|
||||
<p class="navbar-text">
|
||||
<i class="material-icons">account_circle</i>
|
||||
<?php echo makePopupLink('?view=logout', 'zmLogout', 'logout', $user['Username'], (ZM_AUTH_TYPE == 'builtin') ) ?>
|
||||
</p>
|
||||
<?php
|
||||
$result .= '<p id="getAcctCircleHTML" class="navbar-text mr-2">'.PHP_EOL;
|
||||
$result .= makePopupLink('?view=logout', 'zmLogout', 'logout',
|
||||
'<i class="material-icons">account_circle</i> '. $user['Username'],
|
||||
(ZM_AUTH_TYPE == 'builtin') ).PHP_EOL;
|
||||
$result .= '</p>'.PHP_EOL;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the runtime status button
|
||||
function getStatusBtnHTML($status) {
|
||||
$result = '';
|
||||
|
||||
if ( canEdit('System') ) {
|
||||
?>
|
||||
<button type="button" class="btn btn-default navbar-btn" data-toggle="modal" data-target="#modalState"><?php echo $status ?></button>
|
||||
<?php if ( ZM_SYSTEM_SHUTDOWN ) { ?>
|
||||
<p class="navbar-text">
|
||||
<?php echo makePopupLink('?view=shutdown', 'zmShutdown', 'shutdown', '<i class="material-icons md-18">power_settings_new</i>' ) ?>
|
||||
</p>
|
||||
<?php } ?>
|
||||
<?php } else if ( canView('System') ) { ?>
|
||||
<p class="navbar-text"><?php echo $status ?></p>
|
||||
<?php } ?>
|
||||
</div>
|
||||
<?php } else { # end if !$user or $user['Id'] meaning logged in ?>
|
||||
</ul>
|
||||
<?php } # end if !$user or $user['Id'] meaning logged in ?>
|
||||
</div><!-- End .navbar-collapse -->
|
||||
</div> <!-- End .container-fluid -->
|
||||
<div id="panel"<?php echo ( isset($_COOKIE['zmHeaderFlip']) and $_COOKIE['zmHeaderFlip'] == 'down' ) ? 'style="display:none;"' : '' ?>>
|
||||
<?php
|
||||
} //end reload null. Runs on full page load
|
||||
//$result .= '<li class="nav-item dropdown">'.PHP_EOL;
|
||||
$result .= '<form id="getStatusBtnHTML" class="form-inline">'.PHP_EOL;
|
||||
$result .= '<button type="button" class="btn btn-default navbar-btn" data-toggle="modal" data-target="#modalState">' .$status. '</button>'.PHP_EOL;
|
||||
$result .= '</form>'.PHP_EOL;
|
||||
//$result .= '</li>'.PHP_EOL;
|
||||
|
||||
if ( (!ZM_OPT_USE_AUTH) or $user ) {
|
||||
if ($reload == 'reload') ob_start();
|
||||
?>
|
||||
<div id="reload" class="container-fluid reduced-text">
|
||||
<div id="Bandwidth" class="pull-left">
|
||||
<?php echo makePopupLink( '?view=bandwidth', 'zmBandwidth', 'bandwidth', "<i class='material-icons md-18'>network_check</i> ".$bandwidth_options[$_COOKIE['zmBandwidth']] . ' ', ($user && $user['MaxBandwidth'] != 'low' ) ) ?>
|
||||
</div>
|
||||
<div id="Version" class="pull-right">
|
||||
<?php echo makePopupLink( '?view=version', 'zmVersion', 'version', '<span class="version '.$versionClass.'">v'.ZM_VERSION.'</span>', canEdit('System') ) ?>
|
||||
</div>
|
||||
<ul class="list-inline">
|
||||
<li class="Load"><i class="material-icons md-18">trending_up</i> <?php echo translate('Load') ?>: <?php echo getLoad() ?></li>
|
||||
<i class="material-icons md-18">storage</i>
|
||||
<?php
|
||||
$connections = dbFetchOne('SHOW status WHERE variable_name=\'threads_connected\'', 'Value');
|
||||
$max_connections = dbFetchOne('SHOW variables WHERE variable_name=\'max_connections\'', 'Value');
|
||||
$percent_used = $max_connections ? 100 * $connections / $max_connections : 100;
|
||||
echo '<li'. ( $percent_used > 90 ? ' class="warning"' : '' ).'>'.translate('DB').':'.$connections.'/'.$max_connections.'</li>';
|
||||
?>
|
||||
<li><?php echo translate('Storage') ?>:
|
||||
<?php
|
||||
$storage_areas = ZM\Storage::find(array('Enabled'=>true));
|
||||
$storage_paths = null;
|
||||
$storage_areas_with_no_server_id = array();
|
||||
foreach ( $storage_areas as $area ) {
|
||||
$storage_paths[$area->Path()] = $area;
|
||||
if ( ! $area->ServerId() ) {
|
||||
$storage_areas_with_no_server_id[] = $area;
|
||||
}
|
||||
if ( ZM_SYSTEM_SHUTDOWN ) {
|
||||
$result .= '<p class="navbar-text">'.PHP_EOL;
|
||||
$result .= makePopupLink('?view=shutdown', 'zmShutdown', 'shutdown', '<i class="material-icons md-18">power_settings_new</i>' ).PHP_EOL;
|
||||
$result .= '</p>'.PHP_EOL;
|
||||
}
|
||||
|
||||
} else if ( canView('System') ) {
|
||||
$result .= '<p id="getStatusBtnHTML" class="navbar-text">'.PHP_EOL;
|
||||
$result .= $status.PHP_EOL;
|
||||
$result .= '</p>'.PHP_EOL;
|
||||
}
|
||||
$func = function($S){
|
||||
$class = '';
|
||||
if ( $S->disk_usage_percent() > 98 ) {
|
||||
$class = 'error';
|
||||
} else if ( $S->disk_usage_percent() > 90 ) {
|
||||
$class = 'warning';
|
||||
}
|
||||
$title = human_filesize($S->disk_used_space()) . ' of ' . human_filesize($S->disk_total_space()).
|
||||
( ( $S->disk_used_space() != $S->event_disk_space() ) ? ' ' .human_filesize($S->event_disk_space()) . ' used by events' : '' );
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
return '<span class="'.$class.'" title="'.$title.'">'.$S->Name() . ': ' . $S->disk_usage_percent().'%' . '</span>
|
||||
'; };
|
||||
#$func = function($S){ return '<span title="">'.$S->Name() . ': ' . $S->disk_usage_percent().'%' . '</span>'; };
|
||||
if ( count($storage_areas) > 4 )
|
||||
$storage_areas = $storage_areas_with_no_server_id;
|
||||
if ( count($storage_areas) <= 4 )
|
||||
echo implode(', ', array_map($func, $storage_areas));
|
||||
$shm_percent = getDiskPercent(ZM_PATH_MAP);
|
||||
$shm_total_space = disk_total_space(ZM_PATH_MAP);
|
||||
$shm_used = $shm_total_space - disk_free_space(ZM_PATH_MAP);
|
||||
|
||||
$class = '';
|
||||
if ( $shm_percent > 98 ) {
|
||||
$class = 'error';
|
||||
} else if ( $shm_percent > 90 ) {
|
||||
$class = 'warning';
|
||||
function runtimeStatus($running=null) {
|
||||
if ( $running == null )
|
||||
$running = daemonCheck();
|
||||
if ( $running ) {
|
||||
$state = dbFetchOne('SELECT Name FROM States WHERE isActive=1', 'Name');
|
||||
if ( $state == 'default' )
|
||||
$state = '';
|
||||
}
|
||||
echo ' <span class="'.$class.'" title="' . human_filesize($shm_used).' of '.human_filesize($shm_total_space).'">'.ZM_PATH_MAP.': '.$shm_percent.'%</span>';
|
||||
?></li>
|
||||
</ul>
|
||||
<?php if ( defined('ZM_WEB_CONSOLE_BANNER') and ZM_WEB_CONSOLE_BANNER != '' ) { ?>
|
||||
<h3 id="development"><?php echo validHtmlStr(ZM_WEB_CONSOLE_BANNER); ?></h3>
|
||||
<?php } ?>
|
||||
<!-- End .footer/reload --></div>
|
||||
<?php
|
||||
if ($reload == 'reload') return ob_get_clean();
|
||||
} // end if (!ZM_OPT_USE_AUTH) or $user )
|
||||
?>
|
||||
</div>
|
||||
</div><!-- End .navbar .navbar-default -->
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
} // end function getNavBarHTML()
|
||||
|
||||
return $running ? ($state ? $state : translate('Running')) : translate('Stopped');
|
||||
}
|
||||
|
||||
function xhtmlFooter() {
|
||||
global $cspNonce;
|
||||
global $view;
|
||||
global $skin;
|
||||
global $running;
|
||||
if ( canEdit('System') ) {
|
||||
include("skins/$skin/views/state.php");
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
|||
bootstrap.min.js
|
File diff suppressed because it is too large
Load Diff
|
@ -1 +1 @@
|
|||
https://github.com/twbs/bootstrap/releases/download/v3.3.6/bootstrap-3.3.6-dist.zip
|
||||
https://github.com/twbs/bootstrap/releases/download/v4.5.0/bootstrap-4.5.0-dist.zip
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -236,7 +236,7 @@ window.addEventListener("DOMContentLoaded", function onSkinDCL() {
|
|||
console.error("Nothing found to bind to " + fnName);
|
||||
return;
|
||||
}
|
||||
el.onchange = window[fnName].bind(el, el);
|
||||
el.oninput = window[fnName].bind(el, el);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -338,7 +338,12 @@ if ( currentView != 'none' && currentView != 'login' ) {
|
|||
auth_hash = data.auth;
|
||||
}
|
||||
}
|
||||
$j('#reload').replaceWith(data.message);
|
||||
// iterate through all the keys then update each element id with the same name
|
||||
for (var key of Object.keys(data)) {
|
||||
if ( key == "auth" ) continue;
|
||||
if ( $j('#'+key).hasClass("show") ) continue; // don't update if the user has the dropdown open
|
||||
if ( $j('#'+key).length ) $j('#'+key).replaceWith(data[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -397,6 +402,10 @@ function submitTab(evt) {
|
|||
}
|
||||
|
||||
function submitThisForm() {
|
||||
if ( ! this.form ) {
|
||||
console.log("No this.form. element with onchange is not in a form");
|
||||
return;
|
||||
}
|
||||
this.form.submit();
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ $html =
|
|||
'
|
||||
<div class="controlHeader">
|
||||
<!-- Used to submit the form with the enter key -->
|
||||
<input type="submit" class="hide"/>
|
||||
<input type="submit" class="d-none"/>
|
||||
<input type="hidden" name="filtering" value=""/>
|
||||
';
|
||||
|
||||
|
|
|
@ -157,13 +157,17 @@ if ( $show_storage_areas ) $left_columns += 1;
|
|||
xhtmlHeaders(__FILE__, translate('Console'));
|
||||
getBodyTopHTML();
|
||||
?>
|
||||
<?php echo $navbar ?>
|
||||
<form name="monitorForm" method="get" action="?">
|
||||
<input type="hidden" name="view" value="<?php echo $view ?>"/>
|
||||
<input type="hidden" name="action" value=""/>
|
||||
|
||||
<?php echo $navbar ?>
|
||||
<div class="filterBar"><?php echo $filterbar ?></div>
|
||||
<div class="statusBreakdown">
|
||||
<div class="filterBar" id="fbpanel"<?php echo ( isset($_COOKIE['zmFilterBarFlip']) and $_COOKIE['zmFilterBarFlip'] == 'down' ) ? ' style="display:none;"' : '' ?>>
|
||||
<?php echo $filterbar ?>
|
||||
</div>
|
||||
|
||||
<div class="container-fluid pt-2">
|
||||
<div class="statusBreakdown float-left">
|
||||
<?php
|
||||
$html = '';
|
||||
foreach ( array_keys($status_counts) as $status ) {
|
||||
|
@ -172,9 +176,8 @@ getBodyTopHTML();
|
|||
}
|
||||
echo $html;
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container-fluid">
|
||||
<button type="button" name="addBtn" data-on-click-this="addMonitor"
|
||||
<?php echo (canEdit('Monitors') && !$user['MonitorIds']) ? '' : ' disabled="disabled" title="'.translate('AddMonitorDisabled').'"' ?>
|
||||
>
|
||||
|
@ -200,10 +203,12 @@ getBodyTopHTML();
|
|||
<i class="material-icons md-18">view_list</i>
|
||||
<?php echo translate('Select') ?>
|
||||
</button>
|
||||
|
||||
<a href="#"><i id="fbflip" class="material-icons md-18">keyboard_arrow_<?php echo ( isset($_COOKIE['zmFilterBarFlip']) and $_COOKIE['zmFilterBarFlip'] == 'down') ? 'down' : 'up' ?></i></a>
|
||||
<?php
|
||||
ob_start();
|
||||
?>
|
||||
<div class="table-responsive">
|
||||
<div class="table-responsive-sm pt-2">
|
||||
<table class="table table-striped table-hover table-condensed consoleTable">
|
||||
<thead class="thead-highlight">
|
||||
<tr>
|
||||
|
|
|
@ -161,11 +161,11 @@ xhtmlHeaders(__FILE__, translate('CycleWatch'));
|
|||
</div>
|
||||
<div class="container-fluid">
|
||||
<div class="row" id="content">
|
||||
<div class="col-sm-2 sidebar">
|
||||
<ul class="nav nav-pills nav-stacked">
|
||||
<div class="col-sm-2 sidebar">
|
||||
<ul class="nav flex-column">
|
||||
<?php
|
||||
foreach ( $monitors as $m ) {
|
||||
echo '<li'.( $m->Id() == $monitor->Id() ? ' class="active"' : '' ).'><a href="?view=cycle&mid='.$m->Id().'">'.$m->Name().'</a></li>';
|
||||
echo '<li class="nav-item"><a class="nav-link'.( $m->Id() == $monitor->Id() ? ' active' : '' ).'" href="?view=cycle&mid='.$m->Id().'">'.$m->Name().'</a></li>';
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
|
|
|
@ -68,9 +68,9 @@ if ( !empty($page) ) {
|
|||
$limitLeft = $limit - $limitStart;
|
||||
$limitAmount = ($limitLeft>ZM_WEB_EVENTS_PER_PAGE)?ZM_WEB_EVENTS_PER_PAGE:$limitLeft;
|
||||
}
|
||||
$eventsSql .= " limit $limitStart, $limitAmount";
|
||||
$eventsSql .= " LIMIT $limitStart, $limitAmount";
|
||||
} elseif ( !empty($limit) ) {
|
||||
$eventsSql .= ' limit 0, '.$limit;
|
||||
$eventsSql .= ' LIMIT 0, '.$limit;
|
||||
}
|
||||
|
||||
$maxShortcuts = 5;
|
||||
|
|
|
@ -174,7 +174,7 @@ xhtmlHeaders(__FILE__, translate('EventFilter'));
|
|||
<input type="hidden" name="view" value="filter"/>
|
||||
<hr/>
|
||||
<div id="filterSelector"><label for="<?php echo 'Id' ?>"><?php echo translate('UseFilter') ?></label>
|
||||
<?php
|
||||
<?php
|
||||
if ( count($filterNames) > 1 ) {
|
||||
echo htmlSelect('Id', $filterNames, $filter->Id(), array('data-on-change-this'=>'selectFilter'));
|
||||
} else {
|
||||
|
@ -194,16 +194,16 @@ if ( (null !== $filter->Concurrent()) and $filter->Concurrent() )
|
|||
<input type="hidden" name="object" value="filter"/>
|
||||
|
||||
<hr/>
|
||||
<?php if ( $filter->Id() ) { ?>
|
||||
<?php if ( $filter->Id() ) { ?>
|
||||
<p class="Id"><label><?php echo translate('Id') ?></label><?php echo $filter->Id() ?></p>
|
||||
<?php } ?>
|
||||
<?php } ?>
|
||||
<p class="Name">
|
||||
<label for="filter[Name]"><?php echo translate('Name') ?></label>
|
||||
<input type="text" id="filter[Name]" name="filter[Name]" value="<?php echo validHtmlStr($filter->Name()) ?>" data-on-input-this="updateButtons"/>
|
||||
</p>
|
||||
<?php if ( ZM_OPT_USE_AUTH ) { ?>
|
||||
<p><label><?php echo translate('FilterUser') ?></label>
|
||||
<?php
|
||||
<?php
|
||||
global $user;
|
||||
echo htmlSelect('filter[UserId]',
|
||||
ZM\User::Indexed_By_Id(),
|
||||
|
|
|
@ -26,16 +26,17 @@ if ( !canView('Events') ) {
|
|||
require_once('includes/Frame.php');
|
||||
|
||||
$eid = validInt($_REQUEST['eid']);
|
||||
if ( !empty($_REQUEST['fid']) )
|
||||
$fid = validInt($_REQUEST['fid']);
|
||||
$fid = empty($_REQUEST['fid']) ? 0 : validInt($_REQUEST['fid']);
|
||||
|
||||
$Event = new ZM\Event($eid);
|
||||
$Monitor = $Event->Monitor();
|
||||
|
||||
# This is kinda weird.. so if we pass fid=0 or some other non-integer, then it loads max score
|
||||
# perhaps we should consider being explicit, like fid = maxscore
|
||||
if ( !empty($fid) ) {
|
||||
$sql = 'SELECT * FROM Frames WHERE EventId = ? AND FrameId = ?';
|
||||
if ( !($frame = dbFetchOne( $sql, NULL, array($eid, $fid) )) )
|
||||
$frame = array( 'EventId'=>$eid, 'FrameId'=>$fid, 'Type'=>'Normal', 'Score'=>0 );
|
||||
if ( !($frame = dbFetchOne($sql, NULL, array($eid, $fid))) )
|
||||
$frame = array('EventId'=>$eid, 'FrameId'=>$fid, 'Type'=>'Normal', 'Score'=>0);
|
||||
} else {
|
||||
$frame = dbFetchOne('SELECT * FROM Frames WHERE EventId = ? AND Score = ?', NULL, array($eid, $Event->MaxScore()));
|
||||
}
|
||||
|
@ -50,19 +51,19 @@ $lastFid = $maxFid;
|
|||
|
||||
$alarmFrame = $Frame->Type() == 'Alarm';
|
||||
|
||||
if ( isset( $_REQUEST['scale'] ) ) {
|
||||
if ( isset($_REQUEST['scale']) ) {
|
||||
$scale = validNum($_REQUEST['scale']);
|
||||
} else if ( isset( $_COOKIE['zmWatchScale'.$Monitor->Id()] ) ) {
|
||||
} else if ( isset($_COOKIE['zmWatchScale'.$Monitor->Id()]) ) {
|
||||
$scale = validNum($_COOKIE['zmWatchScale'.$Monitor->Id()]);
|
||||
} else if ( isset( $_COOKIE['zmWatchScale'] ) ) {
|
||||
} else if ( isset($_COOKIE['zmWatchScale']) ) {
|
||||
$scale = validNum($_COOKIE['zmWatchScale']);
|
||||
} else {
|
||||
$scale = max(reScale(SCALE_BASE, $Monitor->DefaultScale(), ZM_WEB_DEFAULT_SCALE), SCALE_BASE);
|
||||
}
|
||||
$scale = $scale ?: 'auto';
|
||||
$scale = $scale ? $scale : 0;
|
||||
|
||||
$imageData = $Event->getImageSrc( $frame, $scale, 0 );
|
||||
if ( ! $imageData ) {
|
||||
$imageData = $Event->getImageSrc($frame, $scale, 0);
|
||||
if ( !$imageData ) {
|
||||
ZM\Error("No data found for Event $eid frame $fid");
|
||||
$imageData = array();
|
||||
}
|
||||
|
@ -89,10 +90,10 @@ xhtmlHeaders(__FILE__, translate('Frame').' - '.$Event->Id().' - '.$Frame->Frame
|
|||
<form>
|
||||
<div id="headerButtons">
|
||||
<?php if ( ZM_RECORD_EVENT_STATS && $alarmFrame ) { echo makePopupLink( '?view=stats&eid='.$Event->Id().'&fid='.$Frame->FrameId(), 'zmStats', 'stats', translate('Stats') ); } ?>
|
||||
<?php if ( canEdit( 'Events' ) ) { ?><a href="?view=none&action=delete&markEid=<?php echo $Event->Id() ?>"><?php echo translate('Delete') ?></a><?php } ?>
|
||||
<?php if ( canEdit('Events') ) { ?><a href="?view=none&action=delete&markEid=<?php echo $Event->Id() ?>"><?php echo translate('Delete') ?></a><?php } ?>
|
||||
<a href="#" data-on-click="closeWindow"><?php echo translate('Close') ?></a>
|
||||
</div>
|
||||
<div id="scaleControl"><label for="scale"><?php echo translate('Scale') ?></label><?php echo buildSelect('scale', $scales); ?></div>
|
||||
<div id="scaleControl"><label for="scale"><?php echo translate('Scale') ?></label><?php echo htmlSelect('scale', $scales, $scale); ?></div>
|
||||
<h2><?php echo translate('Frame') ?> <?php echo $Event->Id().'-'.$Frame->FrameId().' ('.$Frame->Score().')' ?></h2>
|
||||
<input type="hidden" name="base_width" id="base_width" value="<?php echo $Event->Width(); ?>"/>
|
||||
<input type="hidden" name="base_height" id="base_height" value="<?php echo $Event->Height(); ?>"/>
|
||||
|
@ -100,7 +101,6 @@ xhtmlHeaders(__FILE__, translate('Frame').' - '.$Event->Id().' - '.$Frame->Frame
|
|||
</div>
|
||||
<div id="content">
|
||||
<p id="image">
|
||||
|
||||
<?php if ( $imageData['hasAnalImage'] ) {
|
||||
echo sprintf('<a href="?view=frame&eid=%d&fid=%d&scale=%d&show=%s">', $Event->Id(), $Frame->FrameId(), $scale, ( $show=='anal'?'capt':'anal' ) );
|
||||
} ?>
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
<?php
|
||||
global $monIdx;
|
||||
global $nextMid;
|
||||
global $options;
|
||||
global $monitors;
|
||||
?>
|
||||
var monIdx = '<?php echo $monIdx; ?>';
|
||||
var nextMid = "<?php echo isset($nextMid)?$nextMid:'' ?>";
|
||||
var mode = "<?php echo $options['mode'] ?>";
|
||||
|
|
|
@ -1,3 +1,15 @@
|
|||
<?php
|
||||
global $connkey;
|
||||
global $Event;
|
||||
global $Monitor;
|
||||
global $FilterQuery;
|
||||
global $sortQuery;
|
||||
global $rates;
|
||||
global $rate;
|
||||
global $scale;
|
||||
global $streamMode;
|
||||
global $popup;
|
||||
?>
|
||||
//
|
||||
// Import constants
|
||||
//
|
||||
|
|
|
@ -1,3 +1,16 @@
|
|||
<?php
|
||||
global $filterQuery;
|
||||
global $sortQuery;
|
||||
global $conjunctionTypes;
|
||||
global $opTypes;
|
||||
global $archiveTypes;
|
||||
global $weekdays;
|
||||
global $states;
|
||||
global $servers;
|
||||
global $storageareas;
|
||||
global $monitors;
|
||||
global $zones;
|
||||
?>
|
||||
var filterQuery = '<?php echo isset($filterQuery) ? validJsStr(htmlspecialchars_decode($filterQuery)) : '' ?>';
|
||||
var sortQuery = '<?php echo isset($sortQuery) ? validJsStr(htmlspecialchars_decode($sortQuery)) : '' ?>';
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ function changeScale() {
|
|||
if ( img ) {
|
||||
var baseWidth = $j('#base_width').val();
|
||||
var baseHeight = $j('#base_height').val();
|
||||
if ( scale == 'auto' ) {
|
||||
if ( ! parseInt(scale) ) {
|
||||
var newSize = scaleToFit(baseWidth, baseHeight, img, $j('#controls'));
|
||||
newWidth = newSize.width;
|
||||
newHeight = newSize.height;
|
||||
|
@ -24,7 +24,7 @@ function changeScale() {
|
|||
img.css('width', newWidth + 'px');
|
||||
img.css('height', newHeight + 'px');
|
||||
}
|
||||
Cookie.write( 'zmWatchScale', scale, {duration: 10*365} );
|
||||
Cookie.write('zmWatchScale', scale, {duration: 10*365});
|
||||
$j.each(controlsLinks, function(k, anchor) { //Make frames respect scale choices
|
||||
if ( anchor ) {
|
||||
anchor.prop('href', anchor.prop('href').replace(/scale=.*&/, 'scale=' + scale + '&'));
|
||||
|
@ -32,7 +32,7 @@ function changeScale() {
|
|||
});
|
||||
}
|
||||
|
||||
if ( scale == 'auto' ) {
|
||||
if ( !scale ) {
|
||||
$j(document).ready(changeScale);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
window.addEventListener( 'DOMContentLoaded', function() {
|
||||
if ( failed == true ) {
|
||||
$('loginError').removeClass( 'hidden' );
|
||||
$j('#loginError').show();
|
||||
}
|
||||
} );
|
||||
|
|
|
@ -157,6 +157,7 @@ function updateMethods(element) {
|
|||
switch ( element.value ) {
|
||||
case 'http' :
|
||||
<?php
|
||||
global $httpMethods;
|
||||
foreach( $httpMethods as $value=>$label ) {
|
||||
?>
|
||||
methodSelector.options[methodSelector.options.length] = new Option("<?php echo htmlspecialchars($label) ?>", "<?php echo $value ?>");
|
||||
|
@ -168,6 +169,7 @@ function updateMethods(element) {
|
|||
break;
|
||||
case 'rtsp' :
|
||||
<?php
|
||||
global $rtspMethods;
|
||||
foreach( $rtspMethods as $value=>$label ) {
|
||||
?>
|
||||
methodSelector.options[methodSelector.options.length] = new Option( "<?php echo htmlspecialchars($label) ?>", "<?php echo $value ?>" );
|
||||
|
|
|
@ -297,8 +297,8 @@ function changeSize() {
|
|||
console.log("Error finding frame for " + monitor.id);
|
||||
continue;
|
||||
}
|
||||
monitor_frame.css('width', ( width ? width+'px' : 'auto') );
|
||||
monitor_frame.css('height', ( height ? height+'px' : 'auto') );
|
||||
monitor_frame.css('width', ( width ? width+'px' : 'auto'));
|
||||
monitor_frame.css('height', ( height ? height+'px' : 'auto'));
|
||||
|
||||
/*Stream could be an applet so can't use moo tools*/
|
||||
var streamImg = $('liveStream'+monitor.id);
|
||||
|
|
|
@ -28,6 +28,7 @@ var canStreamNative = <?php echo canStreamNative()?'true':'false' ?>;
|
|||
|
||||
var monitorData = new Array();
|
||||
<?php
|
||||
global $monitors;
|
||||
foreach ( $monitors as $monitor ) {
|
||||
?>
|
||||
monitorData[monitorData.length] = {
|
||||
|
@ -46,6 +47,7 @@ monitorData[monitorData.length] = {
|
|||
layouts = new Array();
|
||||
layouts[0] = {}; // reserved, should hold which fields to clear when transitioning
|
||||
<?php
|
||||
global $layouts;
|
||||
foreach ( $layouts as $layout ) {
|
||||
?>
|
||||
layouts[<?php echo $layout->Id() ?>] = {"Name":"<?php echo $layout->Name()?>","Positions":<?php echo $layout->Positions() ?>};
|
||||
|
|
|
@ -4,6 +4,20 @@ $TimeZone = new DateTimeZone( ini_get('date.timezone') );
|
|||
$now = new DateTime('now', $TimeZone);
|
||||
$offset = $TimeZone->getOffset($now);
|
||||
echo $offset.'; // '.floor($offset / 3600).' hours ';
|
||||
|
||||
global $defaultScale;
|
||||
global $liveMode;
|
||||
global $fitMode;
|
||||
global $speeds;
|
||||
global $speedIndex;
|
||||
global $initialDisplayInterval;
|
||||
global $minTimeSecs;
|
||||
global $maxTimeSecs;
|
||||
global $minTime;
|
||||
global $maxTime;
|
||||
global $monitors;
|
||||
global $eventsSql;
|
||||
global $framesSql;
|
||||
?>
|
||||
|
||||
var currentScale=<?php echo $defaultScale?>;
|
||||
|
@ -40,7 +54,7 @@ $maxScore = 0;
|
|||
if ( !$liveMode ) {
|
||||
$result = dbQuery($eventsSql);
|
||||
if ( !$result ) {
|
||||
Fatal('SQL-ERR');
|
||||
ZM\Fatal('SQL-ERR');
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -146,7 +160,6 @@ foreach ( ZM\Server::find() as $Server ) {
|
|||
echo 'Servers[' . $Server->Id() . '] = new Server(' . $Server->to_json(). ");\n";
|
||||
}
|
||||
|
||||
|
||||
echo '
|
||||
var monitorName = [];
|
||||
var monitorLoading = [];
|
||||
|
@ -167,8 +180,8 @@ var monitorCanvasCtx = [];
|
|||
var monitorPtr = []; // monitorName[monitorPtr[0]] is first monitor
|
||||
';
|
||||
|
||||
$numMonitors=0; // this array is indexed by the monitor ID for faster access later, so it may be sparse
|
||||
$avgArea=floatval(0); // Calculations the normalizing scale
|
||||
$numMonitors = 0; // this array is indexed by the monitor ID for faster access later, so it may be sparse
|
||||
$avgArea = floatval(0); // Calculations the normalizing scale
|
||||
|
||||
foreach ( $monitors as $m ) {
|
||||
$avgArea = $avgArea + floatval($m->Width() * $m->Height());
|
||||
|
|
|
@ -6,13 +6,14 @@
|
|||
// will save the GET request via the postLoginQuery variable. After logging in, this
|
||||
// view receives the postLoginQuery via the login form submission, and we can then
|
||||
// redirect the user to his original intended destination by appending it to the URL.
|
||||
//
|
||||
?>
|
||||
|
||||
(
|
||||
$j(
|
||||
function () {
|
||||
// Append '?(GET query)' to URL if the GET query is not empty.
|
||||
var querySuffix = '<?php
|
||||
if (!empty($_SESSION['postLoginQuery'])) {
|
||||
if ( !empty($_SESSION['postLoginQuery']) ) {
|
||||
parse_str($_SESSION['postLoginQuery'], $queryParams);
|
||||
echo '?' . http_build_query($queryParams);
|
||||
zm_session_start();
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
<?php
|
||||
global $filterQuery;
|
||||
global $monitors;
|
||||
?>
|
||||
var filterQuery = '<?php echo validJsStr($filterQuery) ?>';
|
||||
|
||||
<?php
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
<?php
|
||||
global $streamMode;
|
||||
global $showPtzControls;
|
||||
global $connkey;
|
||||
global $monitor;
|
||||
global $scale;
|
||||
?>
|
||||
//
|
||||
// Import constants
|
||||
//
|
||||
|
|
|
@ -450,6 +450,7 @@ function drawZonePoints() {
|
|||
'name': 'newZone[Points]['+i+'][x]',
|
||||
'value': zone['Points'][i].x,
|
||||
'type': 'number',
|
||||
'class': 'ZonePoint',
|
||||
'min': '0',
|
||||
'max': maxX,
|
||||
'data-point-index': i
|
||||
|
@ -464,6 +465,7 @@ function drawZonePoints() {
|
|||
'name': 'newZone[Points]['+i+'][y]',
|
||||
'value': zone['Points'][i].y,
|
||||
'type': 'number',
|
||||
'class': 'ZonePoint',
|
||||
'min': '0',
|
||||
'max': maxY,
|
||||
'data-point-index': i
|
||||
|
|
|
@ -1,3 +1,14 @@
|
|||
<?php
|
||||
global $presets;
|
||||
global $zone;
|
||||
global $newZone;
|
||||
global $monitor;
|
||||
global $selfIntersecting;
|
||||
global $streamMode;
|
||||
global $connkey;
|
||||
global $streamSrc;
|
||||
?>
|
||||
|
||||
var presets = new Object();
|
||||
<?php
|
||||
foreach ( $presets as $preset ) {
|
||||
|
@ -21,7 +32,7 @@ presets[<?php echo $preset['Id'] ?>] = {
|
|||
'ExtendAlarmFrames': '<?php echo $preset['ExtendAlarmFrames'] ?>'
|
||||
};
|
||||
<?php
|
||||
}
|
||||
} # end foreach preset
|
||||
?>
|
||||
|
||||
var zone = {
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
<?php
|
||||
global $connkey;
|
||||
global $monitor;
|
||||
?>
|
||||
var connKey = '<?php echo $connkey ?>';
|
||||
var monitorUrl = '<?php echo ( $monitor->UrlToIndex() ) ?>';
|
||||
var CMD_QUIT = <?php echo CMD_QUIT ?>;
|
||||
|
|
|
@ -25,94 +25,83 @@ if ( !canView('System') ) {
|
|||
|
||||
$focusWindow = true;
|
||||
|
||||
xhtmlHeaders(__FILE__, translate('SystemLog') );
|
||||
xhtmlHeaders(__FILE__, translate('SystemLog'));
|
||||
?>
|
||||
<body>
|
||||
<div id="page">
|
||||
<div id="header">
|
||||
<table class="table">
|
||||
<tr class="row">
|
||||
<td class="col text-center">
|
||||
<div id="logSummary">
|
||||
<?php echo translate('State') ?>: <span id="logState"></span>/
|
||||
<?php echo translate('Total') ?>: <span id="totalLogs"></span>/
|
||||
<?php echo translate('Available') ?>: <span id="availLogs"></span>/
|
||||
<?php echo translate('Displaying') ?>: <span id="displayLogs"></span>/
|
||||
<?php echo translate('Updated') ?>: <span id="lastUpdate"></span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="row">
|
||||
<td class="col text-center">
|
||||
<div class="btn-group">
|
||||
<button type="button" data-on-click="expandLog"><?php echo translate('More') ?></button>
|
||||
<button type="button" data-on-click="clearLog"><?php echo translate('Clear') ?></button>
|
||||
<button type="button" data-on-click="refreshLog"><?php echo translate('Refresh') ?></button>
|
||||
<button type="button" data-on-click="exportLog"><?php echo translate('Export') ?></button>
|
||||
<button type="button" data-on-click="closeWindow"><?php echo translate('Close') ?></button>
|
||||
</div> <!--btn-->
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div> <!--header-->
|
||||
<div id="content">
|
||||
<form id="logForm" name="logForm" method="post" action="?">
|
||||
<div id="filters">
|
||||
|
||||
<table class="table-condensed">
|
||||
<tr class="row">
|
||||
<td class="col">
|
||||
<label><?php echo translate('Component') ?></label>
|
||||
<select class="form-control chosen" id="filter[Component]" data-on-change="filterLog"><option value="">-----</option></select>
|
||||
</td>
|
||||
<td class="col">
|
||||
<label><?php echo translate('Server') ?></label>
|
||||
<select class="form-control chosen" id="filter[ServerId]" data-on-change="filterLog"><option value="">-----</option></select>
|
||||
</td>
|
||||
<td class="col">
|
||||
<label><?php echo translate('Pid') ?></label>
|
||||
<select class="form-control chosen" id="filter[Pid]" data-on-change="filterLog"><option value="">-----</option></select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="row">
|
||||
<td class="col">
|
||||
<label><?php echo translate('Level') ?></label>
|
||||
<select class="form-control chosen" id="filter[Level]" data-on-change="filterLog"><option value="">---</option></select>
|
||||
</td>
|
||||
<td class="col">
|
||||
<label><?php echo translate('File') ?></label>
|
||||
<select class="form-control chosen" id="filter[File]" data-on-change="filterLog"><option value="">------</option></select>
|
||||
</td>
|
||||
<td class="col">
|
||||
<label><?php echo translate('Line') ?></label>
|
||||
<select class="form-control chosen" id="filter[Line]" data-on-change="filterLog"><option value="">----</option></select>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<button type="reset" data-on-click="resetLog"><?php echo translate('Reset') ?></button>
|
||||
</div>
|
||||
<input type="hidden" name="view" value="<?php echo $view ?>"/>
|
||||
<table id="logTable" class="major">
|
||||
<thead class="thead-highlight">
|
||||
<tr>
|
||||
<th><?php echo translate('DateTime') ?></th>
|
||||
<th class="table-th-nosort"><?php echo translate('Component') ?></th>
|
||||
<th class="table-th-nosort"><?php echo translate('Server') ?></th>
|
||||
<th class="table-th-nosort"><?php echo translate('Pid') ?></th>
|
||||
<th class="table-th-nosort"><?php echo translate('Level') ?></th>
|
||||
<th class="table-th-nosort"><?php echo translate('Message') ?></th>
|
||||
<th class="table-th-nosort"><?php echo translate('File') ?></th>
|
||||
<th class="table-th-nosort"><?php echo translate('Line') ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
<div id="contentButtons">
|
||||
<div id="logSummary" class="text-center">
|
||||
<?php echo translate('State') ?>: <span id="logState"></span>/
|
||||
<?php echo translate('Total') ?>: <span id="totalLogs"></span>/
|
||||
<?php echo translate('Available') ?>: <span id="availLogs"></span>/
|
||||
<?php echo translate('Displaying') ?>: <span id="displayLogs"></span>/
|
||||
<?php echo translate('Updated') ?>: <span id="lastUpdate"></span>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="btn-toolbar text-center">
|
||||
<div class="btn-group">
|
||||
<button type="button" data-on-click="expandLog"><?php echo translate('More') ?></button>
|
||||
<button type="button" data-on-click="clearLog"><?php echo translate('Clear') ?></button>
|
||||
<button type="button" data-on-click="refreshLog"><?php echo translate('Refresh') ?></button>
|
||||
<button type="button" data-on-click="exportLog"><?php echo translate('Export') ?></button>
|
||||
<button type="reset" data-on-click="resetLog"><?php echo translate('Reset') ?></button>
|
||||
</div>
|
||||
<div class="btn-group pull-right">
|
||||
<button type="button" data-on-click="closeWindow"><?php echo translate('Close') ?></button>
|
||||
</div>
|
||||
</div> <!--btn-->
|
||||
</div> <!--header-->
|
||||
<div id="content">
|
||||
<form id="logForm" name="logForm" method="post" action="?">
|
||||
<div class="container" id="filters">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<label><?php echo translate('Component') ?></label>
|
||||
<select class="form-control chosen" id="filter[Component]" data-on-change="filterLog"><option value="">-----</option></select>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label><?php echo translate('Server') ?></label>
|
||||
<select class="form-control chosen" id="filter[ServerId]" data-on-change="filterLog"><option value="">-----</option></select>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label><?php echo translate('Pid') ?></label>
|
||||
<select class="form-control chosen" id="filter[Pid]" data-on-change="filterLog"><option value="">-----</option></select>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label><?php echo translate('Level') ?></label>
|
||||
<select class="form-control chosen" id="filter[Level]" data-on-change="filterLog"><option value="">---</option></select>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label><?php echo translate('File') ?></label>
|
||||
<select class="form-control chosen" id="filter[File]" data-on-change="filterLog"><option value="">------</option></select>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label><?php echo translate('Line') ?></label>
|
||||
<select class="form-control chosen" id="filter[Line]" data-on-change="filterLog"><option value="">----</option></select>
|
||||
</div>
|
||||
</div><!--row-->
|
||||
</div><!--container-->
|
||||
<input type="hidden" name="view" value="<?php echo $view ?>"/>
|
||||
<table id="logTable" class="major">
|
||||
<thead class="thead-highlight">
|
||||
<tr>
|
||||
<th><?php echo translate('DateTime') ?></th>
|
||||
<th class="table-th-nosort"><?php echo translate('Component') ?></th>
|
||||
<th class="table-th-nosort"><?php echo translate('Server') ?></th>
|
||||
<th class="table-th-nosort"><?php echo translate('Pid') ?></th>
|
||||
<th class="table-th-nosort"><?php echo translate('Level') ?></th>
|
||||
<th class="table-th-nosort"><?php echo translate('Message') ?></th>
|
||||
<th class="table-th-nosort"><?php echo translate('File') ?></th>
|
||||
<th class="table-th-nosort"><?php echo translate('Line') ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
<div id="contentButtons">
|
||||
</div>
|
||||
</div><!--content-->
|
||||
</form>
|
||||
</div><!--page-->
|
||||
<div id="exportLog" class="overlay">
|
||||
<div class="overlayHeader">
|
||||
<div class="overlayTitle"><?php echo translate('ExportLog') ?></div>
|
||||
|
@ -142,8 +131,8 @@ xhtmlHeaders(__FILE__, translate('SystemLog') );
|
|||
<button type="button" id="exportButton" value="Export" data-on-click="exportRequest"><?php echo translate('Export') ?></button>
|
||||
<button type="button" value="Cancel" class="overlayCloser"><?php echo translate('Cancel') ?></button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div><!--overlayContent-->
|
||||
</div><!--overlaybody-->
|
||||
</div><!-- exportLog-->
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1104,8 +1104,10 @@ echo htmlSelect('newMonitor[OutputContainer]', $videowriter_containers, $monitor
|
|||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><?php echo translate('OptionalEncoderParam') ?></td>
|
||||
<td><textarea name="newMonitor[EncoderParameters]" rows="4" cols="36"><?php echo validHtmlStr($monitor->EncoderParameters()) ?></textarea></td>
|
||||
<td><?php echo translate('OptionalEncoderParam') ?> (<?php echo makePopupLink('?view=optionhelp&option=OPTIONS_ENCODER_PARAMETERS', 'zmOptionHelp', 'optionhelp', '?' ) ?>)</td>
|
||||
<td>
|
||||
<textarea name="newMonitor[EncoderParameters]" rows="<?php echo count(explode("\n", $monitor->EncoderParameters())); ?>"><?php echo validHtmlStr($monitor->EncoderParameters()) ?></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td><?php echo translate('RecordAudio') ?></td><td>
|
||||
<?php if ( $monitor->Type() == 'Ffmpeg' ) { ?>
|
||||
|
@ -1191,7 +1193,7 @@ if ( canEdit('Control') ) {
|
|||
</tr>
|
||||
<tr>
|
||||
<td><?php echo translate('ControlAddress') ?></td>
|
||||
<td><input type="text" name="newMonitor[ControlAddress]" value="<?php echo validHtmlStr($monitor->ControlAddress()) ?>"/></td>
|
||||
<td><input type="text" name="newMonitor[ControlAddress]" value="<?php echo validHtmlStr($monitor->ControlAddress()) ? : 'user:port@ip' ?>"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><?php echo translate('AutoStopTimeout') ?></td>
|
||||
|
|
|
@ -56,54 +56,54 @@ xhtmlHeaders(__FILE__, translate('Options'));
|
|||
?>
|
||||
<body>
|
||||
<?php echo getNavBarHTML(); ?>
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-sm-2 sidebar">
|
||||
<ul class="nav nav-pills nav-stacked">
|
||||
<div class="container-fluid h-100">
|
||||
<div class="row flex-nowrap h-100">
|
||||
<nav id="sidebar h-100">
|
||||
<ul class="nav nav-pills flex-column h-100">
|
||||
<?php
|
||||
foreach ( $tabs as $name=>$value ) {
|
||||
?>
|
||||
<li<?php echo $tab == $name ? ' class="active"' : '' ?>><a href="?view=<?php echo $view ?>&tab=<?php echo $name ?>"><?php echo $value ?></a></li>
|
||||
<li class="nav-item form-control-sm my-1"><a class="nav-link<?php echo $tab == $name ? ' active' : '' ?>" href="?view=<?php echo $view ?>&tab=<?php echo $name ?>"><?php echo $value ?></a></li>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-sm-10 col-sm-offset-2">
|
||||
</nav>
|
||||
<div class="col-sm-10 col-sm-offset-2 h-100">
|
||||
<br/>
|
||||
<div id="options">
|
||||
<?php
|
||||
if ( $tab == 'skins' ) {
|
||||
?>
|
||||
<form name="optionsForm" class="form-horizontal" method="get" action="?">
|
||||
<form name="optionsForm" method="get" action="?">
|
||||
<input type="hidden" name="view" value="<?php echo $view ?>"/>
|
||||
<input type="hidden" name="tab" value="<?php echo $tab ?>"/>
|
||||
<div class="form-group">
|
||||
<label for="skin" class="col-sm-3 control-label"><?php echo translate('Skin')?></label>
|
||||
<div class="form-group row">
|
||||
<label for="skin" class="col-sm-3 col-form-label"><?php echo translate('Skin')?></label>
|
||||
<div class="col-sm-6">
|
||||
<select name="skin" class="form-control chosen">
|
||||
<?php
|
||||
# Have to do this stuff up here before including header.php because fof the cookie setting
|
||||
$skin_options = array_map('basename', glob('skins/*',GLOB_ONLYDIR));
|
||||
$skin_options = array_map('basename', glob('skins/*', GLOB_ONLYDIR));
|
||||
foreach ( $skin_options as $dir ) {
|
||||
echo '<option value="'.$dir.'" '.($skin==$dir ? 'SELECTED="SELECTED"' : '').'>'.$dir.'</option>';
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
<span class="help-block"><?php echo translate('SkinDescription'); ?></span>
|
||||
<span class="form-text"><?php echo translate('SkinDescription'); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="css" class="col-sm-3 control-label">CSS</label>
|
||||
<div class="form-group row">
|
||||
<label for="css" class="col-sm-3 col-form-label">CSS</label>
|
||||
<div class="col-sm-6">
|
||||
<select name="css" class="form-control chosen">
|
||||
<?php
|
||||
foreach ( array_map('basename', glob('skins/'.$skin.'/css/*',GLOB_ONLYDIR)) as $dir ) {
|
||||
foreach ( array_map('basename', glob('skins/'.$skin.'/css/*', GLOB_ONLYDIR)) as $dir ) {
|
||||
echo '<option value="'.$dir.'" '.($css==$dir ? 'SELECTED="SELECTED"' : '').'>'.$dir.'</option>';
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
<span class="help-block"><?php echo translate('CSSDescription'); ?></span>
|
||||
<span class="form-text"><?php echo translate('CSSDescription'); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="contentButtons">
|
||||
|
@ -302,8 +302,8 @@ foreach ( array_map('basename', glob('skins/'.$skin.'/css/*',GLOB_ONLYDIR)) as $
|
|||
?>
|
||||
|
||||
<form name="userForm" method="post" action="?">
|
||||
<button class="pull-left" type="submit" name="updateSelected" id="updateSelected"><?php echo translate('Update')?></button>
|
||||
<button class="btn-danger pull-right" type="submit" name="revokeAllTokens" id="revokeAllTokens"><?php echo translate('RevokeAllTokens')?></button>
|
||||
<button class="float-left" type="submit" name="updateSelected" id="updateSelected"><?php echo translate('Update')?></button>
|
||||
<button class="btn-danger float-right" type="submit" name="revokeAllTokens" id="revokeAllTokens"><?php echo translate('RevokeAllTokens')?></button>
|
||||
<br/>
|
||||
<?php
|
||||
function revokeAllTokens() {
|
||||
|
@ -429,7 +429,7 @@ foreach ( array_map('basename', glob('skins/'.$skin.'/css/*',GLOB_ONLYDIR)) as $
|
|||
$configCats[$tab]['ZM_TIMEZONE']['Hint'] = array(''=> translate('TZUnset')) + timezone_list();
|
||||
} # end if tab == system
|
||||
?>
|
||||
<form name="optionsForm" class="form-horizontal" method="post" action="?">
|
||||
<form name="optionsForm" class="" method="post" action="?">
|
||||
<input type="hidden" name="view" value="<?php echo $view ?>"/>
|
||||
<input type="hidden" name="tab" value="<?php echo $tab ?>"/>
|
||||
<input type="hidden" name="action" value="options"/>
|
||||
|
@ -439,9 +439,9 @@ foreach ( array_map('basename', glob('skins/'.$skin.'/css/*',GLOB_ONLYDIR)) as $
|
|||
$shortName = preg_replace( '/^ZM_/', '', $name );
|
||||
$optionPromptText = !empty($OLANG[$shortName])?$OLANG[$shortName]['Prompt']:$value['Prompt'];
|
||||
?>
|
||||
<div class="form-group">
|
||||
<label for="<?php echo $name ?>" class="col-sm-3 control-label"><?php echo $shortName ?></label>
|
||||
<div class="col-sm-6">
|
||||
<div class="form-group form-row">
|
||||
<label for="<?php echo $name ?>" class="col-md-4 control-label text-md-right"><?php echo $shortName ?></label>
|
||||
<div class="col-md">
|
||||
<?php
|
||||
if ( $value['Type'] == 'boolean' ) {
|
||||
?>
|
||||
|
@ -456,7 +456,7 @@ foreach ( array_map('basename', glob('skins/'.$skin.'/css/*',GLOB_ONLYDIR)) as $
|
|||
$options = explode('|', $value['Hint']);
|
||||
if ( count($options) > 3 ) {
|
||||
?>
|
||||
<select class="form-control" name="newConfig[<?php echo $name ?>]"<?php echo $canEdit?'':' disabled="disabled"' ?>>
|
||||
<select class="form-control-sm" name="newConfig[<?php echo $name ?>]"<?php echo $canEdit?'':' disabled="disabled"' ?>>
|
||||
<?php
|
||||
foreach ( $options as $option ) {
|
||||
if ( preg_match('/^([^=]+)=(.+)$/', $option, $matches) ) {
|
||||
|
@ -481,7 +481,7 @@ foreach ( array_map('basename', glob('skins/'.$skin.'/css/*',GLOB_ONLYDIR)) as $
|
|||
$optionLabel = $optionValue = $option;
|
||||
}
|
||||
?>
|
||||
<label>
|
||||
<label class="font-weight-bold form-control-sm">
|
||||
<input type="radio" id="<?php echo $name.'_'.preg_replace('/[^a-zA-Z0-9]/', '', $optionValue) ?>" name="newConfig[<?php echo $name ?>]" value="<?php echo $optionValue ?>"<?php if ( $value['Value'] == $optionValue ) { ?> checked="checked"<?php } ?><?php echo $canEdit?'':' disabled="disabled"' ?>/>
|
||||
<?php echo htmlspecialchars($optionLabel) ?>
|
||||
</label>
|
||||
|
@ -492,27 +492,27 @@ foreach ( array_map('basename', glob('skins/'.$skin.'/css/*',GLOB_ONLYDIR)) as $
|
|||
<?php
|
||||
} else if ( $value['Type'] == 'text' ) {
|
||||
?>
|
||||
<textarea class="form-control" id="<?php echo $name ?>" name="newConfig[<?php echo $name ?>]" rows="5" cols="40"<?php echo $canEdit?'':' disabled="disabled"' ?>><?php echo validHtmlStr($value['Value']) ?></textarea>
|
||||
<textarea class="form-control-sm" id="<?php echo $name ?>" name="newConfig[<?php echo $name ?>]" rows="5" cols="40"<?php echo $canEdit?'':' disabled="disabled"' ?>><?php echo validHtmlStr($value['Value']) ?></textarea>
|
||||
<?php
|
||||
} else if ( $value['Type'] == 'integer' ) {
|
||||
?>
|
||||
<input type="number" class="form-control small" id="<?php echo $name ?>" name="newConfig[<?php echo $name ?>]" value="<?php echo validHtmlStr($value['Value']) ?>" <?php echo $canEdit?'':' disabled="disabled"' ?>/>
|
||||
<input type="number" class="form-control-sm" id="<?php echo $name ?>" name="newConfig[<?php echo $name ?>]" value="<?php echo validHtmlStr($value['Value']) ?>" <?php echo $canEdit?'':' disabled="disabled"' ?>/>
|
||||
<?php
|
||||
} else if ( $value['Type'] == 'hexadecimal' ) {
|
||||
?>
|
||||
<input type="text" class="form-control medium" id="<?php echo $name ?>" name="newConfig[<?php echo $name ?>]" value="<?php echo validHtmlStr($value['Value']) ?>" <?php echo $canEdit?'':' disabled="disabled"' ?>/>
|
||||
<input type="text" class="form-control-sm" id="<?php echo $name ?>" name="newConfig[<?php echo $name ?>]" value="<?php echo validHtmlStr($value['Value']) ?>" <?php echo $canEdit?'':' disabled="disabled"' ?>/>
|
||||
<?php
|
||||
} else if ( $value['Type'] == 'decimal' ) {
|
||||
?>
|
||||
<input type="text" class="form-control small" id="<?php echo $name ?>" name="newConfig[<?php echo $name ?>]" value="<?php echo validHtmlStr($value['Value']) ?>" <?php echo $canEdit?'':' disabled="disabled"' ?>/>
|
||||
<input type="text" class="form-control-sm" id="<?php echo $name ?>" name="newConfig[<?php echo $name ?>]" value="<?php echo validHtmlStr($value['Value']) ?>" <?php echo $canEdit?'':' disabled="disabled"' ?>/>
|
||||
<?php
|
||||
} else {
|
||||
?>
|
||||
<input type="text" class="form-control large" id="<?php echo $name ?>" name="newConfig[<?php echo $name ?>]" value="<?php echo validHtmlStr($value['Value']) ?>" <?php echo $canEdit?'':' disabled="disabled"' ?>/>
|
||||
<input type="text" class="form-control-sm" id="<?php echo $name ?>" name="newConfig[<?php echo $name ?>]" value="<?php echo validHtmlStr($value['Value']) ?>" <?php echo $canEdit?'':' disabled="disabled"' ?>/>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<span class="help-block"><?php echo validHtmlStr($optionPromptText) ?> (<?php echo makePopupLink( '?view=optionhelp&option='.$name, 'zmOptionHelp', 'optionhelp', '?' ) ?>)</span>
|
||||
<span class="form-text form-control-sm"><?php echo validHtmlStr($optionPromptText) ?> (<?php echo makePopupLink( '?view=optionhelp&option='.$name, 'zmOptionHelp', 'optionhelp', '?' ) ?>)</span>
|
||||
</div><!-- End .col-sm-9 -->
|
||||
</div><!-- End .form-group -->
|
||||
<?php
|
||||
|
|
|
@ -17,29 +17,33 @@
|
|||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
//
|
||||
global $running;
|
||||
|
||||
if ( !canEdit('System') ) {
|
||||
$view = 'error';
|
||||
return;
|
||||
}
|
||||
?>
|
||||
<div id="modalState" class="modal fade">
|
||||
<form class="form-horizontal" name="contentForm" method="get" action="?view=state">
|
||||
<input type="hidden" name="view" value="state"/>
|
||||
<input type="hidden" name="action" value="state"/>
|
||||
<input type="hidden" name="apply" value="1"/>
|
||||
|
||||
<div class="modal-dialog">
|
||||
<div id="modalState" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="ModalCenterTitle" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h2 class="modal-title"><?php echo translate('RunState') ?></h2>
|
||||
<button type="button" class="btn" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<h5 class="modal-title w-100 text-center" id="ModalCenterTitle"><?php echo translate('RunState') ?></h5>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<form class="" name="contentForm" method="get" action="?view=state">
|
||||
<input type="hidden" name="view" value="state"/>
|
||||
<input type="hidden" name="action" value="state"/>
|
||||
<input type="hidden" name="apply" value="1"/>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="runState" class="col-sm-3 control-label">Change State</label>
|
||||
<div class="col-sm-9">
|
||||
<label for="runState" class="col-md-3 col-form-label float-left">Change State</label>
|
||||
<div class="col-md-9">
|
||||
<select id="runState" name="runState" class="form-control">
|
||||
<?php
|
||||
if ( $running ) {
|
||||
|
@ -62,14 +66,15 @@ foreach ( $states as $state ) {
|
|||
}
|
||||
?>
|
||||
</select>
|
||||
</div><!--col-sm-9-->
|
||||
</div><!--col-md-9-->
|
||||
</div><!--form-group-->
|
||||
<div class="form-group">
|
||||
<label for="newState" class="col-sm-3 control-label"><?php echo translate('NewState') ?></label>
|
||||
<div class="col-sm-9">
|
||||
<label for="newState" class="col-md-3 col-form-label float-left"><?php echo translate('NewState') ?></label>
|
||||
<div class="col-md-9">
|
||||
<input class="form-control" type="text" id="newState"/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div> <!-- modal-body -->
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-primary" type="button" id="btnApply"><?php echo translate('Apply') ?></button>
|
||||
|
@ -79,5 +84,4 @@ foreach ( $states as $state ) {
|
|||
</div><!-- footer -->
|
||||
</div> <!-- content -->
|
||||
</div> <!-- dialog -->
|
||||
</form>
|
||||
</div> <!-- state -->
|
||||
|
|
|
@ -25,19 +25,19 @@ if ( !canEdit('System') && !$selfEdit ) {
|
|||
return;
|
||||
}
|
||||
|
||||
require('includes/User.php');
|
||||
|
||||
if ( $_REQUEST['uid'] ) {
|
||||
if ( !($newUser = dbFetchOne('SELECT * FROM Users WHERE Id = ?', NULL, ARRAY($_REQUEST['uid']))) ) {
|
||||
if ( !($newUser = new ZM\User($_REQUEST['uid'])) ) {
|
||||
$view = 'error';
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
$newUser = array();
|
||||
$newUser['Username'] = translate('NewUser');
|
||||
$newUser['Enabled'] = 1;
|
||||
$newUser['MonitorIds'] = '';
|
||||
$newUser = new ZM\User();
|
||||
$newUser->Username(translate('NewUser'));
|
||||
}
|
||||
|
||||
$monitorIds = array_flip(explode(',', $newUser['MonitorIds']));
|
||||
$monitorIds = array_flip(explode(',', $newUser->MonitorIds()));
|
||||
|
||||
$yesno = array( 0=>translate('No'), 1=>translate('Yes') );
|
||||
$nv = array( 'None'=>translate('None'), 'View'=>translate('View') );
|
||||
|
@ -55,12 +55,12 @@ foreach ( dbFetchAll($sql) as $monitor ) {
|
|||
|
||||
$focusWindow = true;
|
||||
|
||||
xhtmlHeaders(__FILE__, translate('User').' - '.$newUser['Username']);
|
||||
xhtmlHeaders(__FILE__, translate('User').' - '.$newUser->Username());
|
||||
?>
|
||||
<body>
|
||||
<div id="page">
|
||||
<div id="header">
|
||||
<h2><?php echo translate('User').' - '.validHtmlStr($newUser['Username']); ?></h2>
|
||||
<h2><?php echo translate('User').' - '.validHtmlStr($newUser->Username()); ?></h2>
|
||||
</div>
|
||||
<div id="content">
|
||||
<form id="contentForm" name="contentForm" method="post" action="?view=user">
|
||||
|
@ -72,7 +72,7 @@ if ( canEdit('System') ) {
|
|||
?>
|
||||
<tr>
|
||||
<th scope="row"><?php echo translate('Username') ?></th>
|
||||
<td><input type="text" name="newUser[Username]" value="<?php echo validHtmlStr($newUser['Username']); ?>"<?php echo $newUser['Username'] == 'admin' ? ' readonly="readonly"':''?>/></td>
|
||||
<td><input type="text" name="newUser[Username]" value="<?php echo validHtmlStr($newUser->Username()); ?>"<?php echo $newUser->Username() == 'admin' ? ' readonly="readonly"':''?>/></td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
|
@ -87,53 +87,53 @@ if ( canEdit('System') ) {
|
|||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php echo translate('Language') ?></th>
|
||||
<td><?php echo htmlSelect('newUser[Language]', $langs, $newUser['Language']) ?></td>
|
||||
<td><?php echo htmlSelect('newUser[Language]', $langs, $newUser->Language()) ?></td>
|
||||
</tr>
|
||||
<?php
|
||||
if ( canEdit('System') and ( $newUser['Username'] != 'admin' ) ) {
|
||||
if ( canEdit('System') and ( $newUser->Username() != 'admin' ) ) {
|
||||
?>
|
||||
<tr>
|
||||
<th scope="row"><?php echo translate('Enabled') ?></th>
|
||||
<td><?php echo htmlSelect('newUser[Enabled]', $yesno, $newUser['Enabled']) ?></td>
|
||||
<td><?php echo htmlSelect('newUser[Enabled]', $yesno, $newUser->Enabled()) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php echo translate('Stream') ?></th>
|
||||
<td><?php echo htmlSelect('newUser[Stream]', $nv, $newUser['Stream']) ?></td>
|
||||
<td><?php echo htmlSelect('newUser[Stream]', $nv, $newUser->Stream()) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php echo translate('Events') ?></th>
|
||||
<td><?php echo htmlSelect('newUser[Events]', $nve, $newUser['Events']) ?></td>
|
||||
<td><?php echo htmlSelect('newUser[Events]', $nve, $newUser->Events()) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php echo translate('Control') ?></th>
|
||||
<td><?php echo htmlSelect('newUser[Control]', $nve, $newUser['Control']) ?></td>
|
||||
<td><?php echo htmlSelect('newUser[Control]', $nve, $newUser->Control()) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php echo translate('Monitors') ?></th>
|
||||
<td><?php echo htmlSelect('newUser[Monitors]', $nve, $newUser['Monitors']) ?></td>
|
||||
<td><?php echo htmlSelect('newUser[Monitors]', $nve, $newUser->Monitors()) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php echo translate('Groups') ?></th>
|
||||
<td><?php echo htmlSelect('newUser[Groups]', $nve, $newUser['Groups']) ?></td>
|
||||
<td><?php echo htmlSelect('newUser[Groups]', $nve, $newUser->Groups()) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php echo translate('System') ?></th>
|
||||
<td><?php echo htmlSelect('newUser[System]', $nve, $newUser['System']) ?></td>
|
||||
<td><?php echo htmlSelect('newUser[System]', $nve, $newUser->System()) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php echo translate('MaxBandwidth') ?></th>
|
||||
<td><?php echo htmlSelect('newUser[MaxBandwidth]', $bandwidths, $newUser['MaxBandwidth']) ?></td>
|
||||
<td><?php echo htmlSelect('newUser[MaxBandwidth]', $bandwidths, $newUser->MaxBandwidth()) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><?php echo translate('RestrictedMonitors') ?></th>
|
||||
<td>
|
||||
<?php echo htmlSelect('newUser[MonitorIds][]', $monitors, explode(',', $newUser['MonitorIds']), array('multiple'=>'multiple')); ?>
|
||||
<?php echo htmlSelect('newUser[MonitorIds][]', $monitors, explode(',', $newUser->MonitorIds()), array('multiple'=>'multiple')); ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php if ( ZM_OPT_USE_API ) { ?>
|
||||
<tr>
|
||||
<th scope="row"><?php echo translate('APIEnabled')?></th>
|
||||
<td><?php echo htmlSelect('newUser[APIEnabled]', $yesno, $newUser['APIEnabled']) ?></td>
|
||||
<td><?php echo htmlSelect('newUser[APIEnabled]', $yesno, $newUser->APIEnabled()) ?></td>
|
||||
</tr>
|
||||
|
||||
<?php
|
||||
|
|
Loading…
Reference in New Issue