Merge branch 'master' into zma_to_thread

This commit is contained in:
Isaac Connor 2020-08-07 17:52:43 -04:00
commit 5fb56c9f57
82 changed files with 12733 additions and 2955 deletions

View File

@ -3,6 +3,7 @@
module.exports = {
"env": {
"browser": true,
"es6": true,
},
"extends": ["google"],
"overrides": [{

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 \

View File

@ -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

View File

@ -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

View File

@ -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})

View File

@ -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 => '',

View File

@ -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');

View File

@ -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

View 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);

View File

@ -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());

View File

@ -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,

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -78,6 +78,7 @@ class FfmpegCamera : public Camera {
#if HAVE_LIBSWSCALE
struct SwsContext *mConvertContext;
#endif
uint8_t *frame_buffer;
int error_count;

View File

@ -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]);

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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; }

View File

@ -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));

View File

@ -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();
};

View File

@ -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)

View File

@ -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 );

View File

@ -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();

View File

@ -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;
}

View File

@ -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 ) {

View File

@ -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;

View File

@ -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));

View File

@ -0,0 +1,2 @@
echo json_encode($message);
echo json_encode($zone);

View File

@ -0,0 +1,2 @@
echo json_encode($message);
echo json_encode($zone);

View File

@ -0,0 +1,2 @@
$xml = Xml::fromArray(array('response'=>$message, 'zone'=>$zone));
echo $xml->asXML();

View File

@ -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

View File

@ -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 )

View File

@ -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);
}

View File

@ -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'}) ) {

View File

@ -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");
}
?>

View File

@ -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;
}

View File

@ -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();
}
}

View File

@ -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.'

View File

@ -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;
}

View File

@ -11,6 +11,7 @@
textarea,
input[name="newMonitor[Name]"],
input[name="newMonitor[LabelFormat]"],
input[name="newMonitor[ControlDevice]"],
input[name="newMonitor[ControlAddress]"] {
width: 100%;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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],

View File

@ -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 .= '&nbsp;'.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&amp;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>&nbsp;".$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>&nbsp;".$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>&nbsp;<?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

View File

@ -0,0 +1 @@
bootstrap.min.js

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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();
}

View File

@ -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=""/>
';

View File

@ -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>
&nbsp;<?php echo translate('Select') ?>
</button>
&nbsp;<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>

View File

@ -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&amp;mid='.$m->Id().'">'.$m->Name().'</a></li>';
echo '<li class="nav-item"><a class="nav-link'.( $m->Id() == $monitor->Id() ? ' active' : '' ).'" href="?view=cycle&amp;mid='.$m->Id().'">'.$m->Name().'</a></li>';
}
?>
</ul>

View File

@ -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;

View File

@ -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(),

View File

@ -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&amp;eid='.$Event->Id().'&amp;fid='.$Frame->FrameId(), 'zmStats', 'stats', translate('Stats') ); } ?>
<?php if ( canEdit( 'Events' ) ) { ?><a href="?view=none&amp;action=delete&amp;markEid=<?php echo $Event->Id() ?>"><?php echo translate('Delete') ?></a><?php } ?>
<?php if ( canEdit('Events') ) { ?><a href="?view=none&amp;action=delete&amp;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&amp;eid=%d&amp;fid=%d&scale=%d&amp;show=%s">', $Event->Id(), $Frame->FrameId(), $scale, ( $show=='anal'?'capt':'anal' ) );
} ?>

View File

@ -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'] ?>";

View File

@ -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
//

View File

@ -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)) : '' ?>';

View File

@ -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);
}

View File

@ -1,5 +1,5 @@
window.addEventListener( 'DOMContentLoaded', function() {
if ( failed == true ) {
$('loginError').removeClass( 'hidden' );
$j('#loginError').show();
}
} );

View File

@ -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 ?>" );

View File

@ -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);

View File

@ -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() ?>};

View File

@ -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());

View File

@ -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();

View File

@ -1,3 +1,7 @@
<?php
global $filterQuery;
global $monitors;
?>
var filterQuery = '<?php echo validJsStr($filterQuery) ?>';
<?php

View File

@ -1,3 +1,10 @@
<?php
global $streamMode;
global $showPtzControls;
global $connkey;
global $monitor;
global $scale;
?>
//
// Import constants
//

View File

@ -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

View File

@ -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 = {

View File

@ -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 ?>;

View File

@ -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>

View File

@ -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') ?>&nbsp;(<?php echo makePopupLink('?view=optionhelp&amp;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>

View File

@ -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 ?>&amp;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 ?>&amp;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) ?>&nbsp;(<?php echo makePopupLink( '?view=optionhelp&amp;option='.$name, 'zmOptionHelp', 'optionhelp', '?' ) ?>)</span>
<span class="form-text form-control-sm"><?php echo validHtmlStr($optionPromptText) ?>&nbsp;(<?php echo makePopupLink( '?view=optionhelp&amp;option='.$name, 'zmOptionHelp', 'optionhelp', '?' ) ?>)</span>
</div><!-- End .col-sm-9 -->
</div><!-- End .form-group -->
<?php

View File

@ -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">&times;</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">&times;</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 -->

View File

@ -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