Compare commits

..

29 Commits

Author SHA1 Message Date
Isaac Connor bdb9acc0fe Release lock before notify 2022-02-20 10:35:22 -05:00
Isaac Connor 484827bdeb Should get lock before testing for connected 2022-02-20 10:33:45 -05:00
Isaac Connor aaf391fc65 Include EndDateTimeShort in event ajax response 2022-02-17 13:32:36 -05:00
Isaac Connor 8822463ac7 Handle empty endtime more gracefully. If there is a next event just jump to it. 2022-02-17 13:32:10 -05:00
Isaac Connor 9cc17024c5 Include EndDateTimeShort in event stats 2022-02-17 13:31:57 -05:00
Isaac Connor 687818e1ec Convert Fatal()s to Errors() which is really more appropriate anyways. Maybe Fixes #3426 2022-02-08 18:11:33 -05:00
Isaac Connor 3abacfa488 Change title of settings button to give an indication WHY it isn't enabled 2022-02-08 17:51:21 -05:00
Isaac Connor 66336106ca When device isn't specified, pass nullptr. Currently zmc device probing is broken. This fixes it. Not needed for master. 2022-02-08 17:43:26 -05:00
Isaac Connor 2396e98fb9 detaint language file. 2022-02-08 14:17:30 -05:00
Isaac Connor 6268652520 Test for valid language file when saving user. 2022-02-08 14:16:50 -05:00
Isaac Connor b10bb9d8b0 Use getBodyTopHTML so that we get error messages in UI 2022-02-08 13:37:39 -05:00
Isaac Connor 2b0398b35a Change the error message banner to always take up space and be seen. 2022-02-08 13:37:39 -05:00
Isaac Connor 5b9ccc6889 Implement a check on change of language. Make sure that the specified language file exists. Reports errors to UI 2022-02-08 13:37:39 -05:00
Isaac Connor 9973b1fbaf Move the version detection down to after we have a repo and hence a commit history on version. Fixes CURRENT builds always being commit 0 2022-02-02 20:56:41 -05:00
Isaac Connor df16099463 Default limit to 0 which means no limit 2022-02-02 11:02:34 -05:00
Isaac Connor b28f97c5c3 Implement filter limits. Which go before pagination/advanced search limits 2022-02-02 10:50:28 -05:00
Isaac Connor 4501a7c2a1 Remove field that ffmpeg 5.0 doesn't have. 2022-02-01 07:25:13 -05:00
Isaac Connor 0125efb93e add some brackets to make logic more clear 2022-01-25 14:25:27 -05:00
Isaac Connor 1bdb4f302c Fix mTerminate not being initialised. 2022-01-25 14:25:13 -05:00
Isaac Connor df7e34a51d Remove the decoding code, just populate the av_packet. This fixes rtsp decoding because we weren't copying the decoded frame to shm raw image. 2022-01-25 14:24:52 -05:00
Isaac Connor 988f118ba9 Fix fail to get Sources in RTSP. the string msg although initially reserved to ZM_NETWORK_BUFSIZ, after use it's capacity is changed whatever it's contents are. So need to re-reserve. 2022-01-25 12:07:32 -05:00
Isaac Connor ae17b2316e break out when zm_terminate is true 2022-01-24 20:07:14 -05:00
Isaac Connor 8891feec74 Fix missing text-right align on Port/Path labels. Set step to 1 for Port 2022-01-24 18:31:31 -05:00
Isaac Connor 42d5101f08 Make Remote Host 100% 2022-01-24 18:31:05 -05:00
Isaac Connor 01030e9850 Preface Debug with ZM 2022-01-13 22:15:29 -05:00
Isaac Connor 9893d37bf1 include user and function error message about insufficient permissions. Will make it easier to figure out who tried what. 2021-12-14 12:26:47 -05:00
makers-mark 9f8fc65cd3 Update zm_update-1.35.25.sql 2021-12-14 10:27:07 -05:00
Isaac Connor 4a51253aa9 Fix auth not getting realm from auth headers due to them being an array now. Get auth and ip from Path if not set in ControlAddress. 2021-12-14 10:26:17 -05:00
Isaac Connor 3ee649406c Warning=>Debug when -1 is passed to GetImage 2021-12-14 10:25:48 -05:00
37 changed files with 279 additions and 988 deletions

View File

@ -56,7 +56,7 @@ EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Monitor_Status'
AND column_name = 'DayEvents'
AND column_name = 'DayEventDiskSpace'
) > 0,
"ALTER TABLE `Monitor_Status` DROP `DayEventDiskSpace`",
"SELECT 'Column DayEventDiskSpace already removed from Monitor_Status'"

@ -1 +1 @@
Subproject commit cd7fd49becad6010a1b8466bfebbd93999a39878
Subproject commit eab32851421ffe54fec0229c3efc44c642bc8d46

View File

@ -51,11 +51,21 @@ sub open {
my $self = shift;
$self->loadMonitor();
if ( $self->{Monitor}->{ControlAddress} !~ /^\w+:\/\// ) {
# Has no scheme at the beginning, so won't parse as a URI
$self->{Monitor}->{ControlAddress} = 'http://'.$self->{Monitor}->{ControlAddress};
}
$uri = URI->new($self->{Monitor}->{ControlAddress});
if ($self->{Monitor}->{ControlAddress} and ($self->{Monitor}->{ControlAddress} ne 'user:pass@ip')) {
Debug("Getting connection details from Control Address " . $self->{Monitor}->{ControlAddress});
if ( $self->{Monitor}->{ControlAddress} !~ /^\w+:\/\// ) {
# Has no scheme at the beginning, so won't parse as a URI
$self->{Monitor}->{ControlAddress} = 'http://'.$self->{Monitor}->{ControlAddress};
}
$uri = URI->new($self->{Monitor}->{ControlAddress});
} elsif ($self->{Monitor}->{Path}) {
Debug("Getting connection details from Path " . $self->{Monitor}->{Path});
$uri = URI->new($self->{Monitor}->{Path});
$uri->scheme('http');
$uri->port(80);
$uri->path('');
}
use LWP::UserAgent;
$self->{ua} = LWP::UserAgent->new;
@ -64,6 +74,7 @@ sub open {
$self->{state} = 'closed';
my ( $username, $password, $host ) = ( $uri->authority() =~ /^([^:]+):([^@]*)@(.+)$/ );
Debug("Have username: $username password: $password host: $host from authority:" . $uri->authority());
$uri->userinfo(undef);
@ -75,40 +86,47 @@ sub open {
# test auth
my $res = $self->{ua}->get($uri->canonical().$url);
if ( $res->is_success ) {
if ( $res->content() ne "Properties.PTZ.PTZ=yes\n" ) {
if ($res->is_success) {
if ($res->content() ne "Properties.PTZ.PTZ=yes\n") {
Warning('Response suggests that camera doesn\'t support PTZ. Content:('.$res->content().')');
}
$self->{state} = 'open';
return;
}
if ($res->status_line() eq '404 Not Found') {
#older style
$url = 'axis-cgi/com/ptz.cgi';
$res = $self->{ua}->get($uri->canonical().$url);
Debug("Result from getting ".$uri->canonical().$url . ':' . $res->status_line());
}
if ( $res->status_line() eq '401 Unauthorized' ) {
if ($res->status_line() eq '401 Unauthorized') {
my $headers = $res->headers();
foreach my $k ( keys %$headers ) {
Debug("Initial Header $k => $$headers{$k}");
}
if ( $$headers{'www-authenticate'} ) {
my ( $auth, $tokens ) = $$headers{'www-authenticate'} =~ /^(\w+)\s+(.*)$/;
if ( $tokens =~ /\w+="([^"]+)"/i ) {
if ( $realm ne $1 ) {
$realm = $1;
$self->{ua}->credentials($uri->host_port(), $realm, $username, $password);
$res = $self->{ua}->get($uri->canonical().$url);
if ( $res->is_success() ) {
Info("Auth succeeded after setting realm to $realm. You can set this value in the Control Device field to speed up connections and remove these log entries.");
$self->{state} = 'open';
return;
foreach my $auth_header ( ref $$headers{'www-authenticate'} eq 'ARRAY' ? @{$$headers{'www-authenticate'}} : ($$headers{'www-authenticate'})) {
my ( $auth, $tokens ) = $auth_header =~ /^(\w+)\s+(.*)$/;
if ( $tokens =~ /\w+="([^"]+)"/i ) {
if ( $realm ne $1 ) {
$realm = $1;
$self->{ua}->credentials($uri->host_port(), $realm, $username, $password);
$res = $self->{ua}->get($uri->canonical().$url);
if ( $res->is_success() ) {
Info("Auth succeeded after setting realm to $realm. You can set this value in the Control Device field to speed up connections and remove these log entries.");
$self->{state} = 'open';
return;
}
Error('Authentication still failed after updating REALM status: '.$res->status_line);
} else {
Error('Authentication failed, not a REALM problem');
}
Error('Authentication still failed after updating REALM status: '.$res->status_line);
} else {
Error('Authentication failed, not a REALM problem');
}
} else {
Error('Failed to match realm in tokens');
} # end if
Error('Failed to match realm in tokens');
} # end if
} # end foreach auth header
} else {
Debug('No headers line');
} # end if headers

View File

@ -244,6 +244,7 @@ class Socket : public CommsBase {
}
virtual ssize_t recv(std::string &msg) const {
msg.reserve(ZM_NETWORK_BUFSIZ);
std::vector<char> buffer(msg.capacity());
ssize_t nBytes;
if ((nBytes = ::recv(mSd, buffer.data(), buffer.size(), 0)) < 0) {

View File

@ -107,8 +107,8 @@ bool zmDbConnect() {
}
void zmDbClose() {
std::lock_guard<std::mutex> lck(db_mutex);
if (zmDbConnected) {
std::lock_guard<std::mutex> lck(db_mutex);
mysql_close(&dbconn);
// mysql_init() call implicitly mysql_library_init() but
// mysql_close() does not call mysql_library_end()
@ -237,8 +237,12 @@ zmDbQueue::~zmDbQueue() {
}
void zmDbQueue::stop() {
mTerminate = true;
{
std::unique_lock<std::mutex> lock(mMutex);
mTerminate = true;
}
mCondition.notify_all();
if (mThread.joinable()) mThread.join();
}

View File

@ -295,8 +295,8 @@ void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output)
Debug(1, "ids [0x%x]", st->id);
if (lang)
Debug(1, "language (%s)", lang->value);
Debug(1, "frames:%d, frame_size:%d stream timebase: %d/%d",
st->codec_info_nb_frames, codec->frame_size,
Debug(1, "frame_size:%d stream timebase: %d/%d",
codec->frame_size,
st->time_base.num, st->time_base.den
);

View File

@ -1175,7 +1175,7 @@ void Monitor::AddPrivacyBitmask() {
int Monitor::GetImage(int32_t index, int scale) {
if (index < 0 || index > image_buffer_count) {
Warning("Invalid index %d passed. image_buffer_count = %d", index, image_buffer_count);
Debug(1, "Invalid index %d passed. image_buffer_count = %d", index, image_buffer_count);
index = shared_data->last_write_index;
}
if (!image_buffer.size() or static_cast<size_t>(index) >= image_buffer.size()) {

View File

@ -22,6 +22,7 @@
#include "zm_config.h"
#include "zm_monitor.h"
#include "zm_packet.h"
#include "zm_signal.h"
#if HAVE_LIBAVFORMAT
@ -128,7 +129,7 @@ int RemoteCameraRtsp::Disconnect() {
int RemoteCameraRtsp::PrimeCapture() {
Debug(2, "Waiting for sources");
for ( int i = 0; (i < 100) && !rtspThread->hasSources(); i++ ) {
for ( int i = 100; i &&zm_terminate && !rtspThread->hasSources(); i-- ) {
usleep(100000);
}
if ( !rtspThread->hasSources() ) {
@ -169,8 +170,10 @@ int RemoteCameraRtsp::PrimeCapture() {
}
} // end foreach stream
if ( mVideoStreamId == -1 )
Fatal("Unable to locate video stream");
if ( mVideoStreamId == -1 ) {
Error("Unable to locate video stream");
return -1;
}
if ( mAudioStreamId == -1 )
Debug(3, "Unable to locate audio stream");
@ -184,8 +187,10 @@ int RemoteCameraRtsp::PrimeCapture() {
// Find the decoder for the video stream
AVCodec *codec = avcodec_find_decoder(mVideoCodecContext->codec_id);
if ( codec == nullptr )
Panic("Unable to locate codec %d decoder", mVideoCodecContext->codec_id);
if ( codec == nullptr ) {
Error("Unable to locate codec %d decoder", mVideoCodecContext->codec_id);
return -1;
}
// Open codec
#if !LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 8, 0)
@ -193,7 +198,10 @@ int RemoteCameraRtsp::PrimeCapture() {
#else
if ( avcodec_open2(mVideoCodecContext, codec, 0) < 0 )
#endif
Panic("Can't open codec");
{
Error("Can't open codec");
return -1;
}
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
int pSize = av_image_get_buffer_size(imagePixFormat, width, height, 1);
@ -202,7 +210,8 @@ int RemoteCameraRtsp::PrimeCapture() {
#endif
if ( (unsigned int)pSize != imagesize ) {
Fatal("Image size mismatch. Required: %d Available: %llu", pSize, imagesize);
Error("Image size mismatch. Required: %d Available: %llu", pSize, imagesize);
return -1;
}
return 1;
@ -221,18 +230,13 @@ int RemoteCameraRtsp::PreCapture() {
int RemoteCameraRtsp::Capture(std::shared_ptr<ZMPacket> &zm_packet) {
int frameComplete = false;
AVPacket *packet = &zm_packet->packet;
if ( !zm_packet->image ) {
Debug(1, "Allocating image %dx%d %d colours %d", width, height, colours, subpixelorder);
zm_packet->image = new Image(width, height, colours, subpixelorder);
}
while (!frameComplete) {
buffer.clear();
if (!rtspThread || rtspThread->IsStopped())
return -1;
if ( rtspThread->getFrame(buffer) ) {
if (rtspThread->getFrame(buffer)) {
Debug(3, "Read frame %d bytes", buffer.size());
Hexdump(4, buffer.head(), 16);
@ -267,49 +271,20 @@ int RemoteCameraRtsp::Capture(std::shared_ptr<ZMPacket> &zm_packet) {
//while ( (!frameComplete) && (buffer.size() > 0) ) {
if ( buffer.size() > 0 ) {
packet->data = buffer.head();
packet->data = (uint8_t*)av_malloc(buffer.size());
memcpy(packet->data, buffer.head(), buffer.size());
//packet->data = buffer.head();
packet->size = buffer.size();
bytes += packet->size;
buffer -= packet->size;
struct timeval now;
gettimeofday(&now, NULL);
gettimeofday(&now, nullptr);
packet->pts = packet->dts = now.tv_sec*1000000+now.tv_usec;
int bytes_consumed = zm_packet->decode(mVideoCodecContext);
if ( bytes_consumed < 0 ) {
Error("Error while decoding frame %d", frameCount);
//Hexdump(Logger::ERROR, buffer.head(), buffer.size()>256?256:buffer.size());
}
buffer -= packet->size;
if ( bytes_consumed ) {
zm_dump_video_frame(zm_packet->in_frame, "remote_rtsp_decode");
if ( ! mVideoStream->
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
codecpar
#else
codec
#endif
->width ) {
zm_dump_codec(mVideoCodecContext);
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
zm_dump_codecpar(mVideoStream->codecpar);
mVideoStream->codecpar->width = zm_packet->in_frame->width;
mVideoStream->codecpar->height = zm_packet->in_frame->height;
#else
mVideoStream->codec->width = zm_packet->in_frame->width;
mVideoStream->codec->height = zm_packet->in_frame->height;
#endif
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
zm_dump_codecpar(mVideoStream->codecpar);
#endif
}
zm_packet->codec_type = mVideoCodecContext->codec_type;
zm_packet->stream = mVideoStream;
frameComplete = true;
Debug(2, "Frame: %d - %d/%d", frameCount, bytes_consumed, buffer.size());
packet->data = nullptr;
packet->size = 0;
}
zm_packet->codec_type = mVideoCodecContext->codec_type;
zm_packet->stream = mVideoStream;
frameComplete = true;
Debug(2, "Frame: %d - %d/%d", frameCount, packet->size, buffer.size());
}
} /* getFrame() */
} // end while true

View File

@ -279,7 +279,7 @@ void RtpCtrlThread::Run() {
time_t last_receive = time(nullptr);
bool timeout = false; // used as a flag that we had a timeout, and then sent an RR to see if we wake back up. Real timeout will happen when this is true.
while (!mTerminate && select.wait() >= 0) {
while (!mTerminate && (select.wait() >= 0)) {
time_t now = time(nullptr);
ZM::Select::CommsList readable = select.getReadable();
if ( readable.size() == 0 ) {

View File

@ -47,8 +47,10 @@ RtpSource::RtpSource(
mFrame(65536),
mFrameCount(0),
mFrameGood(true),
prevM(false),
mFrameReady(false),
mFrameProcessed(false)
mFrameProcessed(false),
mTerminate(false)
{
char hostname[256] = "";
gethostname(hostname, sizeof(hostname));

View File

@ -92,8 +92,6 @@ private:
bool mFrameGood;
bool prevM;
bool mTerminate;
bool mFrameReady;
std::condition_variable mFrameReadyCv;
std::mutex mFrameReadyMutex;
@ -101,6 +99,7 @@ private:
bool mFrameProcessed;
std::condition_variable mFrameProcessedCv;
std::mutex mFrameProcessedMutex;
bool mTerminate;
private:
void init(uint16_t seq);

View File

@ -486,7 +486,7 @@ int main(int argc, char *argv[]) {
exit_zmu(-1);
}
if ( !ValidateAccess(user, mon_id, function) ) {
Error("Insufficient privileges for requested action");
Error("Insufficient privileges for user %s for requested function %x", username, function);
exit_zmu(-1);
}
} // end if auth
@ -730,7 +730,7 @@ int main(int argc, char *argv[]) {
if ( function & ZMU_QUERY ) {
#if ZM_HAS_V4L
char vidString[0x10000] = "";
bool ok = LocalCamera::GetCurrentSettings(device.c_str(), vidString, v4lVersion, verbose);
bool ok = LocalCamera::GetCurrentSettings(device.empty()?nullptr:device.c_str(), vidString, v4lVersion, verbose);
printf("%s", vidString);
exit_zmu(ok ? 0 : -1);
#else // ZM_HAS_V4L

View File

@ -136,13 +136,6 @@ else
echo "Defaulting to master branch";
BRANCH="master";
fi;
if [ "$SNAPSHOT" == "NOW" ]; then
SNAPSHOT=`date +%Y%m%d%H%M%S`;
else
if [ "$SNAPSHOT" == "CURRENT" ]; then
SNAPSHOT="`date +%Y%m%d.`$(git rev-list ${versionhash}..HEAD --count)"
fi;
fi;
fi;
fi
@ -150,6 +143,8 @@ if [ "$PACKAGE_VERSION" == "NOW" ]; then
PACKAGE_VERSION=`date +%Y%m%d%H%M%S`;
else
if [ "$PACKAGE_VERSION" == "CURRENT" ]; then
# git the latest (short) commit hash of the version file
versionhash=$(git log -n1 --pretty=format:%h version)
PACKAGE_VERSION="`date +%Y%m%d.`$(git rev-list ${versionhash}..HEAD --count)"
fi;
fi;
@ -200,10 +195,19 @@ else
fi;
cd "${GITHUB_FORK}_zoneminder_release"
git checkout $BRANCH
cd ../
git checkout $BRANCH
VERSION=`cat ${GITHUB_FORK}_zoneminder_release/version`
VERSION=`cat version`
if [ "$SNAPSHOT" == "NOW" ]; then
SNAPSHOT=`date +%Y%m%d%H%M%S`;
else
if [ "$SNAPSHOT" == "CURRENT" ]; then
# git the latest (short) commit hash of the version file
versionhash=$(git log -n1 --pretty=format:%h version)
SNAPSHOT="`date +%Y%m%d.`$(git rev-list ${versionhash}..HEAD --count)"
fi;
fi;
cd ../
if [ -z "$VERSION" ]; then
exit 1;

View File

@ -182,6 +182,9 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim
$sort = $sort == 'Monitor' ? 'M.Name' : 'E.'.$sort;
$col_str = 'E.*, M.Name AS Monitor';
$sql = 'SELECT ' .$col_str. ' FROM `Events` AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id'.$where.' ORDER BY '.$sort.' '.$order;
if ($filter->limit() and !count($filter->pre_sql_conditions()) and !count($filter->post_sql_conditions())) {
$sql .= ' LIMIT '.$filter->limit();
}
$storage_areas = ZM\Storage::find();
$StorageById = array();
@ -208,6 +211,12 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim
$unfiltered_rows[] = $row;
} # end foreach row
# Filter limits come before pagination limits.
if ($filter->limit() and ($filter->limit() > count($unfiltered_rows))) {
ZM\Debug("Filtering rows due to filter->limit " . count($unfiltered_rows)." limit: ".$filter->limit());
$unfiltered_rows = array_slice($unfiltered_rows, 0, $filter->limit());
}
ZM\Debug('Have ' . count($unfiltered_rows) . ' events matching base filter.');
$filtered_rows = null;
@ -246,8 +255,10 @@ function queryRequest($filter, $search, $advsearch, $sort, $offset, $order, $lim
$filtered_rows = $unfiltered_rows;
} # end if search_filter->terms() > 1
if ($limit)
if ($limit) {
ZM\Debug("Filtering rows due to limit " . count($filtered_rows)." offset: $offset limit: $limit");
$filtered_rows = array_slice($filtered_rows, $offset, $limit);
}
$returned_rows = array();
foreach ($filtered_rows as $row) {

View File

@ -112,6 +112,7 @@ $statusData = array(
'StartTimeShort' => array( 'sql' => 'date_format( StartDateTime, \''.MYSQL_FMT_DATETIME_SHORT.'\' )' ),
'StartDateTimeShort' => array( 'sql' => 'date_format( StartDateTime, \''.MYSQL_FMT_DATETIME_SHORT.'\' )' ),
'EndDateTime' => true,
'EndDateTimeShort' => array( 'sql' => 'date_format( EndDateTime, \''.MYSQL_FMT_DATETIME_SHORT.'\' )' ),
'Width' => true,
'Height' => true,
'Length' => true,
@ -140,6 +141,7 @@ $statusData = array(
'StartTimeShort' => array( 'sql' => 'date_format( StartDateTime, \''.MYSQL_FMT_DATETIME_SHORT.'\' )' ),
'StartDateTimeShort' => array( 'sql' => 'date_format( StartDateTime, \''.MYSQL_FMT_DATETIME_SHORT.'\' )' ),
'EndDateTime' => true,
'EndDateTimeShort' => array( 'sql' => 'date_format( EndDateTime, \''.MYSQL_FMT_DATETIME_SHORT.'\' )' ),
'Width' => true,
'Height' => true,
'Length' => true,

View File

@ -227,7 +227,7 @@ class Filter extends ZM_Object {
}
if ( isset( $this->Query()['limit'] ) )
return $this->{'Query'}['limit'];
return 100;
return 0;
#return $this->defaults{'limit'};
}

View File

@ -24,6 +24,8 @@ if ( !canEdit('System') ) {
return;
}
global $error_message;
if ( $action == 'delete' ) {
if ( isset($_REQUEST['object']) ) {
if ( $_REQUEST['object'] == 'server' ) {
@ -65,10 +67,19 @@ if ( $action == 'delete' ) {
}
if ( isset($newValue) && ($newValue != $config['Value']) ) {
# Handle special cases first
if ($config['Name'] == 'ZM_LANG_DEFAULT') {
# Verify that the language file exists in the lang directory.
if (!file_exists(ZM_PATH_WEB.'/lang/'.$newValue.'.php')) {
$error_message .= 'Error setting ' . $config['Name'].'. New value ' .$newValue.' not saved because '.ZM_PATH_WEB.'/lang/'.$newValue.'.php doesn\'t exist.<br/>';
ZM\Error($error_message);
continue;
}
}
dbQuery('UPDATE Config SET Value=? WHERE Name=?', array($newValue, $config['Name']));
$changed = true;
}
}
} # end if value changed
} # end foreach config entry
if ( $changed ) {
switch ( $_REQUEST['tab'] ) {
case 'system' :

View File

@ -44,12 +44,21 @@ if ($action == 'Save') {
} else {
unset($_REQUEST['newUser']['Password']);
}
if (isset($_REQUEST['newUser']['Language']) and $_REQUEST['newUser']['Language']) {
# Verify that the language file exists in the lang directory.
if (!file_exists(ZM_PATH_WEB.'/lang/'.$_REQUEST['newUser']['Language'].'.php')) {
$error_message .= 'Error setting Language. New value ' .$_REQUEST['newUser']['Language'].' not saved because '.ZM_PATH_WEB.'/lang/'.$_REQUEST['newUser']['Language'].'.php doesn\'t exist.<br/>';
ZM\Error($error_message);
unset($_REQUEST['newUser']['Language']);
unset($_REQUEST['redirect']);
}
}
$changes = $dbUser->changes($_REQUEST['newUser']);
ZM\Debug("Changes: " . print_r($changes, true));
ZM\Debug('Changes: ' . print_r($changes, true));
if (count($changes)) {
if (!$dbUser->save($changes)) {
$error_message = $dbUser->get_last_error();
$error_message .= $dbUser->get_last_error().'<br/>';
unset($_REQUEST['redirect']);
return;
}
@ -73,6 +82,15 @@ if ($action == 'Save') {
} else {
unset($_REQUEST['newUser']['Password']);
}
if (isset($_REQUEST['newUser']['Language']) and $_REQUEST['newUser']['Language']) {
# Verify that the language file exists in the lang directory.
if (!file_exists(ZM_PATH_WEB.'/lang/'.$_REQUEST['newUser']['Language'].'.php')) {
$error_message .= 'Error setting Language. New value ' .$_REQUEST['newUser']['Language'].' not saved because '.ZM_PATH_WEB.'/lang/'.$_REQUEST['newUser']['Language'].'.php doesn\'t exist.<br/>';
ZM\Error($error_message);
unset($_REQUEST['newUser']['Language']);
unset($_REQUEST['redirect']);
}
}
$fields = array('Password'=>'', 'Language'=>'', 'HomeView'=>'');
ZM\Debug("changes: ".print_r(array_intersect_key($_REQUEST['newUser'], $fields),true));
$changes = $dbUser->changes(array_intersect_key($_REQUEST['newUser'], $fields));
@ -80,7 +98,7 @@ if ($action == 'Save') {
if (count($changes)) {
if (!$dbUser->save($changes)) {
$error_message = $dbUser->get_last_error();
$error_message .= $dbUser->get_last_error();
unset($_REQUEST['redirect']);
return;
}

View File

@ -348,7 +348,7 @@ return false;
return $value === csrf_hash($_COOKIE[$n], $time);
case 'key':
if (!$GLOBALS['csrf']['key']) {
Debug("Checking key: no key set" );
ZM\Debug("Checking key: no key set" );
return false;
}
#Debug("Checking sid: $value === " . csrf_hash($GLOBALS['csrf']['key'], $time) );

View File

@ -30,20 +30,21 @@ function translate($name) {
function loadLanguage($prefix='') {
global $user;
if ( $prefix )
if ($prefix)
$prefix = $prefix.'/';
if ( isset($user['Language']) and $user['Language'] ) {
$userLangFile = $prefix.'lang/'.$user['Language'].'.php';
if (isset($user['Language']) and $user['Language']) {
# Languages can only have letters, numbers and underscore
$userLangFile = $prefix.'lang/'.preg_replace('/[^[:alnum:]_]+/', '', $user['Language']).'.php';
if ( file_exists($userLangFile) ) {
if (file_exists($userLangFile)) {
return $userLangFile;
} else {
ZM\Warning("User language file $userLangFile does not exist.");
}
}
$systemLangFile = $prefix.'lang/'.ZM_LANG_DEFAULT.'.php';
$systemLangFile = $prefix.'lang/'.preg_replace('/[^[:alnum:]_]+/', '', ZM_LANG_DEFAULT).'.php';
if ( file_exists($systemLangFile) ) {
return $systemLangFile;
} else {

View File

@ -340,6 +340,14 @@ ul.tabList li.active a {
.alarm, .errorText, .error {
color: #ff3f34;
}
/* Refers to the error box at the top of the web UI */
#error {
width: 100%;
padding: 5px;
font-weight: bold;
background-color: white;
color: #ff3f34;
}
.timedErrorBox {
color:white;

View File

@ -10,6 +10,7 @@
}
textarea,
input[name="newMonitor[Host]"],
input[name="newMonitor[Name]"],
input[name="newMonitor[Path]"],
input[name="newMonitor[SecondPath]"],

View File

@ -163,12 +163,13 @@ function getBodyTopHTML() {
<noscript>
<div style="background-color:red;color:white;font-size:x-large;">
'. validHtmlStr(ZM_WEB_TITLE) .' requires Javascript. Please enable Javascript in your browser for this site.
</div>
</noscript>
';
global $error_message;
if ( $error_message ) {
echo '<div class="error">'.$error_message.'</div>';
echo '<div id="error">'.$error_message.'</div>';
}
} // end function getBodyTopHTML
@ -202,7 +203,7 @@ function getNormalNavBarHTML($running, $user, $bandwidth_options, $view, $skin)
$status = runtimeStatus($running);
?>
<div class="fixed-top container-fluid p-0">
<div class="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">
@ -903,12 +904,6 @@ function xhtmlFooter() {
<link href="skins/<?php echo $skin ?>/js/video-js.css" rel="stylesheet">
<link href="skins/<?php echo $skin ?>/js/video-js-skin.css" rel="stylesheet">
<script src="skins/<?php echo $skin ?>/js/video.js"></script>
<link href="skins/<?php echo $skin ?>/js/player-view/button.css" rel="stylesheet">
<link href="skins/<?php echo $skin ?>/js/player-view/index.css" rel="stylesheet">
<link href="skins/<?php echo $skin ?>/js/player-view/progress.css" rel="stylesheet">
<script src="skins/<?php echo $skin ?>/js/missile.js"></script>
<script src="skins/<?php echo $skin ?>/js/h265webjs-v20220302.js"></script>
<script src="skins/<?php echo $skin ?>/js/player.js"></script>
<script src="./js/videojs.zoomrotate.js"></script>
<?php
}
@ -945,4 +940,4 @@ function xhtmlFooter() {
</html>
<?php
} // end xhtmlFooter
?>
?>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,71 +0,0 @@
.controller li {
position: relative;
float: left;
border: 15px solid #404040;
color: #404040; height: 0;
width:0;
-webkit-border-radius: 100%;
-moz-border-radius: 100%;
-o-border-radius: 100%;
border-radius: 100%;
margin: 0 5px;
}
.controller li a {
border-style: solid;
text-indent: -9999px;
position: absolute;
top: -8px;
left: -5px;
}
.playBtn a {
border-color: transparent transparent transparent #fff;
border-width: 8px 0 8px 12px;
width: 0;
height: 0;
}
.pauseBtn a {
border-color: transparent white;
border-width: 0 3px;
height: 15px;
width: 6px;
left: -6px;
}
.stopBtn a {
border: 7px solid #fff;
height: 0;
width: 0;
left: -7px;
top: -7px;
}
.forwardBtn a {
border-left-width: 8px;
left: 1px;
}
.forwardBtn a:first-child {
margin-left: -7px;
}
.rewindBtn a {
border-width: 8px 8px 8px 0;
border-color: transparent #fff transparent transparent;
width: 0;
height: 0;
}
.rewindBtn a:first-child {
margin-left: -7px;
}
.ejectBtn a.arrow {
border-width: 0 8px 8px 8px;
border-color: transparent transparent #fff transparent;
top:-26px;
left:-8px;
}
.ejectBtn a.dash {
border-width: 0 0 4px;
border-color: transparent transparent #fff;
height: 0; width:16px;
left: -8px;
top: 4px;
}

View File

@ -1,143 +0,0 @@
#player-container {
position: absolute;
margin:auto;
left: 0;
right: 0;
width: 1280px;
height: 720px;
/*overflow: hidden;*/
}
.controller {
background-color: black;
/*background-image: linear-gradient(
to right, red 50px, yellow, blue, green);*/
/*background-position: 100% 50%;*/
width: 720px;
min-height: 50px;
position: absolute;
/*float: bottom;*/
z-index: 99999;
left: 0;
bottom: 0;
}
/*.controller:hover {
background-color: white;
}*/
.operate-container {
min-height: 20px;
padding: 3px;
/*position: relative;
top: 50%;
transform: translateY(-50%);*/
}
.muteBtn {
color: white;
}
.progressVoice {
float: left;
width: 50%;
margin-top: 0.2rem;
/*border: 10px solid rgba(255,255,255,0);*/
color: #d9d9d9;
height: 10px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
border: none;
}
.progressVoice::-moz-progress-bar {
background-color:#d9d9d9;
}
.progressVoice::-webkit-progress-value {
background-color:#d9d9d9;
}
#coverLayer {
width: 100%;
height: 100%;
padding-top: 300px;
z-index: 10000;
position: absolute;
top: 0px;
left: 0px;
background-color: rgba(0, 0, 0, 0.5);
}
#coverLayerBtn {
width: 20%;
height: 200px;
border-radius: 50px;
}
.ptsLabel {
font-size: 15px;
color: white;
background: rgb(0, 0, 0);
/*border: 1px solid white;*/
float: left;
/*border-radius: 7px;*/
padding: 1px;
margin-top: 4px;
margin-left: 5px;
}
.voice-div {
color: white;
/*background: rgb(0, 0, 0);
border: 2px solid white;
border-radius: 7px;
padding-left: 20px;*/
width: 18%;
float: left;
margin-top: 3px;
margin-left: 10px;
/*position: relative;*/
/*margin-top: 50%;*/
/*transform: translateY(-50%);*/
}
.voice-div > span {
/*font-size: 15px;*/
float: left;
color: white;
margin-right: 5px;
}
.voice-div > progress {
margin-top: 8px;
}
.fullScreenBtn {
/*font-size: 10px;*/
float: right;
margin-top: 3px;
margin-right: 5px;
color: white;
/*background: #ffffff;*/
/*border: 2px solid white;*/
/*text-align: center;*/
/*line-height: 20px;*/
height: 24px;
/*font-weight: bold;*/
/*border-radius: 7px;*/
}
.showLabel {
height: 18px;
font-size: 8px;
color: white;
background: rgb(0, 0, 0);
border-bottom: 1px solid #666666;
/*border-radius: 7px;*/
padding-top: 1px;
padding-left: 5px;
padding-right: 5px;
float: right;
margin-top: 5px;
margin-right: 5px;
}

View File

@ -1,42 +0,0 @@
.progress-common {
height: 10px; /** same as progress-contaniner **/
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
border: none;
margin-bottom: 2px;
}
.progress-contaniner {
z-index: 1000;
width: 100%;
background-color: #666666;
}
.cachePts {
position: absolute;
z-index: 1001;
width: 0px;
/*margin-top: 0.125rem;*/
background-color: #d9d9d9;
}
/*.cachePts::-moz-progress-bar {
background-color: #e9e9e9;
}
.cachePts::-webkit-progress-value {
background-color: #e9e9e9;
}*/
.progressPts {
position: absolute;
z-index: 1002;
width: 0px;
/*margin-top: 0.125rem;*/
background-color: rgba(246, 79, 30, 255);
}
/*.progressPts::-moz-progress-bar {
background-color: yellow;
}
.progressPts::-webkit-progress-value {
background-color: yellow;
}*/

View File

@ -1,342 +0,0 @@
/*********************************************************
* LICENSE: GPL-3.0 https://www.gnu.org/licenses/gpl-3.0.txt
*
* Author: Numberwolf - ChangYanlong
* QQ: 531365872
* QQ Group:925466059
* Wechat: numberwolf11
* Discord: numberwolf#8694
* E-Mail: porschegt23@foxmail.com
* Github: https://github.com/numberwolf/h265web.js
*
* 作者: 小老虎(Numberwolf)(常炎隆)
* QQ: 531365872
* QQ群: 531365872
* 微信: numberwolf11
* Discord: numberwolf#8694
* 邮箱: porschegt23@foxmail.com
* 博客: https://www.jianshu.com/u/9c09c1e00fd1
* Github: https://github.com/numberwolf/h265web.js
*
**********************************************************/
const SHOW_LOADING = "loading...";
const SHOW_DONE = "done.";
function durationFormatSubVal(val) {
let valStr = val.toString();
if (valStr.length < 2) {
return '0' + valStr;
}
return valStr;
}
function durationText(duration) {
if (duration < 0) {
return "Play";
}
let durationSecInt = Math.round(duration);
return durationFormatSubVal(Math.floor(durationSecInt / 3600))
+ ":" + durationFormatSubVal(Math.floor((durationSecInt % 3600) / 60))
+ ":" + durationFormatSubVal(Math.floor(durationSecInt % 60));
}
const getMsTime = () => {
return new Date().getTime();
};
/***************************************************
*
*
*
* 1. H.265/HEVC MP4/FLV/HLS/TS
* Demo for create player(MP4/FLV/HLS/TS)
* 点播/直播播放器创建Demo(MP4/FLV/HLS/TS)
*
*
*
***************************************************/
// clear cache count
function clear() {
window.STATICE_MEM_playerCount = -1;
window.STATICE_MEM_playerIndexPtr = 0;
}
clear();
window.onload = function() {
//var token = "============>>>>>>>>>>>>>>Author:changyanlong|numberwolf,Github:https://github.com/numberwolf,Email:porschegt23@foxmail.com,QQ:531365872,HomePage:http://xvideo.video,Discord:numberwolf#8694,Beijing,WorkIn:Baidu<<<<<<<<<<<<===========";
var token = "base64:QXV0aG9yOmNoYW5neWFubG9uZ3xudW1iZXJ3b2xmLEdpdGh1YjpodHRwczovL2dpdGh1Yi5jb20vbnVtYmVyd29sZixFbWFpbDpwb3JzY2hlZ3QyM0Bmb3htYWlsLmNvbSxRUTo1MzEzNjU4NzIsSG9tZVBhZ2U6aHR0cDovL3h2aWRlby52aWRlbyxEaXNjb3JkOm51bWJlcndvbGYjODY5NCx3ZWNoYXI6bnVtYmVyd29sZjExLEJlaWppbmcsV29ya0luOkJhaWR1";
/******** Test Cases *******/
var url = document.getElementById("glplayer").getAttribute("src");
//var url = "res/hls/veilside.m3u8";
//var url = "res/hls1/test.m3u8";
//var url = "http://182.61.31.911:8080/live/livestream.flv";
//var url = "http://127.0.0.1/live/test/hls.m3u8";
/******** Websocket FLV/TS ********/
// var url = "ws://127.0.0.1/live/test.flv";
// var url = "ws://127.0.0.1/live/test.live.ts";
/******** HTTP FLV/TS/HLS ********/
// var url = "http://127.0.0.1/live/test.flv";
// var url = "http://127.0.0.1/live/test.live.ts";
// var url = "http://127.0.0.1/live/test/hls.m3u8";
var config = {
player: "glplayer",
width: 1280,
height: 720,
token : token,
extInfo : {
coreProbePart : 0.4,
probeSize : 8192,
ignoreAudio : 0
}
}; // config
let playerId = config.player;
let playerObj = window.new265webjs(url, config);
let playerDom = document.querySelector('#' + playerId);
let playerCont = document.querySelector('#player-container');
let controllerCont = document.querySelector('#controller');
let progressCont = document.querySelector('#progress-contaniner');
let progressContW = progressCont.offsetWidth;
let cachePts = progressCont.querySelector('#cachePts');
let progressPts = progressCont.querySelector('#progressPts');
let progressVoice = document.querySelector('#progressVoice');
let playBar = document.querySelector('#playBar');
let playBtn = playBar.getElementsByTagName('a')[0];
let showLabel = document.querySelector('#showLabel');
let ptsLabel = document.querySelector('#ptsLabel');
let coverToast = document.querySelector('#coverLayer');
let coverBtn = document.querySelector('#coverLayerBtn');
let muteBtn = document.querySelector('#muteBtn');
// let debugYUVBtn = document.querySelector('#debugYUVBtn');
// let debugYUVATag = document.querySelector('#debugYUVUrl');
let fullScreenBtn = document.querySelector('#fullScreenBtn');
let mediaInfo = null;
playBtn.disabled = true;
// playBar.textContent = '>';
showLabel.textContent = SHOW_LOADING;
playerCont.style.width = config.width + 'px';
playerCont.style.height = config.height + 'px';
controllerCont.style.width = config.width + 'px';
let muteState = false;
// controllerCont.style.left = playerContainer.clientLeft;
// controllerCont.style.bottom = playerContainer.clientBottom;
// alert(playerContainer.clientLeft);
let playAction = () => {
console.log("is playing:", playerObj.isPlaying());
if (playerObj.isPlaying()) {
console.log("bar pause============>");
// playBar.textContent = '>';
playBar.setAttribute('class', 'playBtn');
playerObj.pause();
} else {
// playBar.textContent = '||';
playBar.setAttribute('class', 'pauseBtn');
playerObj.play();
}
};
playerCont.onmouseover = function() {
controllerCont.hidden = false;
};
playerCont.onmouseout = function() {
controllerCont.hidden = true;
};
playerDom.onmouseup = function() {
playAction();
};
playBtn.onclick = () => {
playAction();
};
muteBtn.onclick = () => {
console.log(playerObj.getVolume());
if (muteState === true) {
playerObj.setVoice(1.0);
progressVoice.value = 100;
} else {
playerObj.setVoice(0.0);
progressVoice.value = 0;
}
muteState = !muteState;
};
fullScreenBtn.onclick = () => {
playerObj.fullScreen();
// setTimeout(() => {
// playerObj.closeFullScreen();
// }, 2000);
};
progressCont.addEventListener('click', (e) => {
showLabel.textContent = SHOW_LOADING;
let x = e.pageX - progressCont.getBoundingClientRect().left; // or e.offsetX (less support, though)
let y = e.pageY - progressCont.getBoundingClientRect().top; // or e.offsetY
let clickedValue = x * progressCont.max / progressCont.offsetWidth;
// alert(clickedValue);
playerObj.seek(clickedValue);
});
progressVoice.addEventListener('click', (e) => {
let x = e.pageX - progressVoice.getBoundingClientRect().left; // or e.offsetX (less support, though)
let y = e.pageY - progressVoice.getBoundingClientRect().top; // or e.offsetY
let clickedValue = x * progressVoice.max / progressVoice.offsetWidth;
progressVoice.value = clickedValue;
let volume = clickedValue / 100;
// alert(volume);
// console.log(
// progressVoice.offsetLeft, // 209
// x, y, // 324 584
// progressVoice.max, progressVoice.offsetWidth);
playerObj.setVoice(volume);
});
playerObj.onSeekStart = (pts) => {
showLabel.textContent = SHOW_LOADING + " seek to:" + parseInt(pts);
};
playerObj.onSeekFinish = () => {
showLabel.textContent = SHOW_DONE;
};
playerObj.onPlayFinish = () => {
console.log("============= FINISHED ===============");
// playBar.textContent = '>';
playBar.setAttribute('class', 'playBtn');
// playerObj.release();
// console.log("=========> release ok");
};
playerObj.onRender = (width, height, imageBufferY, imageBufferB, imageBufferR) => {
console.log("on render");
};
playerObj.onOpenFullScreen = () => {
console.log("onOpenFullScreen");
};
playerObj.onCloseFullScreen = () => {
console.log("onCloseFullScreen");
};
playerObj.onSeekFinish = () => {
showLabel.textContent = SHOW_DONE;
};
playerObj.onLoadCache = () => {
showLabel.textContent = "Caching...";
};
playerObj.onLoadCacheFinshed = () => {
showLabel.textContent = SHOW_DONE;
};
playerObj.onReadyShowDone = () => {
console.log("onReadyShowDone");
showLabel.textContent = "Cover Img OK";
};
playerObj.onLoadFinish = () => {
playerObj.setVoice(1.0);
mediaInfo = playerObj.mediaInfo();
console.log("mediaInfo===========>", mediaInfo);
/*
meta:
durationMs: 144400
fps: 25
sampleRate: 44100
size: {
width: 864,
height: 480
},
audioNone : false
videoType: "vod"
*/
if (mediaInfo.meta.isHEVC === false) {
console.log("is not HEVC/H.265 media!");
//coverToast.removeAttribute('hidden');
//coverBtn.style.width = '100%';
//coverBtn.style.fontSize = '50px';
//coverBtn.innerHTML = 'is not HEVC/H.265 media!';
//return;
}
//console.log("is HEVC/H.265 media.");
playBtn.disabled = false;
if (mediaInfo.meta.audioNone) {
progressVoice.value = 0;
progressVoice.style.display = 'none';
} else {
playerObj.setVoice(0.5);
}
if (mediaInfo.videoType == "vod") {
cachePts.max = mediaInfo.meta.durationMs / 1000;
progressCont.max = mediaInfo.meta.durationMs / 1000;
ptsLabel.textContent = durationText(0) + '/' + durationText(progressCont.max);
} else {
cachePts.hidden = true;
progressCont.hidden = true;
ptsLabel.textContent = 'LIVE';
if (mediaInfo.meta.audioNone === true) {
// playBar.textContent = '||';
playerObj.play();
} else {
coverToast.removeAttribute('hidden');
coverBtn.onclick = () => {
// playBar.textContent = '||';
playAction();
coverToast.setAttribute('hidden', 'hidden');
};
}
}
showLabel.textContent = SHOW_DONE;
};
playerObj.onCacheProcess = (cPts) => {
// console.log("onCacheProcess => ", cPts);
try {
// cachePts.value = cPts;
let precent = cPts / progressCont.max;
let cacheWidth = precent * progressContW;
// console.log(precent, precent * progressCont.offsetWidth);
cachePts.style.width = cacheWidth + 'px';
} catch(err) {
console.log(err);
}
};
playerObj.onPlayTime = (videoPTS) => {
if (mediaInfo.videoType == "vod") {
// progressPts.value = videoPTS;
let precent = videoPTS / progressCont.max;
let progWidth = precent * progressContW;
// console.log(precent, precent * progressCont.offsetWidth);
progressPts.style.width = progWidth + 'px';
ptsLabel.textContent = durationText(videoPTS) + '/' + durationText(progressCont.max);
} else {
// ptsLabel.textContent = durationText(videoPTS) + '/LIVE';
ptsLabel.textContent = '/LIVE';
}
};
playerObj.do();
return playerObj;
};

View File

@ -193,47 +193,22 @@ if ( $Event->Id() and !file_exists($Event->Path()) )
<?php
if ( $video_tag ) {
?>
<div id="videoFeed" style="width: 1280px;height: 720px">
<div id="player-container">
<div id="glplayer" class="glplayer" src="<?php echo $Event->getStreamSrc(array('mode'=>'mpeg','format'=>'h264'),'&amp;'); ?>"></div>
<div id="controller" class="controller">
<div id="progress-contaniner" class="progress-common progress-contaniner">
<div id="cachePts" class="progress-common cachePts"></div>
<div id="progressPts" class="progress-common progressPts"></div>
</div>
<div id="operate-container" class="operate-container">
<li id="playBar" class="playBtn">
<a href="javascript:void(0)" title="start">Start</a>
</li>
<span id="ptsLabel" class="ptsLabel">00:00:00/00:00:00</span>
<div class="voice-div">
<span>
<a id="muteBtn"
class="muteBtn" href="javascript:void(0)">
<svg class="icon" style="width: 1em;height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="488">
<path d="M153.6 665.6V358.4h204.8V256H153.6c-56.32 0-102.4 46.08-102.4 102.4v307.2c0 56.32 46.08 102.4 102.4 102.4h204.8v-102.4H153.6zM358.4 256v102.4l204.8-128v563.2L358.4 665.6v102.4l307.2 204.8V51.2zM768 261.12v107.52c61.44 20.48 102.4 76.8 102.4 143.36s-40.96 122.88-102.4 143.36v107.52c117.76-25.6 204.8-128 204.8-250.88s-87.04-225.28-204.8-250.88z" p-id="489">
</path>
</svg>
</a>
</span>
<progress id="progressVoice" class="progressVoice" value="50" max="100"></progress>
</div>
<a id="fullScreenBtn"
class="fullScreenBtn" href="javascript:void(0)">
<svg class="icon" style="width: 1em;height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="403">
<path d="M167.8 903.1c-11.5 0-22.9-4.4-31.7-13.1-17.5-17.5-17.5-45.8 0-63.3l221.1-221.1c17.5-17.5 45.9-17.5 63.3 0 17.5 17.5 17.5 45.8 0 63.3L199.4 890c-8.7 8.7-20.2 13.1-31.6 13.1zM638.5 432.4c-11.5 0-22.9-4.4-31.7-13.1-17.5-17.5-17.5-45.8 0-63.3l221.7-221.7c17.5-17.5 45.8-17.5 63.3 0s17.5 45.8 0 63.3L670.1 419.3c-8.7 8.7-20.2 13.1-31.6 13.1zM859.7 903.8c-11.5 0-23-4.4-31.7-13.1L606.7 668.8c-17.5-17.5-17.4-45.9 0.1-63.4s45.9-17.4 63.3 0.1l221.4 221.9c17.5 17.5 17.4 45.9-0.1 63.4-8.8 8.7-20.2 13-31.7 13zM389 432.1c-11.5 0-23-4.4-31.7-13.1L136.1 197.2c-17.5-17.5-17.4-45.9 0.1-63.4s45.9-17.4 63.3 0.1l221.2 221.7c17.5 17.5 17.4 45.9-0.1 63.4-8.7 8.7-20.2 13.1-31.6 13.1z" fill="#ffffff" p-id="404">
</path>
<path d="M145 370c-24.7 0-44.8-20.1-44.8-44.8V221.8C100.2 153.5 155.7 98 224 98h103.4c24.7 0 44.8 20.1 44.8 44.8s-20.1 44.8-44.8 44.8H224c-18.9 0-34.2 15.3-34.2 34.2v103.4c0 24.7-20.1 44.8-44.8 44.8zM883.3 370c-24.7 0-44.8-20.1-44.8-44.8V221.8c0-18.9-15.3-34.2-34.2-34.2H700.8c-24.7 0-44.8-20.1-44.8-44.8S676.1 98 700.8 98h103.5c68.2 0 123.8 55.5 123.8 123.8v103.5c0 24.7-20.1 44.7-44.8 44.7zM327.5 926.6H224c-68.2 0-123.8-55.5-123.8-123.8V699.4c0-24.7 20.1-44.8 44.8-44.8s44.8 20.1 44.8 44.8v103.5c0 18.9 15.3 34.2 34.2 34.2h103.5c24.7 0 44.8 20.1 44.8 44.8s-20.1 44.7-44.8 44.7zM804.3 926.6H700.8c-24.7 0-44.8-20.1-44.8-44.8s20.1-44.8 44.8-44.8h103.5c18.9 0 34.2-15.4 34.2-34.2V699.4c0-24.7 20.1-44.8 44.8-44.8 24.7 0 44.8 20.1 44.8 44.8v103.5c0 68.2-55.6 123.7-123.8 123.7z" fill="#ffffff" p-id="405">
</path>
</svg>
</a>
<span id="showLabel" class="showLabel"></span>
</div>
</div>
</div> <!-- end player container -->
<div id="videoFeed">
<video autoplay id="videoobj" class="video-js vjs-default-skin"
style="transform: matrix(1, 0, 0, 1, 0, 0);"
<?php echo $scale ? 'width="'.reScale($Event->Width(), $scale).'"' : '' ?>
<?php echo $scale ? 'height="'.reScale($Event->Height(), $scale).'"' : '' ?>
data-setup='{ "controls": true, "autoplay": true, "preload": "auto", "playbackRates": [ <?php echo implode(',',
array_map(function($r){return $r/100;},
array_filter(
array_keys($rates),
function($r){return $r >= 0 ? true : false;}
))) ?>], "plugins": { "zoomrotate": { "zoom": "<?php echo $Zoom ?>"}}}'
>
<source src="<?php echo $Event->getStreamSrc(array('mode'=>'mpeg','format'=>'h264'),'&amp;'); ?>" type="video/mp4">
<track id="monitorCaption" kind="captions" label="English" srclang="en" src='data:plain/text;charset=utf-8,"WEBVTT\n\n 00:00:00.000 --> 00:00:01.000 ZoneMinder"' default/>
Your browser does not support the video tag.
</video>
</div><!--videoFeed-->
<?php
} else {

View File

@ -52,14 +52,19 @@ function vjsReplay() {
var overLaid = $j("#videoobj");
overLaid.append('<p class="vjsMessage" style="height: '+overLaid.height()+'px; line-height: '+overLaid.height()+'px;">No more events</p>');
} else {
var endTime = (Date.parse(eventData.EndDateTime)).getTime();
if (!eventData.EndDateTime) {
// No EndTime but have a next event, just go to it.
streamNext(true);
return;
}
var endTime = Date.parse(eventData.EndDateTime).getTime();
var nextStartTime = nextEventStartTime.getTime(); //nextEventStartTime.getTime() is a mootools workaround, highjacks Date.parse
if ( nextStartTime <= endTime ) {
streamNext(true);
return;
}
var overLaid = $j("#videoobj");
vid.pause();
var overLaid = $j("#videoobj");
overLaid.append('<p class="vjsMessage" style="height: '+overLaid.height()+'px; line-height: '+overLaid.height()+'px;"></p>');
var gapDuration = (new Date().getTime()) + (nextStartTime - endTime);
var messageP = $j('.vjsMessage');

View File

@ -51,6 +51,7 @@ var eventData = {
StartDateTime: '<?php echo $Event->StartDateTime() ?>',
StartDateTimeShort: '<?php echo strftime(STRF_FMT_DATETIME_SHORT, strtotime($Event->StartDateTime())) ?>',
EndDateTime: '<?php echo $Event->EndDateTime() ?>',
EndDateTimeShort: '<?php echo $Event->EndDateTime()? strftime(STRF_FMT_DATETIME_SHORT, strtotime($Event->EndDateTime())) : '' ?>',
Frames: '<?php echo $Event->Frames() ?>',
AlarmFrames: '<?php echo $Event->AlarmFrames() ?>',
TotScore: '<?php echo $Event->TotScore() ?>',
@ -73,6 +74,7 @@ var eventDataStrings = {
MonitorName: '<?php echo translate('AttrMonitorName') ?>',
Cause: '<?php echo translate('Cause') ?>',
StartDateTimeShort: '<?php echo translate('AttrStartTime') ?>',
EndDateTimeShort: '<?php echo translate('AttrEndTime') ?>',
Length: '<?php echo translate('Duration') ?>',
Frames: '<?php echo translate('AttrFrames') ?>',
AlarmFrames: '<?php echo translate('AttrAlarmFrames') ?>',

View File

@ -850,7 +850,7 @@ function initPage() {
// Load the PTZ Preset modal into the DOM
if (monitorControllable) getCtrlPresetModal();
// Load the settings modal into the DOM
if (monitorType == "Local") getSettingsModal();
if (monitorType == 'Local') getSettingsModal();
}
if (monitorType != 'WebSite') {
@ -917,7 +917,15 @@ function initPage() {
});
// Only enable the settings button for local cameras
settingsBtn.prop('disabled', !(canView.Control && (monitorType == 'Local')));
if (!canView.Control) {
settingsBtn.prop('disabled', true);
settingsBtn.prop('title', 'Disbled due to lack of Control View permission.');
} else if (monitorType != 'Local') {
settingsBtn.prop('disabled', true);
settingsBtn.prop('title', 'Settings only available for Local monitors.');
} else {
settingsBtn.prop('disabled', false);
}
// Init the bootstrap-table
if (monitorType != 'WebSite') table.bootstrapTable({icons: icons});

View File

@ -770,9 +770,18 @@ include('_monitor_source_nvsocket.php');
?>
</td>
</tr>
<tr><td class="text-right pr-3"><?php echo translate('RemoteHostName') ?></td><td><input type="text" name="newMonitor[Host]" value="<?php echo validHtmlStr($monitor->Host()) ?>"/></td></tr>
<tr><td><?php echo translate('RemoteHostPort') ?></td><td><input type="number" name="newMonitor[Port]" value="<?php echo validHtmlStr($monitor->Port()) ?>" min="0" max="65535"/></td></tr>
<tr><td><?php echo translate('RemoteHostPath') ?></td><td><input type="text" name="newMonitor[Path]" value="<?php echo validHtmlStr($monitor->Path()) ?>"/></td></tr>
<tr>
<td class="text-right pr-3"><?php echo translate('RemoteHostName') ?></td>
<td><input type="text" name="newMonitor[Host]" value="<?php echo validHtmlStr($monitor->Host()) ?>"/></td>
</tr>
<tr>
<td class="text-right pr-3"><?php echo translate('RemoteHostPort') ?></td>
<td><input type="number" name="newMonitor[Port]" value="<?php echo validHtmlStr($monitor->Port()) ?>" min="0" max="65535" step="1"/></td>
</tr>
<tr>
<td class="text-right pr-3"><?php echo translate('RemoteHostPath') ?></td>
<td><input type="text" name="newMonitor[Path]" value="<?php echo validHtmlStr($monitor->Path()) ?>"/></td>
</tr>
<?php
} else if ( $monitor->Type() == 'File' ) {
?>

View File

@ -54,9 +54,9 @@ else
$focusWindow = true;
xhtmlHeaders(__FILE__, translate('Options'));
getBodyTopHTML();
echo getNavBarHTML();
?>
<body>
<?php echo getNavBarHTML(); ?>
<div class="container-fluid">
<div class="row flex-nowrap">
<nav id="sidebar">

View File

@ -65,7 +65,7 @@ if ( empty($_REQUEST['path']) ) {
if ( empty($_REQUEST['fid']) ) {
header('HTTP/1.0 404 Not Found');
ZM\Fatal('No Frame ID specified');
ZM\Error('No Frame ID specified');
return;
}
@ -73,47 +73,50 @@ if ( empty($_REQUEST['path']) ) {
$Event = ZM\Event::find_one(array('Id'=>$_REQUEST['eid']));
if ( !$Event ) {
header('HTTP/1.0 404 Not Found');
ZM\Fatal('Event '.$_REQUEST['eid'].' Not found');
ZM\Error('Event '.$_REQUEST['eid'].' Not found');
return;
}
if ( $_REQUEST['fid'] == 'objdetect' ) {
// if animation file is found, return that, else return image
// we are only looking for GIF or jpg here, not mp4
// as most often, browsers asking for this link will be expecting
// media types that can be rendered as <img src=>
$path_anim_gif = $Event->Path().'/objdetect.gif';
$path_image = $Event->Path().'/objdetect.jpg';
if (file_exists($path_anim_gif)) {
// we found the animation gif file
$media_type = 'image/gif';
ZM\Debug("Animation file found at $path");
$path = $path_anim_gif;
} else if (file_exists($path_image)) {
// animation not found, but image found
ZM\Debug("Image file found at $path");
$path = $path_image;
} else {
// neither animation nor image found
header('HTTP/1.0 404 Not Found');
ZM\Fatal("Object detection animation and image not found for this event");
}
$Frame = new ZM\Frame();
$Frame->Id('objdetect');
} else if ( $_REQUEST['fid'] == 'objdetect_mp4' ) {
$path = $Event->Path().'/objdetect.mp4';
if ( !file_exists($path) ) {
header('HTTP/1.0 404 Not Found');
ZM\Fatal("File $path does not exist. You might not have enabled create_animation in objectconfig.ini. If you have, inspect debug logs for errors during creation");
}
$Frame = new ZM\Frame();
$Frame->Id('objdetect');
$media_type = 'video/mp4';
} else if ( $_REQUEST['fid'] == 'objdetect_gif' ) {
$path = $Event->Path().'/objdetect.gif';
if ( !file_exists($path) ) {
header('HTTP/1.0 404 Not Found');
ZM\Fatal("File $path does not exist. You might not have enabled create_animation in objectconfig.ini. If you have, inspect debug logs for errors during creation");
// if animation file is found, return that, else return image
// we are only looking for GIF or jpg here, not mp4
// as most often, browsers asking for this link will be expecting
// media types that can be rendered as <img src=>
$path_anim_gif = $Event->Path().'/objdetect.gif';
$path_image = $Event->Path().'/objdetect.jpg';
if (file_exists($path_anim_gif)) {
// we found the animation gif file
$media_type = 'image/gif';
ZM\Debug("Animation file found at $path");
$path = $path_anim_gif;
} else if (file_exists($path_image)) {
// animation not found, but image found
ZM\Debug("Image file found at $path");
$path = $path_image;
} else {
// neither animation nor image found
header('HTTP/1.0 404 Not Found');
ZM\Error('Object detection animation and image not found for this event');
return;
}
$Frame = new ZM\Frame();
$Frame->Id('objdetect');
} else if ( $_REQUEST['fid'] == 'objdetect_mp4' ) {
$path = $Event->Path().'/objdetect.mp4';
if ( !file_exists($path) ) {
header('HTTP/1.0 404 Not Found');
ZM\Error("File $path does not exist. You might not have enabled create_animation in objectconfig.ini. If you have, inspect debug logs for errors during creation");
return;
}
$Frame = new ZM\Frame();
$Frame->Id('objdetect');
$media_type = 'video/mp4';
} else if ( $_REQUEST['fid'] == 'objdetect_gif' ) {
$path = $Event->Path().'/objdetect.gif';
if ( !file_exists($path) ) {
header('HTTP/1.0 404 Not Found');
ZM\Error("File $path does not exist. You might not have enabled create_animation in objectconfig.ini. If you have, inspect debug logs for errors during creation");
return;
}
$Frame = new ZM\Frame();
$Frame->Id('objdetect');
@ -122,7 +125,8 @@ if ( empty($_REQUEST['path']) ) {
$path = $Event->Path().'/objdetect.jpg';
if ( !file_exists($path) ) {
header('HTTP/1.0 404 Not Found');
ZM\Fatal("File $path does not exist. Please make sure store_frame_in_zm is enabled in the object detection config");
ZM\Error("File $path does not exist. Please make sure store_frame_in_zm is enabled in the object detection config");
return;
}
$Frame = new ZM\Frame();
$Frame->Id('objdetect');
@ -149,7 +153,7 @@ if ( empty($_REQUEST['path']) ) {
$path = $Event->Path().'/'.sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d', $Frame->FrameId()).'-'.$show.'.jpg';
} else {
header('HTTP/1.0 404 Not Found');
ZM\Fatal('No alarm jpg found for event '.$_REQUEST['eid']);
ZM\Error('No alarm jpg found for event '.$_REQUEST['eid']);
return;
}
} else {
@ -189,11 +193,12 @@ if ( empty($_REQUEST['path']) ) {
ZM\Debug("Command: $command, retval: $retval, output: " . implode("\n", $output));
if ( ! file_exists($path) ) {
header('HTTP/1.0 404 Not Found');
ZM\Fatal('Can\'t create frame images from video for this event '.$Event->DefaultVideo().'
ZM\Error('Can\'t create frame images from video for this event '.$Event->DefaultVideo().'
Command was: '.$command.'
Output was: '.implode(PHP_EOL,$output) );
return;
}
# Generating an image file will use up more disk space, so update the Event record.
if ( $Event->EndDateTime() ) {
@ -202,7 +207,7 @@ if ( empty($_REQUEST['path']) ) {
}
} else {
header('HTTP/1.0 404 Not Found');
ZM\Fatal('No snapshot jpg found for event '.$_REQUEST['eid']);
ZM\Error('No snapshot jpg found for event '.$_REQUEST['eid']);
return;
}
} # end if stored jpgs
@ -231,7 +236,8 @@ if ( empty($_REQUEST['path']) ) {
$Frame->Delta($previousBulkFrame['Delta'] + floor( 100* ( $nextBulkFrame['Delta'] - $previousBulkFrame['Delta'] ) * $percentage )/100);
ZM\Debug('Got virtual frame from Bulk Frames previous delta: ' . $previousBulkFrame['Delta'] . ' + nextdelta:' . $nextBulkFrame['Delta'] . ' - ' . $previousBulkFrame['Delta'] . ' * ' . $percentage );
} else {
ZM\Fatal('No Frame found for event('.$_REQUEST['eid'].') and frame id('.$_REQUEST['fid'].')');
ZM\Error('No Frame found for event('.$_REQUEST['eid'].') and frame id('.$_REQUEST['fid'].')');
return;
}
} # end if !Frame
// Frame can be non-existent. We have Bulk frames. So now we should try to load the bulk frame
@ -244,14 +250,14 @@ if ( empty($_REQUEST['path']) ) {
$Frame = ZM\Frame::find_one(array('Id'=>$_REQUEST['fid']));
if ( !$Frame ) {
header('HTTP/1.0 404 Not Found');
ZM\Fatal('Frame ' . $_REQUEST['fid'] . ' Not Found');
ZM\Error('Frame ' . $_REQUEST['fid'] . ' Not Found');
return;
}
$Event = ZM\Event::find_one(array('Id'=>$Frame->EventId()));
if ( !$Event ) {
header('HTTP/1.0 404 Not Found');
ZM\Fatal('Event ' . $Frame->EventId() . ' Not Found');
ZM\Error('Event ' . $Frame->EventId() . ' Not Found');
return;
}
$path = $Event->Path().'/'.sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d',$Frame->FrameId()).'-'.$show.'.jpg';
@ -263,7 +269,8 @@ if ( empty($_REQUEST['path']) ) {
if ( ($show == 'capture') and $Event->DefaultVideo() ) {
if ( !file_exists($Event->Path().'/'.$Event->DefaultVideo()) ) {
header('HTTP/1.0 404 Not Found');
ZM\Fatal("Can't create frame images from video because there is no video file for this event at (".$Event->Path().'/'.$Event->DefaultVideo() );
ZM\Error("Can't create frame images from video because there is no video file for this event at (".$Event->Path().'/'.$Event->DefaultVideo() );
return;
}
$command = ZM_PATH_FFMPEG.' -ss '. $Frame->Delta() .' -i '.$Event->Path().'/'.$Event->DefaultVideo().' -frames:v 1 '.$path . ' 2>&1';
#$command ='ffmpeg -ss '. $Frame->Delta() .' -i '.$Event->Path().'/'.$Event->DefaultVideo().' -vf "select=gte(n\\,'.$Frame->FrameId().'),setpts=PTS-STARTPTS" '.$path;
@ -275,11 +282,12 @@ if ( empty($_REQUEST['path']) ) {
ZM\Debug("Command: $command, retval: $retval, output: " . implode("\n", $output));
if ( ! file_exists($path) ) {
header('HTTP/1.0 404 Not Found');
ZM\Fatal('Can\'t create frame images from video for this event '.$Event->DefaultVideo().'
ZM\Error('Can\'t create frame images from video for this event '.$Event->DefaultVideo().'
Command was: '.$command.'
Output was: '.implode(PHP_EOL,$output) );
return;
}
# Generating an image file will use up more disk space, so update the Event record.
if ( $Event->EndDateTime() ) {
@ -288,8 +296,9 @@ Output was: '.implode(PHP_EOL,$output) );
}
} else {
header('HTTP/1.0 404 Not Found');
ZM\Fatal("Can't create frame $show images from video because there is no video file for this event at ".
ZM\Error("Can't create frame $show images from video because there is no video file for this event at ".
$Event->Path().'/'.$Event->DefaultVideo() );
return;
}
} # end if ! file_exists($path)
@ -317,7 +326,8 @@ Output was: '.implode(PHP_EOL,$output) );
}
if ( !file_exists($path) ) {
header('HTTP/1.0 404 Not Found');
ZM\Fatal("Image not found at $path");
ZM\Error("Image not found at $path");
return;
}
}