Merge branch 'master' into zma_to_thread

This commit is contained in:
Isaac Connor 2020-12-29 12:18:26 -05:00
commit 284b9f963f
24 changed files with 498 additions and 382 deletions

View File

@ -59,7 +59,7 @@ if(NOT HOST_OS)
endif(NOT HOST_OS) endif(NOT HOST_OS)
set (CMAKE_CXX_STANDARD 11) set (CMAKE_CXX_STANDARD 11)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
# Default CLFAGS and CXXFLAGS: # Default CLFAGS and CXXFLAGS:
set(CMAKE_C_FLAGS_RELEASE "-Wall -D__STDC_CONSTANT_MACROS -O2") set(CMAKE_C_FLAGS_RELEASE "-Wall -D__STDC_CONSTANT_MACROS -O2")
set(CMAKE_CXX_FLAGS_RELEASE "-Wall -D__STDC_CONSTANT_MACROS -O2") set(CMAKE_CXX_FLAGS_RELEASE "-Wall -D__STDC_CONSTANT_MACROS -O2")

View File

@ -482,7 +482,7 @@ CREATE TABLE `Monitors` (
`SaveJPEGs` TINYINT NOT NULL DEFAULT '3' , `SaveJPEGs` TINYINT NOT NULL DEFAULT '3' ,
`VideoWriter` TINYINT NOT NULL DEFAULT '0', `VideoWriter` TINYINT NOT NULL DEFAULT '0',
`OutputCodec` int(10) unsigned NOT NULL default 0, `OutputCodec` int(10) unsigned NOT NULL default 0,
`Encoder` enum('auto','h264','h264_omx','mjpeg','mpeg1','mpeg2'), `Encoder` enum('auto','h264','libx264','h264_omx','h264_vaapi','mjpeg','mpeg1','mpeg2'),
`OutputContainer` enum('auto','mp4','mkv'), `OutputContainer` enum('auto','mp4','mkv'),
`EncoderParameters` TEXT, `EncoderParameters` TEXT,
`RecordAudio` TINYINT NOT NULL DEFAULT '0', `RecordAudio` TINYINT NOT NULL DEFAULT '0',

View File

@ -239,7 +239,7 @@ use Sys::MemInfo qw(totalmem freemem totalswap freeswap);
use ZoneMinder::Server qw(CpuLoad); use ZoneMinder::Server qw(CpuLoad);
#use Data::Dumper; #use Data::Dumper;
use constant KILL_DELAY => 60; # seconds to wait between sending TERM and sending KILL use constant KILL_DELAY => 10; # seconds to wait between sending TERM and sending KILL
our %cmd_hash; our %cmd_hash;
our %pid_hash; our %pid_hash;

View File

@ -156,7 +156,7 @@ while( 1 ) {
Error("Error reading shared data for $$monitor{Id} $$monitor{Name}"); Error("Error reading shared data for $$monitor{Id} $$monitor{Name}");
} elsif ( !$image_time ) { } elsif ( !$image_time ) {
# We can't get the last capture time so can't be sure it's died. # We can't get the last capture time so can't be sure it's died.
$restart = 1; #$restart = 1;
Error("Last analyse time for $$monitor{Id} $$monitor{Name} was zero."); Error("Last analyse time for $$monitor{Id} $$monitor{Name} was zero.");
} else { } else {

View File

@ -188,7 +188,7 @@ public:
inline unsigned int SubpixelOrder() const { return subpixelorder; } inline unsigned int SubpixelOrder() const { return subpixelorder; }
inline unsigned int Size() const { return size; } inline unsigned int Size() const { return size; }
inline unsigned int AVPixFormat() { inline AVPixelFormat AVPixFormat() {
if ( colours == ZM_COLOUR_RGB32 ) { if ( colours == ZM_COLOUR_RGB32 ) {
return AV_PIX_FMT_RGBA; return AV_PIX_FMT_RGBA;
} else if ( colours == ZM_COLOUR_RGB24 ) { } else if ( colours == ZM_COLOUR_RGB24 ) {

View File

@ -999,6 +999,7 @@ bool Monitor::connect() {
shared_data->format = camera->SubpixelOrder(); shared_data->format = camera->SubpixelOrder();
shared_data->imagesize = camera->ImageSize(); shared_data->imagesize = camera->ImageSize();
shared_data->alarm_cause[0] = 0; shared_data->alarm_cause[0] = 0;
shared_data->last_frame_score = 0;
trigger_data->size = sizeof(TriggerData); trigger_data->size = sizeof(TriggerData);
trigger_data->trigger_state = TRIGGER_CANCEL; trigger_data->trigger_state = TRIGGER_CANCEL;
trigger_data->trigger_score = 0; trigger_data->trigger_score = 0;
@ -1955,7 +1956,7 @@ bool Monitor::Analyse() {
} }
} }
noteSet.insert(linked_monitors[i]->Name()); noteSet.insert(linked_monitors[i]->Name());
score += 50; score += linked_monitors[i]->lastFrameScore(); // 50;
} else { } else {
Debug(4, "Linked monitor %d %s is not alarmed", Debug(4, "Linked monitor %d %s is not alarmed",
linked_monitors[i]->Id(), linked_monitors[i]->Name()); linked_monitors[i]->Id(), linked_monitors[i]->Name());
@ -2195,6 +2196,7 @@ bool Monitor::Analyse() {
snap->unlock(); snap->unlock();
return false; return false;
} }
shared_data->last_frame_score = score;
} else { } else {
Debug(3, "trigger == off"); Debug(3, "trigger == off");
if ( event ) { if ( event ) {
@ -2512,7 +2514,7 @@ int Monitor::Capture() {
Debug(1, "Not decoding"); Debug(1, "Not decoding");
} else { } else {
Debug(2,"About to decode %p", packet); Debug(2,"About to decode %p", packet);
if ( ! packet->decode(camera->get_VideoCodecContext()) ) { if ( packet->decode(camera->get_VideoCodecContext()) < 0 ) {
Error("decode failed"); Error("decode failed");
} // end if decode } // end if decode
} // end if decoding } // end if decoding

View File

@ -135,7 +135,8 @@ protected:
uint8_t signal; /* +54 */ uint8_t signal; /* +54 */
uint8_t format; /* +55 */ uint8_t format; /* +55 */
uint32_t imagesize; /* +56 */ uint32_t imagesize; /* +56 */
uint32_t epadding1; /* +60 */ uint32_t last_frame_score; /* +60 */
// uint32_t epadding1; /* +60 */
/* /*
** This keeps 32bit time_t and 64bit time_t identical and compatible as long as time is before 2038. ** This keeps 32bit time_t and 64bit time_t identical and compatible as long as time is before 2038.
** Shared memory layout should be identical for both 32bit and 64bit and is multiples of 16. ** Shared memory layout should be identical for both 32bit and 64bit and is multiples of 16.
@ -228,6 +229,10 @@ protected:
inline bool isConnected() const { return connected && shared_data->valid; } inline bool isConnected() const { return connected && shared_data->valid; }
inline time_t getLastConnectTime() const { return last_connect_time; } inline time_t getLastConnectTime() const { return last_connect_time; }
inline uint32_t lastFrameScore() {
return shared_data->last_frame_score;
}
bool connect(); bool connect();
bool disconnect(); bool disconnect();

View File

@ -216,11 +216,12 @@ AVFrame *ZMPacket::get_out_frame( const AVCodecContext *ctx ) {
Error("Unable to allocate a frame"); Error("Unable to allocate a frame");
return nullptr; return nullptr;
} }
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
codec_imgsize = av_image_get_buffer_size( codec_imgsize = av_image_get_buffer_size(
ctx->pix_fmt, ctx->pix_fmt,
ctx->width, ctx->width,
ctx->height, 1); ctx->height, 32);
buffer = (uint8_t *)av_malloc(codec_imgsize); buffer = (uint8_t *)av_malloc(codec_imgsize);
av_image_fill_arrays( av_image_fill_arrays(
out_frame->data, out_frame->data,
@ -229,7 +230,7 @@ AVFrame *ZMPacket::get_out_frame( const AVCodecContext *ctx ) {
ctx->pix_fmt, ctx->pix_fmt,
ctx->width, ctx->width,
ctx->height, ctx->height,
1); 32);
#else #else
codec_imgsize = avpicture_get_size( codec_imgsize = avpicture_get_size(
ctx->pix_fmt, ctx->pix_fmt,

View File

@ -28,11 +28,10 @@ zm_packetqueue::zm_packetqueue(
int p_video_stream_id, int p_video_stream_id,
int p_audio_stream_id int p_audio_stream_id
): ):
video_stream_id(p_video_stream_id), video_stream_id(p_video_stream_id),
max_video_packet_count(video_image_count),
deleting(false) deleting(false)
{ {
video_stream_id = p_video_stream_id;
max_video_packet_count = video_image_count-1;
analysis_it = pktQueue.begin(); analysis_it = pktQueue.begin();
max_stream_id = p_video_stream_id > p_audio_stream_id ? p_video_stream_id : p_audio_stream_id; max_stream_id = p_video_stream_id > p_audio_stream_id ? p_video_stream_id : p_audio_stream_id;
@ -43,7 +42,6 @@ video_stream_id(p_video_stream_id),
zm_packetqueue::~zm_packetqueue() { zm_packetqueue::~zm_packetqueue() {
deleting = true; deleting = true;
Debug(4, "In destructor");
/* zma might be waiting. Must have exclusive access */ /* zma might be waiting. Must have exclusive access */
while ( ! mutex.try_lock() ) { while ( ! mutex.try_lock() ) {
Debug(4, "Waiting for exclusive access"); Debug(4, "Waiting for exclusive access");
@ -51,12 +49,9 @@ zm_packetqueue::~zm_packetqueue() {
} }
while ( !pktQueue.empty() ) { while ( !pktQueue.empty() ) {
Debug(4, "Fronting packet %d", pktQueue.empty());
ZMPacket * packet = pktQueue.front(); ZMPacket * packet = pktQueue.front();
Debug(4, "poppng packet %d", packet->image_index);
pktQueue.pop_front(); pktQueue.pop_front();
if ( packet->image_index == -1 ) { if ( packet->image_index == -1 ) {
Debug(4, "Deletng packet");
delete packet; delete packet;
} }
} }
@ -79,6 +74,8 @@ bool zm_packetqueue::queuePacket(ZMPacket* zm_packet) {
pktQueue.push_back(zm_packet); pktQueue.push_back(zm_packet);
packet_counts[zm_packet->packet.stream_index] += 1; packet_counts[zm_packet->packet.stream_index] += 1;
Debug(1, "packet counts for %d is %d",
zm_packet->packet.stream_index, packet_counts[zm_packet->packet.stream_index]);
if ( analysis_it == pktQueue.end() ) { if ( analysis_it == pktQueue.end() ) {
// Analsys_it should only point to end when queue is empty // Analsys_it should only point to end when queue is empty
Debug(4, "pointing analysis_it to back"); Debug(4, "pointing analysis_it to back");
@ -95,8 +92,8 @@ bool zm_packetqueue::queuePacket(ZMPacket* zm_packet) {
while ( packet_counts[video_stream_id] > max_video_packet_count ) { while ( packet_counts[video_stream_id] > max_video_packet_count ) {
//clearQueue(max_video_packet_count, video_stream_id); //clearQueue(max_video_packet_count, video_stream_id);
//clearQueue is rather heavy. Since this is the only packet injection spot, we can just start at the beginning of the queue and remove packets until we get to the next video keyframe //clearQueue is rather heavy. Since this is the only packet injection spot, we can just start at the beginning of the queue and remove packets until we get to the next video keyframe
Debug(1, "Deleting a packet with stream index (%d) with keyframe(%d), Image_index(%d) video_frames_to_keep is (%d) max: %d", Debug(1, "Deleting a packet with stream index (%d) with keyframe(%d), video_frames_to_keep is (%d) max: %d",
zm_packet->packet.stream_index, zm_packet->keyframe, zm_packet->image_index, packet_counts[video_stream_id] , max_video_packet_count); zm_packet->packet.stream_index, zm_packet->keyframe, packet_counts[video_stream_id], max_video_packet_count);
ZMPacket *zm_packet = *pktQueue.begin(); ZMPacket *zm_packet = *pktQueue.begin();
pktQueue.pop_front(); pktQueue.pop_front();
packet_counts[zm_packet->packet.stream_index] -= 1; packet_counts[zm_packet->packet.stream_index] -= 1;

View File

@ -25,8 +25,7 @@
#if HAVE_LIBSWSCALE && HAVE_LIBAVUTIL #if HAVE_LIBSWSCALE && HAVE_LIBAVUTIL
SWScale::SWScale() : gotdefaults(false), swscale_ctx(nullptr), input_avframe(nullptr), output_avframe(nullptr) { SWScale::SWScale() : gotdefaults(false), swscale_ctx(nullptr), input_avframe(nullptr), output_avframe(nullptr) {
Debug(4,"SWScale object created"); Debug(4, "SWScale object created");
} }
bool SWScale::init() { bool SWScale::init() {
@ -68,10 +67,14 @@ SWScale::~SWScale() {
swscale_ctx = nullptr; swscale_ctx = nullptr;
} }
Debug(4,"SWScale object destroyed"); Debug(4, "SWScale object destroyed");
} }
int SWScale::SetDefaults(enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height) { int SWScale::SetDefaults(
enum _AVPIXELFORMAT in_pf,
enum _AVPIXELFORMAT out_pf,
unsigned int width,
unsigned int height) {
/* Assign the defaults */ /* Assign the defaults */
default_input_pf = in_pf; default_input_pf = in_pf;
@ -109,16 +112,16 @@ int SWScale::Convert(
break; break;
} }
/* Get the context */ /* Get the context */
swscale_ctx = sws_getCachedContext( swscale_ctx, swscale_ctx = sws_getCachedContext(swscale_ctx,
in_frame->width, in_frame->height, format, in_frame->width, in_frame->height, format,
out_frame->width, out_frame->height, (AVPixelFormat)out_frame->format, out_frame->width, out_frame->height, (AVPixelFormat)out_frame->format,
SWS_FAST_BILINEAR, NULL, NULL, NULL ); SWS_FAST_BILINEAR, NULL, NULL, NULL);
if ( swscale_ctx == NULL ) { if ( swscale_ctx == NULL ) {
Error("Failed getting swscale context"); Error("Failed getting swscale context");
return -6; return -6;
} }
/* Do the conversion */ /* Do the conversion */
if(!sws_scale(swscale_ctx, in_frame->data, in_frame->linesize, 0, in_frame->height, out_frame->data, out_frame->linesize ) ) { if ( !sws_scale(swscale_ctx, in_frame->data, in_frame->linesize, 0, in_frame->height, out_frame->data, out_frame->linesize ) ) {
Error("swscale conversion failed"); Error("swscale conversion failed");
return -10; return -10;
} }
@ -138,6 +141,8 @@ int SWScale::Convert(
unsigned int new_width, unsigned int new_width,
unsigned int new_height unsigned int new_height
) { ) {
Debug(1, "Convert: in_buffer %p in_buffer_size %d out_buffer %p size %d width %d height %d width %d height %d",
in_buffer, in_buffer_size, out_buffer, out_buffer_size, width, height, new_width, new_height);
/* Parameter checking */ /* Parameter checking */
if ( in_buffer == nullptr ) { if ( in_buffer == nullptr ) {
Error("NULL Input buffer"); Error("NULL Input buffer");
@ -151,7 +156,7 @@ int SWScale::Convert(
// Error("Invalid input or output pixel formats"); // Error("Invalid input or output pixel formats");
// return -2; // return -2;
// } // }
if (!width || !height || !new_height || !new_width) { if ( !width || !height || !new_height || !new_width ) {
Error("Invalid width or height"); Error("Invalid width or height");
return -3; return -3;
} }
@ -188,7 +193,7 @@ int SWScale::Convert(
/* Check the buffer sizes */ /* Check the buffer sizes */
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
size_t insize = av_image_get_buffer_size(in_pf, width, height, 1); size_t insize = av_image_get_buffer_size(in_pf, width, height, 32);
#else #else
size_t insize = avpicture_get_size(in_pf, width, height); size_t insize = avpicture_get_size(in_pf, width, height);
#endif #endif
@ -197,7 +202,7 @@ int SWScale::Convert(
return -4; return -4;
} }
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
size_t outsize = av_image_get_buffer_size(out_pf, new_width, new_height, 1); size_t outsize = av_image_get_buffer_size(out_pf, new_width, new_height, 32);
#else #else
size_t outsize = avpicture_get_size(out_pf, new_width, new_height); size_t outsize = avpicture_get_size(out_pf, new_width, new_height);
#endif #endif
@ -208,7 +213,9 @@ int SWScale::Convert(
} }
/* Get the context */ /* Get the context */
swscale_ctx = sws_getCachedContext( swscale_ctx, width, height, in_pf, new_width, new_height, out_pf, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr ); swscale_ctx = sws_getCachedContext(
swscale_ctx, width, height, in_pf, new_width, new_height,
out_pf, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
if ( swscale_ctx == nullptr ) { if ( swscale_ctx == nullptr ) {
Error("Failed getting swscale context"); Error("Failed getting swscale context");
return -6; return -6;
@ -216,7 +223,7 @@ int SWScale::Convert(
/* Fill in the buffers */ /* Fill in the buffers */
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
if (av_image_fill_arrays(input_avframe->data, input_avframe->linesize, if ( av_image_fill_arrays(input_avframe->data, input_avframe->linesize,
(uint8_t*) in_buffer, in_pf, width, height, 1) <= 0) { (uint8_t*) in_buffer, in_pf, width, height, 1) <= 0) {
#else #else
if (avpicture_fill((AVPicture*) input_avframe, (uint8_t*) in_buffer, if (avpicture_fill((AVPicture*) input_avframe, (uint8_t*) in_buffer,
@ -226,10 +233,10 @@ int SWScale::Convert(
return -7; return -7;
} }
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
if (av_image_fill_arrays(output_avframe->data, output_avframe->linesize, if ( av_image_fill_arrays(output_avframe->data, output_avframe->linesize,
out_buffer, out_pf, new_width, new_height, 1) <= 0) { out_buffer, out_pf, new_width, new_height, 1) <= 0) {
#else #else
if (avpicture_fill((AVPicture*) output_avframe, out_buffer, out_pf, new_width, if ( avpicture_fill((AVPicture*) output_avframe, out_buffer, out_pf, new_width,
new_height) <= 0) { new_height) <= 0) {
#endif #endif
Error("Failed filling output frame with output buffer"); Error("Failed filling output frame with output buffer");
@ -237,7 +244,9 @@ int SWScale::Convert(
} }
/* Do the conversion */ /* Do the conversion */
if(!sws_scale(swscale_ctx, input_avframe->data, input_avframe->linesize, 0, height, output_avframe->data, output_avframe->linesize ) ) { if ( !sws_scale(swscale_ctx,
input_avframe->data, input_avframe->linesize,
0, height, output_avframe->data, output_avframe->linesize ) ) {
Error("swscale conversion failed"); Error("swscale conversion failed");
return -10; return -10;
} }
@ -245,18 +254,33 @@ int SWScale::Convert(
return 0; return 0;
} }
int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height) { int SWScale::Convert(
const uint8_t* in_buffer,
const size_t in_buffer_size,
uint8_t* out_buffer,
const size_t out_buffer_size,
enum _AVPIXELFORMAT in_pf,
enum _AVPIXELFORMAT out_pf,
unsigned int width,
unsigned int height) {
return Convert(in_buffer, in_buffer_size, out_buffer, out_buffer_size, in_pf, out_pf, width, height, width, height); return Convert(in_buffer, in_buffer_size, out_buffer, out_buffer_size, in_pf, out_pf, width, height, width, height);
} }
int SWScale::Convert(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height) { int SWScale::Convert(
const Image* img,
uint8_t* out_buffer,
const size_t out_buffer_size,
enum _AVPIXELFORMAT in_pf,
enum _AVPIXELFORMAT out_pf,
unsigned int width,
unsigned int height) {
if ( img->Width() != width ) { if ( img->Width() != width ) {
Error("Source image width differs. Source: %d Output: %d",img->Width(), width); Error("Source image width differs. Source: %d Output: %d", img->Width(), width);
return -12; return -12;
} }
if ( img->Height() != height ) { if ( img->Height() != height ) {
Error("Source image height differs. Source: %d Output: %d",img->Height(), height); Error("Source image height differs. Source: %d Output: %d", img->Height(), height);
return -13; return -13;
} }

View File

@ -88,10 +88,12 @@ VideoStore::VideoStore(
audio_next_pts = 0; audio_next_pts = 0;
out_format = NULL; out_format = NULL;
oc = NULL; oc = NULL;
swscale.init();
} // VideoStore::VideoStore } // VideoStore::VideoStore
bool VideoStore::open() { bool VideoStore::open() {
Info("Opening video storage stream %s format: %s", filename, format); Debug(1, "Opening video storage stream %s format: %s", filename, format);
int ret = avformat_alloc_output_context2(&oc, nullptr, nullptr, filename); int ret = avformat_alloc_output_context2(&oc, nullptr, nullptr, filename);
if ( ret < 0 ) { if ( ret < 0 ) {
@ -132,6 +134,19 @@ bool VideoStore::open() {
zm_dump_codecpar(video_in_stream->codecpar); zm_dump_codecpar(video_in_stream->codecpar);
} }
int wanted_codec = monitor->OutputCodec();
if ( !wanted_codec ) {
// default to h264
Debug(2, "Defaulting to H264");
wanted_codec = AV_CODEC_ID_H264;
// FIXME what is the optimal codec? Probably low latency h264 which is effectively mjpeg
} else {
Debug(2, "Codec is %d, wanted %d", video_in_ctx->codec_id, wanted_codec);
}
std::string wanted_encoder = monitor->Encoder();
// FIXME Should check that we are set to passthrough. Might be same codec, but want privacy overlays
if ( (!wanted_codec) or (video_in_ctx->codec_id == wanted_codec) ) {
video_out_ctx = avcodec_alloc_context3(NULL); video_out_ctx = avcodec_alloc_context3(NULL);
if ( oc->oformat->flags & AVFMT_GLOBALHEADER ) { if ( oc->oformat->flags & AVFMT_GLOBALHEADER ) {
#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) #if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0)
@ -140,23 +155,19 @@ bool VideoStore::open() {
video_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; video_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;
#endif #endif
} }
if ( !video_out_ctx->codec_tag ) { if ( !video_out_ctx->codec_tag ) {
video_out_ctx->codec_tag = video_out_ctx->codec_tag =
av_codec_get_tag(oc->oformat->codec_tag, video_in_ctx->codec_id); av_codec_get_tag(oc->oformat->codec_tag, video_out_ctx->codec_id);
Debug(2, "No codec_tag, setting to %d", video_out_ctx->codec_tag); Debug(2, "No codec_tag, setting to %d", video_out_ctx->codec_tag);
} }
int wanted_codec = monitor->OutputCodec(); video_out_ctx->time_base = video_in_ctx->time_base;
if ( !wanted_codec ) { if ( ! (video_out_ctx->time_base.num && video_out_ctx->time_base.den) ) {
// default to h264 Debug(2,"No timebase found in video in context, defaulting to Q");
//Debug(2, "Defaulting to H264"); video_out_ctx->time_base = AV_TIME_BASE_Q;
//wanted_codec = AV_CODEC_ID_H264; }
} else { // Copy params from instream to ctx
Debug(2, "Codec is %d, wanted %d", video_in_ctx->codec_id, wanted_codec); // There might not be a useful video_in_stream. v4l in might not populate this very
}
// FIXME Should check that we are set to passthrough. Might be same codec, but want privacy overlays
if ( (!wanted_codec) or (video_in_ctx->codec_id == wanted_codec) ) {
// Copy params from instream to ctx
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
ret = avcodec_parameters_to_context(video_out_ctx, video_in_stream->codecpar); ret = avcodec_parameters_to_context(video_out_ctx, video_in_stream->codecpar);
#else #else
@ -167,7 +178,6 @@ bool VideoStore::open() {
return false; return false;
} }
//video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate //video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate
video_out_ctx->time_base = video_in_ctx->time_base;
// Fix deprecated formats // Fix deprecated formats
switch ( video_out_ctx->pix_fmt ) { switch ( video_out_ctx->pix_fmt ) {
case AV_PIX_FMT_YUVJ422P : case AV_PIX_FMT_YUVJ422P :
@ -187,18 +197,44 @@ bool VideoStore::open() {
} }
} else { // Either no video in or not the desired codec } else { // Either no video in or not the desired codec
for ( unsigned int i = 0; i < sizeof(codec_data) / sizeof(*codec_data); i++ ) { for ( unsigned int i = 0; i < sizeof(codec_data) / sizeof(*codec_data); i++ ) {
if ( wanted_encoder != "" ) {
if ( wanted_encoder != codec_data[i].codec_name ) {
Debug(1, "Not the right codec name %s != %s", codec_data[i].codec_name, wanted_encoder.c_str());
continue;
}
}
if ( codec_data[i].codec_id != wanted_codec ) { if ( codec_data[i].codec_id != wanted_codec ) {
Debug(1, "Not the right codec %d != %d", codec_data[i].codec_id, wanted_codec); Debug(1, "Not the right codec %d != %d", codec_data[i].codec_id, wanted_codec);
continue; continue;
} }
video_out_codec = avcodec_find_encoder_by_name(codec_data[i].codec_name); video_out_codec = avcodec_find_encoder_by_name(codec_data[i].codec_name);
if ( ! video_out_codec ) { if ( !video_out_codec ) {
Debug(1, "Didn't find encoder for %s", codec_data[i].codec_name); Debug(1, "Didn't find encoder for %s", codec_data[i].codec_name);
continue; continue;
} }
Debug(1, "Found video codec for %s", codec_data[i].codec_name); Debug(1, "Found video codec for %s", codec_data[i].codec_name);
video_out_ctx = avcodec_alloc_context3(video_out_codec);
if ( oc->oformat->flags & AVFMT_GLOBALHEADER ) {
#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0)
video_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
#else
video_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;
#endif
}
if ( !video_out_ctx->codec_tag ) {
video_out_ctx->codec_tag =
av_codec_get_tag(oc->oformat->codec_tag, video_out_ctx->codec_id);
Debug(2, "No codec_tag, setting to %d", video_out_ctx->codec_tag);
}
video_out_ctx->time_base = video_in_ctx->time_base;
if ( ! (video_out_ctx->time_base.num && video_out_ctx->time_base.den) ) {
Debug(2,"No timebase found in video in context, defaulting to Q");
video_out_ctx->time_base = AV_TIME_BASE_Q;
}
video_out_ctx->codec_id = codec_data[i].codec_id;
video_out_ctx->pix_fmt = codec_data[i].pix_fmt; video_out_ctx->pix_fmt = codec_data[i].pix_fmt;
video_out_ctx->level = 32; video_out_ctx->level = 32;
@ -207,22 +243,22 @@ bool VideoStore::open() {
video_out_ctx->height = monitor->Height(); video_out_ctx->height = monitor->Height();
video_out_ctx->codec_type = AVMEDIA_TYPE_VIDEO; video_out_ctx->codec_type = AVMEDIA_TYPE_VIDEO;
// Just copy them from the in, no reason to choose different
video_out_ctx->time_base = video_in_ctx->time_base;
if ( ! (video_out_ctx->time_base.num && video_out_ctx->time_base.den) ) {
Debug(2,"No timebase found in video in context, defaulting to Q");
video_out_ctx->time_base = AV_TIME_BASE_Q;
}
video_out_stream->time_base = video_in_stream ? video_in_stream->time_base : AV_TIME_BASE_Q;
if ( video_out_ctx->codec_id == AV_CODEC_ID_H264 ) { if ( video_out_ctx->codec_id == AV_CODEC_ID_H264 ) {
/*
video_out_ctx->bit_rate = 2000000;
video_out_ctx->gop_size = 12;
video_out_ctx->max_b_frames = 1; video_out_ctx->max_b_frames = 1;
if ( video_out_ctx->priv_data ) { if ( video_out_ctx->priv_data ) {
//av_opt_set(video_out_ctx->priv_data, "crf", "1", AV_OPT_SEARCH_CHILDREN); Debug(2, "setting priv_data crf");
//av_opt_set(video_out_ctx->priv_data, "preset", "ultrafast", 0); av_opt_set(video_out_ctx->priv_data, "crf", "1", AV_OPT_SEARCH_CHILDREN);
Debug(2, "setting priv_data preset");
av_opt_set(video_out_ctx->priv_data, "preset", "ultrafast", 0);
} else { } else {
Debug(2, "Not setting priv_data"); Debug(2, "Not setting priv_data");
av_opt_set(video_out_ctx->priv_data, "preset", "fast", 0);
Debug(2, "Not setting priv_data");
} }
*/
} else if ( video_out_ctx->codec_id == AV_CODEC_ID_MPEG2VIDEO ) { } else if ( video_out_ctx->codec_id == AV_CODEC_ID_MPEG2VIDEO ) {
/* just for testing, we also add B frames */ /* just for testing, we also add B frames */
video_out_ctx->max_b_frames = 2; video_out_ctx->max_b_frames = 2;
@ -235,13 +271,12 @@ bool VideoStore::open() {
AVDictionary *opts = 0; AVDictionary *opts = 0;
std::string Options = monitor->GetEncoderOptions(); std::string Options = monitor->GetEncoderOptions();
Debug(2, "Options?");
Debug(2, "Options? %s", Options.c_str()); Debug(2, "Options? %s", Options.c_str());
ret = av_dict_parse_string(&opts, Options.c_str(), "=", ",#\n", 0); ret = av_dict_parse_string(&opts, Options.c_str(), "=", ",#\n", 0);
if ( ret < 0 ) { if ( ret < 0 ) {
Warning("Could not parse ffmpeg encoder options list '%s'\n", Options.c_str()); Warning("Could not parse ffmpeg encoder options list '%s'\n", Options.c_str());
} else { } else {
AVDictionaryEntry *e = NULL; AVDictionaryEntry *e = nullptr;
while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) {
Debug(3, "Encoder Option %s=%s", e->key, e->value); Debug(3, "Encoder Option %s=%s", e->key, e->value);
} }
@ -252,16 +287,15 @@ bool VideoStore::open() {
video_out_codec->name, video_out_codec->name,
av_make_error_string(ret).c_str() av_make_error_string(ret).c_str()
); );
video_out_codec = NULL; video_out_codec = nullptr;
} }
AVDictionaryEntry *e = NULL; AVDictionaryEntry *e = nullptr;
while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != nullptr ) {
Warning("Encoder Option %s not recognized by ffmpeg codec", e->key); Warning("Encoder Option %s not recognized by ffmpeg codec", e->key);
} }
av_dict_free(&opts); av_dict_free(&opts);
if ( video_out_codec ) break; if ( video_out_codec ) break;
} // end foreach codec } // end foreach codec
if ( !video_out_codec ) { if ( !video_out_codec ) {
@ -270,12 +304,12 @@ bool VideoStore::open() {
// We allocate and copy in newer ffmpeg, so need to free it // We allocate and copy in newer ffmpeg, so need to free it
avcodec_free_context(&video_out_ctx); avcodec_free_context(&video_out_ctx);
#endif #endif
video_out_ctx = NULL; video_out_ctx = nullptr;
return false; return false;
} // end if can't open codec } // end if can't open codec
Debug(2, "Sucess opening codec"); Debug(2, "Success opening codec");
} // end if copying or transcoding } // end if copying or transcoding
} // end if video_in_stream } // end if video_in_stream
@ -1026,11 +1060,11 @@ bool VideoStore::setup_resampler() {
#endif #endif
} // end bool VideoStore::setup_resampler() } // end bool VideoStore::setup_resampler()
int VideoStore::writePacket( ZMPacket *ipkt ) { int VideoStore::writePacket(ZMPacket *ipkt) {
if ( ipkt->packet.stream_index == video_in_stream_index ) { if ( ipkt->packet.stream_index == video_in_stream_index ) {
return writeVideoFramePacket( ipkt ); return writeVideoFramePacket(ipkt);
} else if ( ipkt->packet.stream_index == audio_in_stream_index ) { } else if ( ipkt->packet.stream_index == audio_in_stream_index ) {
return writeAudioFramePacket( ipkt ); return writeAudioFramePacket(ipkt);
} }
Error("Unknown stream type in packet (%d) out input video stream is (%d) and audio is (%d)", Error("Unknown stream type in packet (%d) out input video stream is (%d) and audio is (%d)",
ipkt->packet.stream_index, video_in_stream_index, ( audio_in_stream ? audio_in_stream_index : -1 ) ipkt->packet.stream_index, video_in_stream_index, ( audio_in_stream ? audio_in_stream_index : -1 )
@ -1044,10 +1078,10 @@ int VideoStore::writeVideoFramePacket(ZMPacket *zm_packet) {
// if we have to transcode // if we have to transcode
if ( video_out_ctx->codec_id != video_in_ctx->codec_id ) { if ( video_out_ctx->codec_id != video_in_ctx->codec_id ) {
//Debug(3, "Have encoding video frame count (%d)", frame_count); Debug(3, "Have encoding video frame count (%d)", frame_count);
if ( !zm_packet->out_frame ) { if ( !zm_packet->out_frame ) {
//Debug(3, "Have no out frame"); Debug(3, "Have no out frame");
AVFrame *out_frame = zm_packet->get_out_frame(video_out_ctx); AVFrame *out_frame = zm_packet->get_out_frame(video_out_ctx);
if ( !out_frame ) { if ( !out_frame ) {
Error("Unable to allocate a frame"); Error("Unable to allocate a frame");
@ -1055,23 +1089,23 @@ int VideoStore::writeVideoFramePacket(ZMPacket *zm_packet) {
} }
if ( !zm_packet->in_frame ) { if ( !zm_packet->in_frame ) {
//Debug(2,"Have no in_frame"); Debug(2, "Have no in_frame");
if ( zm_packet->packet.size ) { if ( zm_packet->packet.size ) {
//Debug(2,"Decoding"); Debug(2, "Decoding");
if ( !zm_packet->decode(video_in_ctx) ) { if ( !zm_packet->decode(video_in_ctx) ) {
Debug(2, "unable to decode yet."); Debug(2, "unable to decode yet.");
return 0; return 0;
} }
//Go straight to out frame // Go straight to out frame
swscale.Convert(zm_packet->in_frame, out_frame); swscale.Convert(zm_packet->in_frame, out_frame);
} else if ( zm_packet->image ) { } else if ( zm_packet->image ) {
//Debug(2,"Have an image, convert it"); Debug(2, "Have an image, convert it");
//Go straight to out frame //Go straight to out frame
swscale.Convert( swscale.Convert(
zm_packet->image, zm_packet->image,
zm_packet->buffer, zm_packet->buffer,
zm_packet->codec_imgsize, zm_packet->codec_imgsize,
(AVPixelFormat)zm_packet->image->AVPixFormat(), zm_packet->image->AVPixFormat(),
video_out_ctx->pix_fmt, video_out_ctx->pix_fmt,
video_out_ctx->width, video_out_ctx->width,
video_out_ctx->height video_out_ctx->height
@ -1120,7 +1154,7 @@ int VideoStore::writeVideoFramePacket(ZMPacket *zm_packet) {
} }
av_init_packet(&opkt); av_init_packet(&opkt);
opkt.data = NULL; opkt.data = nullptr;
opkt.size = 0; opkt.size = 0;
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
// Do this to allow the encoder to choose whether to use I/P/B frame // Do this to allow the encoder to choose whether to use I/P/B frame
@ -1168,37 +1202,41 @@ int VideoStore::writeVideoFramePacket(ZMPacket *zm_packet) {
opkt.dts = av_rescale_q(opkt.dts, video_out_ctx->time_base, video_out_stream->time_base); opkt.dts = av_rescale_q(opkt.dts, video_out_ctx->time_base, video_out_stream->time_base);
int64_t duration; int64_t duration;
if ( zm_packet->in_frame->pkt_duration ) { if ( zm_packet->in_frame ) {
duration = av_rescale_q( if ( zm_packet->in_frame->pkt_duration ) {
zm_packet->in_frame->pkt_duration, duration = av_rescale_q(
video_in_stream->time_base, zm_packet->in_frame->pkt_duration,
video_out_stream->time_base);
Debug(1, "duration from ipkt: pts(%" PRId64 ") - last_pts(%" PRId64 ") = (%" PRId64 ") => (%" PRId64 ") (%d/%d) (%d/%d)",
zm_packet->in_frame->pts,
video_last_pts,
zm_packet->in_frame->pkt_duration,
duration,
video_in_stream->time_base.num,
video_in_stream->time_base.den,
video_out_stream->time_base.num,
video_out_stream->time_base.den
);
} else {
duration =
av_rescale_q(
zm_packet->in_frame->pts - video_last_pts,
video_in_stream->time_base, video_in_stream->time_base,
video_out_stream->time_base); video_out_stream->time_base);
Debug(1, "duration calc: pts(%" PRId64 ") - last_pts(%" PRId64 ") = (%" PRId64 ") => (%" PRId64 ")", Debug(1, "duration from ipkt: pts(%" PRId64 ") - last_pts(%" PRId64 ") = (%" PRId64 ") => (%" PRId64 ") (%d/%d) (%d/%d)",
zm_packet->in_frame->pts, zm_packet->in_frame->pts,
video_last_pts, video_last_pts,
zm_packet->in_frame->pts - video_last_pts, zm_packet->in_frame->pkt_duration,
duration duration,
); video_in_stream->time_base.num,
if ( duration <= 0 ) { video_in_stream->time_base.den,
duration = zm_packet->in_frame->pkt_duration ? zm_packet->in_frame->pkt_duration : av_rescale_q(1,video_in_stream->time_base, video_out_stream->time_base); video_out_stream->time_base.num,
} video_out_stream->time_base.den
} );
} else {
duration =
av_rescale_q(
zm_packet->in_frame->pts - video_last_pts,
video_in_stream->time_base,
video_out_stream->time_base);
Debug(1, "duration calc: pts(%" PRId64 ") - last_pts(%" PRId64 ") = (%" PRId64 ") => (%" PRId64 ")",
zm_packet->in_frame->pts,
video_last_pts,
zm_packet->in_frame->pts - video_last_pts,
duration
);
if ( duration <= 0 ) {
duration = zm_packet->in_frame->pkt_duration ? zm_packet->in_frame->pkt_duration : av_rescale_q(1,video_in_stream->time_base, video_out_stream->time_base);
}
} // end if in_frmae->pkt_duration
} else {
duration = av_rescale_q(1,video_in_stream->time_base, video_out_stream->time_base);
} // end if in_frmae
opkt.duration = duration; opkt.duration = duration;
} else { // codec matches, we are doing passthrough } else { // codec matches, we are doing passthrough

View File

@ -24,7 +24,7 @@ class VideoStore {
private: private:
struct CodecData { struct CodecData {
const int codec_id; const AVCodecID codec_id;
const char *codec_codec; const char *codec_codec;
const char *codec_name; const char *codec_name;
const enum AVPixelFormat pix_fmt; const enum AVPixelFormat pix_fmt;

View File

@ -156,32 +156,21 @@ class MonitorsController extends AppController {
return; return;
} }
$monitor = $this->Monitor->find('first', array(
'conditions' => array('Id' => $id)
))['Monitor'];
$message = ''; $message = '';
if ( $this->Monitor->save($this->request->data) ) { if ( $this->Monitor->save($this->request->data) ) {
$message = 'Saved'; $message = 'Saved';
$Monitor = $this->Monitor->find('first', array(
'fields' => array('Function','ServerId'), // Stop the monitor. Should happen before saving
$this->Monitor->daemonControl($monitor, 'stop');
$monitor = $this->Monitor->find('first', array(
'conditions' => array('Id' => $id) 'conditions' => array('Id' => $id)
))['Monitor']; ))['Monitor'];
// - restart or stop this monitor after change $this->Monitor->daemonControl($monitor, 'start');
$func = $Monitor['Function'];
// We don't pass the request data as the monitor object because it may be a subset of the full monitor array
$this->daemonControl($this->Monitor->id, 'stop');
if (
( $func != 'None' )
and
(
(!defined('ZM_SERVER_ID'))
or
($Monitor['ServerId']==ZM_SERVER_ID)
)
) {
if ( !defined('ZM_SERVER_ID')) {
ZM\Debug("Not defined ZM_SERVER_ID");
}
$this->daemonControl($this->Monitor->id, 'start');
}
} else { } else {
$message = 'Error ' . print_r($this->Monitor->invalidFields(), true); $message = 'Error ' . print_r($this->Monitor->invalidFields(), true);
} }
@ -353,7 +342,6 @@ class MonitorsController extends AppController {
} }
public function daemonControl($id, $command, $daemon=null) { public function daemonControl($id, $command, $daemon=null) {
// Need to see if it is local or remote // Need to see if it is local or remote
$monitor = $this->Monitor->find('first', array( $monitor = $this->Monitor->find('first', array(
'fields' => array('Type', 'Function', 'Device'), 'fields' => array('Type', 'Function', 'Device'),
@ -361,35 +349,8 @@ class MonitorsController extends AppController {
)); ));
$monitor = $monitor['Monitor']; $monitor = $monitor['Monitor'];
$daemons = array(); $status_text = $this->Monitor->daemonControl($monitor, $command, $daemon);
if ( ! $daemon ) {
if ( $monitor['Function'] == 'Monitor' ) {
array_push($daemons, 'zmc');
} else {
array_push($daemons, 'zmc', 'zma');
}
} else {
array_push($daemons, $daemon);
}
$zm_path_bin = Configure::read('ZM_PATH_BIN');
$status_text = '';
foreach ( $daemons as $daemon ) {
$args = '';
if ( $daemon == 'zmc' and $monitor['Type'] == 'Local' ) {
$args = '-d ' . $monitor['Device'];
} else if ( $daemon == 'zmcontrol.pl' ) {
$args = '--id '.$id;
} else {
$args = '-m ' . $id;
}
$shellcmd = escapeshellcmd("$zm_path_bin/zmdc.pl $command $daemon $args");
ZM\Debug("Command $shellcmd");
$status = exec($shellcmd);
$status_text .= $status."\n";
}
$this->set(array( $this->set(array(
'status' => 'ok', 'status' => 'ok',
'statustext' => $status_text, 'statustext' => $status_text,

View File

@ -136,4 +136,44 @@ class Monitor extends AppModel {
'joinTable' => 'Monitor_Status', 'joinTable' => 'Monitor_Status',
) )
); );
public function daemonControl($monitor, $command, $daemon=null) {
if ( $monitor['Function'] == 'None' ) {
ZM\Debug('Calling daemonControl when Function == None');
return;
}
if ( defined('ZM_SERVER_ID') and ($monitor['ServerId']!=ZM_SERVER_ID) ) {
ZM\Debug('Calling daemonControl for Monitor assigned to different server');
return;
}
$daemons = array();
if ( ! $daemon ) {
if ( $monitor['Function'] == 'Monitor' ) {
array_push($daemons, 'zmc');
} else {
array_push($daemons, 'zmc', 'zma');
}
} else {
array_push($daemons, $daemon);
}
$status_text = '';
foreach ( $daemons as $daemon ) {
$args = '';
if ( $daemon == 'zmc' and $monitor['Type'] == 'Local' ) {
$args = '-d ' . $monitor['Device'];
} else if ( $daemon == 'zmcontrol.pl' ) {
$args = '--id '.$monitor['Id'];
} else {
$args = '-m ' . $monitor['Id'];
}
$shellcmd = escapeshellcmd(ZM_PATH_BIN.'/zmdc.pl '.$command.' '.$daemon.' '.$args);
ZM\Debug("Command $shellcmd");
$status = exec($shellcmd);
$status_text .= $status.PHP_EOL;
} # end foreach daemon
return $status_text;
} # end function daemonControl
} }

View File

@ -202,6 +202,9 @@ if ( $action == 'save' ) {
} // end foreach zone } // end foreach zone
} // end if rotation or just size change } // end if rotation or just size change
} // end if changes in width or height } // end if changes in width or height
} else {
global $error_message;
$error_message = dbError();
} // end if successful save } // end if successful save
$restart = true; $restart = true;
} else { // new monitor } else { // new monitor

View File

@ -112,10 +112,10 @@ function dbLog($sql, $update=false) {
function dbError($sql) { function dbError($sql) {
global $dbConn; global $dbConn;
$error = $dbConn->errorInfo(); $error = $dbConn->errorInfo();
if ( ! $error[0] ) if ( !$error[0] )
return ''; return '';
$message = "SQL-ERR '".implode("\n",$dbConn->errorInfo())."', statement was '".$sql."'"; $message = "SQL-ERR '".implode("\n", $dbConn->errorInfo())."', statement was '".$sql."'";
ZM\Error($message); ZM\Error($message);
return $message; return $message;
} }

View File

@ -16,6 +16,8 @@
// along with this program; if not, write to the Free Software // along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
// //
$j.ajaxSetup({timeout: AJAX_TIMEOUT});
var reportLogs = true;
if ( !window.console ) { if ( !window.console ) {
window.console = window.console =
@ -28,55 +30,63 @@ if ( !window.console ) {
error: function() {} error: function() {}
}; };
} }
if ( !console.debug ) { if ( !console.debug ) {
// IE8 has console but doesn't have console.debug so lets alias it. // IE8 has console but doesn't have console.debug so lets alias it.
console.debug = console.log; console.debug = console.log;
} }
var reportLogs = true; window.onerror = function(message, url, line) {
logReport("ERR", message, url, line);
};
var debugParms; window.addEventListener("securitypolicyviolation", function logCSP(evt) {
var debugReq; var level = evt.disposition == "enforce" ? "ERR" : "DBG";
var message = evt.blockedURI + " violated CSP " + evt.violatedDirective;
if ( evt.sample ) message += " (Sample: " + evt.sample + ")";
logReport(level, message, evt.sourceFile, evt.lineNumber);
});
function logReport( level, message, file, line ) { function logReport( level, message, file, line ) {
if ( !reportLogs ) { if ( !reportLogs ) return;
return;
}
if ( typeof(MooTools) == "undefined" ) {
return;
}
/* eslint-disable no-caller */ /* eslint-disable no-caller */
if ( arguments && arguments.callee && arguments.callee.caller && arguments.callee.caller.caller && arguments.callee.caller.caller.name ) { if ( arguments && arguments.callee && arguments.callee.caller && arguments.callee.caller.caller && arguments.callee.caller.caller.name ) {
message += ' - '+arguments.callee.caller.caller.name+'()'; message += ' - '+arguments.callee.caller.caller.name+'()';
//console.log("arguments"); //console.log("arguments");
} else {
//message += new Error().stack;
//console.log("stack");
} }
/* eslint-enable no-caller */
if ( !debugReq ) { var browser = {};
debugParms = "view=request&request=log&task=create"; if ( Browser ) {
if ( Browser ) { browser.name = Browser.name;
debugParms += "&browser[name]="+Browser.name+"&browser[version]="+Browser.version+"&browser[platform]="+(Browser.Platform?Browser.Platform.name:'unknown'); browser.version = Browser.version;
} else { browser.platform = Browser.Platform ? Browser.Platform.name : 'unknown';
debugParms += "&browser[name]=unknown&browser[version]=unknown&browser[platform]=unknown"; } else {
} browser.name = 'unknown';
debugReq = new Request.JSON({url: thisUrl, method: 'post', timeout: AJAX_TIMEOUT, link: 'chain'}); browser.version = 'unknown';
browser.platform = 'unknown';
} }
var requestParms = debugParms;
requestParms += "&level="+level+"&message="+encodeURIComponent(message); var data = {
view: 'request',
request: 'log',
task: 'create',
level: level,
message: encodeURIComponent(message),
browser: browser
};
if ( file ) { if ( file ) {
requestParms += "&file="+file; data.file = file;
} else if ( location.search ) { } else if ( location.search ) {
//location.search is the querystring part, so ?blah=blah but there is almost never any value to this //location.search is the querystring part, so ?blah=blah but there is almost never any value to this
requestParms += "&file="+location.search; data.file = location.search;
} }
if ( line ) {
requestParms += "&line="+line; if ( line ) data.line = line;
}
debugReq.send(requestParms); $j.getJSON(thisUrl, data);
} }
function Panic(message) { function Panic(message) {
@ -112,22 +122,6 @@ function Debug(message) {
} }
function Dump(value, label) { function Dump(value, label) {
if ( label ) { if ( label ) console.debug(label+" => ");
console.debug(label+" => ");
}
console.debug(value); console.debug(value);
} }
window.onerror =
function( message, url, line ) {
logReport("ERR", message, url, line);
};
window.addEventListener("securitypolicyviolation", function logCSP(evt) {
var level = evt.disposition == "enforce" ? "ERR" : "DBG";
var message = evt.blockedURI + " violated CSP " + evt.violatedDirective;
if ( evt.sample ) {
message += " (Sample: " + evt.sample + ")";
}
logReport(level, message, evt.sourceFile, evt.lineNumber);
});

View File

@ -437,9 +437,9 @@ function secsToTime( seconds ) {
function submitTab(evt) { function submitTab(evt) {
var tab = this.getAttribute("data-tab-name"); var tab = this.getAttribute("data-tab-name");
var form = $('contentForm'); var form = $j('#contentForm');
form.action.value = ""; form.attr('action', '');
form.tab.value = tab; form.attr('tab', tab);
form.submit(); form.submit();
evt.preventDefault(); evt.preventDefault();
} }
@ -599,11 +599,11 @@ function scaleToFit(baseWidth, baseHeight, scaleEl, bottomEl) {
return {width: Math.floor(newWidth), height: Math.floor(newHeight), autoScale: autoScale}; return {width: Math.floor(newWidth), height: Math.floor(newHeight), autoScale: autoScale};
} }
function setButtonState(element_id, butClass) { function setButtonState(element_id, btnClass) {
var element = $(element_id); var element = document.getElementById(element_id);
if ( element ) { if ( element ) {
element.className = butClass; element.className = btnClass;
if (butClass == 'unavail' || (butClass == 'active' && (element.id == 'pauseBtn' || element.id == 'playBtn'))) { if (btnClass == 'unavail' || (btnClass == 'active' && (element.id == 'pauseBtn' || element.id == 'playBtn'))) {
element.disabled = true; element.disabled = true;
} else { } else {
element.disabled = false; element.disabled = false;

View File

@ -156,6 +156,7 @@ if ( !$Event->Id() ) {
} }
?> ?>
<button id="statsBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Stats') ?>" ><i class="fa fa-info"></i></button> <button id="statsBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Stats') ?>" ><i class="fa fa-info"></i></button>
<button id="framesBtn" class="btn btn-normal" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Frames') ?>" ><i class="fa fa-picture-o"></i></button>
<button id="deleteBtn" class="btn btn-danger" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Delete') ?>"><i class="fa fa-trash"></i></button> <button id="deleteBtn" class="btn btn-danger" data-toggle="tooltip" data-placement="top" title="<?php echo translate('Delete') ?>"><i class="fa fa-trash"></i></button>
</div> </div>

View File

@ -102,7 +102,7 @@ getBodyTopHTML();
<th data-sortable="true" data-field="Archived"><?php echo translate('Archived') ?></th> <th data-sortable="true" data-field="Archived"><?php echo translate('Archived') ?></th>
<th data-sortable="true" data-field="Emailed"><?php echo translate('Emailed') ?></th> <th data-sortable="true" data-field="Emailed"><?php echo translate('Emailed') ?></th>
<th data-sortable="true" data-field="Monitor"><?php echo translate('Monitor') ?></th> <th data-sortable="true" data-field="Monitor"><?php echo translate('Monitor') ?></th>
<th data-sortable="true" data-field="Cause"><?php echo translate('Cause') ?></th> <th data-sortable="true" data-field="Cause" data-click-to-select="false"><?php echo translate('Cause') ?></th>
<th data-sortable="true" data-field="StartDateTime"><?php echo translate('AttrStartTime') ?></th> <th data-sortable="true" data-field="StartDateTime"><?php echo translate('AttrStartTime') ?></th>
<th data-sortable="true" data-field="EndDateTime"><?php echo translate('AttrEndTime') ?></th> <th data-sortable="true" data-field="EndDateTime"><?php echo translate('AttrEndTime') ?></th>
<th data-sortable="true" data-field="Length"><?php echo translate('Duration') ?></th> <th data-sortable="true" data-field="Length"><?php echo translate('Duration') ?></th>

View File

@ -1,12 +1,11 @@
var ProbeResults;
var probeReq = new Request.JSON( {url: thisUrl, method: 'get', timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getProbeResponse} );
function probe( url_e ) { function probe( url_e ) {
probeReq.send( "request=add_monitors&action=probe&url="+url_e.value ); $j.getJSON(thisUrl + '?view=request&request=add_monitors&action=probe&url=' + url_e.value)
.done(getProbeResponse)
.fail(logAjaxFail);
} }
var ProbeResults;
function getProbeResponse( respObj, respText ) { function getProbeResponse( respObj, respText ) {
if ( checkStreamForErrors( "getProbeResponse", respObj ) ) { if ( checkStreamForErrors( "getProbeResponse", respObj ) ) {
return; return;
@ -82,7 +81,6 @@ function addMonitor(url) {
function import_csv( form ) { function import_csv( form ) {
var formData = new FormData( form ); var formData = new FormData( form );
console.log(formData); console.log(formData);
//formData.append('file', $('#file')[0].files[0]);
$j.ajax({ $j.ajax({
url: thisUrl+"?request=add_monitors&action=import", url: thisUrl+"?request=add_monitors&action=import",
@ -90,16 +88,19 @@ function import_csv( form ) {
data: formData, data: formData,
processData: false, // tell jQuery not to process the data processData: false, // tell jQuery not to process the data
contentType: false, // tell jQuery not to set contentType contentType: false, // tell jQuery not to set contentType
success: function(data) { done: function(data) {
var json = JSON.parse(data); var json = JSON.parse(data);
parseStreams( json.Streams ); parseStreams( json.Streams );
} }
}); });
} }
function initPage() { function initPage() {
url = $j('#Url')[0]; var url = $j('#Url')[0];
if ( url.value ) { if ( url.value ) {
probe(url); probe(url);
} }
} }
window.addEventListener( 'DOMContentLoaded', initPage );
$j(document).ready(initPage);

View File

@ -1,4 +1,3 @@
$j.ajaxSetup({timeout: AJAX_TIMEOUT}); //sets timeout for all getJSON.
var table = $j('#eventStatsTable'); var table = $j('#eventStatsTable');
var backBtn = $j('#backBtn'); var backBtn = $j('#backBtn');
var renameBtn = $j('#renameBtn'); var renameBtn = $j('#renameBtn');
@ -27,14 +26,20 @@ var streamCmdTimer = null;
var streamStatus = null; var streamStatus = null;
var lastEventId = 0; var lastEventId = 0;
var zmsBroke = false; //Use alternate navigation if zms has crashed var zmsBroke = false; //Use alternate navigation if zms has crashed
var streamParms = "view=request&request=stream&connkey="+connKey;
if ( auth_hash ) streamParms += '&auth='+auth_hash;
var frameBatch = 40; var frameBatch = 40;
var currFrameId = null; var currFrameId = null;
var eventReq = new Request.JSON( {url: thisUrl, method: 'get', timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getEventResponse} ); var auth_hash;
var actReq = new Request.JSON( {url: thisUrl, method: 'get', timeout: AJAX_TIMEOUT, link: 'cancel', onSuccess: getActResponse} );
var frameReq = new Request.JSON( {url: thisUrl, method: 'get', timeout: AJAX_TIMEOUT, link: 'chain', onSuccess: getFrameResponse} ); function streamReq(data) {
var streamReq = new Request.JSON( {url: monitorUrl, method: 'get', timeout: AJAX_TIMEOUT, link: 'chain', onSuccess: getCmdResponse} ); if ( auth_hash ) data.auth = auth_hash;
data.connkey = connKey;
data.view = 'request';
data.request = 'stream';
$j.getJSON(thisUrl, data)
.done(getCmdResponse)
.fail(logAjaxFail);
}
// Function called when video.js hits the end of the video // Function called when video.js hits the end of the video
function vjsReplay() { function vjsReplay() {
@ -208,7 +213,7 @@ function changeScale() {
} // end function changeScale } // end function changeScale
function changeReplayMode() { function changeReplayMode() {
var replayMode = $('replayMode').get('value'); var replayMode = $j('#replayMode').val();
Cookie.write('replayMode', replayMode, {duration: 10*365, samesite: 'strict'}); Cookie.write('replayMode', replayMode, {duration: 10*365, samesite: 'strict'});
@ -217,6 +222,7 @@ function changeReplayMode() {
function changeRate() { function changeRate() {
var rate = parseInt($j('select[name="rate"]').val()); var rate = parseInt($j('select[name="rate"]').val());
if ( ! rate ) { if ( ! rate ) {
pauseClicked(); pauseClicked();
} else if ( rate < 0 ) { } else if ( rate < 0 ) {
@ -233,13 +239,13 @@ function changeRate() {
} }
}, 500); //500ms is a compromise between smooth reverse and realistic performance }, 500); //500ms is a compromise between smooth reverse and realistic performance
} else { } else {
streamReq.send(streamParms+"&command="+CMD_VARPLAY+"&rate="+rate); streamReq({command: CMD_VARPLAY, rate: rate});
} // end if vid } // end if vid
} else { // Forward rate } else { // Forward rate
if ( vid ) { if ( vid ) {
vid.playbackRate(rate/100); vid.playbackRate(rate/100);
} else { } else {
streamReq.send(streamParms+"&command="+CMD_VARPLAY+"&rate="+rate); streamReq({command: CMD_VARPLAY, rate: rate});
} }
} }
Cookie.write('zmEventRate', rate, {duration: 10*365, samesite: 'strict'}); Cookie.write('zmEventRate', rate, {duration: 10*365, samesite: 'strict'});
@ -291,9 +297,9 @@ function getCmdResponse( respObj, respText ) {
$j('#progressValue').html(secsToTime(parseInt(streamStatus.progress))); $j('#progressValue').html(secsToTime(parseInt(streamStatus.progress)));
$j('#zoomValue').html(streamStatus.zoom); $j('#zoomValue').html(streamStatus.zoom);
if ( streamStatus.zoom == "1.0" ) { if ( streamStatus.zoom == "1.0" ) {
setButtonState( $('zoomOutBtn'), 'unavail' ); setButtonState( 'zoomOutBtn', 'unavail' );
} else { } else {
setButtonState( $('zoomOutBtn'), 'inactive' ); setButtonState( 'zoomOutBtn', 'inactive' );
} }
updateProgressBar(); updateProgressBar();
@ -316,23 +322,24 @@ function pauseClicked() {
} }
vid.pause(); vid.pause();
} else { } else {
streamReq.send(streamParms+"&command="+CMD_PAUSE); streamReq({command: CMD_PAUSE});
} }
streamPause(); streamPause();
} }
function streamPause() { function streamPause() {
$j('#modeValue').html('Paused'); $j('#modeValue').html('Paused');
setButtonState( $('pauseBtn'), 'active' ); setButtonState( 'pauseBtn', 'active' );
setButtonState( $('playBtn'), 'inactive' ); setButtonState( 'playBtn', 'inactive' );
setButtonState( $('fastFwdBtn'), 'unavail' ); setButtonState( 'fastFwdBtn', 'unavail' );
setButtonState( $('slowFwdBtn'), 'inactive' ); setButtonState( 'slowFwdBtn', 'inactive' );
setButtonState( $('slowRevBtn'), 'inactive' ); setButtonState( 'slowRevBtn', 'inactive' );
setButtonState( $('fastRevBtn'), 'unavail' ); setButtonState( 'fastRevBtn', 'unavail' );
} }
function playClicked( ) { function playClicked( ) {
var rate_select = $j('select[name="rate"]'); var rate_select = $j('select[name="rate"]');
if ( ! rate_select.val() ) { if ( ! rate_select.val() ) {
$j('select[name="rate"]').val(100); $j('select[name="rate"]').val(100);
} }
@ -343,7 +350,7 @@ function playClicked( ) {
vjsPlay(); //handles fast forward and rewind vjsPlay(); //handles fast forward and rewind
} }
} else { } else {
streamReq.send(streamParms+"&command="+CMD_PLAY); streamReq({command: CMD_PLAY});
} }
streamPlay(); streamPlay();
} }
@ -358,31 +365,31 @@ function vjsPlay() { //catches if we change mode programatically
} }
function streamPlay( ) { function streamPlay( ) {
setButtonState( $('pauseBtn'), 'inactive' ); setButtonState( 'pauseBtn', 'inactive' );
setButtonState( $('playBtn'), 'active' ); setButtonState( 'playBtn', 'active' );
setButtonState( $('fastFwdBtn'), 'inactive' ); setButtonState( 'fastFwdBtn', 'inactive' );
setButtonState( $('slowFwdBtn'), 'unavail' ); setButtonState( 'slowFwdBtn', 'unavail' );
setButtonState( $('slowRevBtn'), 'unavail' ); setButtonState( 'slowRevBtn', 'unavail' );
setButtonState( $('fastRevBtn'), 'inactive' ); setButtonState( 'fastRevBtn', 'inactive' );
} }
function streamFastFwd( action ) { function streamFastFwd( action ) {
setButtonState( $('pauseBtn'), 'inactive' ); setButtonState( 'pauseBtn', 'inactive' );
setButtonState( $('playBtn'), 'inactive' ); setButtonState( 'playBtn', 'inactive' );
setButtonState( $('fastFwdBtn'), 'active' ); setButtonState( 'fastFwdBtn', 'active' );
setButtonState( $('slowFwdBtn'), 'unavail' ); setButtonState( 'slowFwdBtn', 'unavail' );
setButtonState( $('slowRevBtn'), 'unavail' ); setButtonState( 'slowRevBtn', 'unavail' );
setButtonState( $('fastRevBtn'), 'inactive' ); setButtonState( 'fastRevBtn', 'inactive' );
if ( vid ) { if ( vid ) {
if ( revSpeed != .5 ) stopFastRev(); if ( revSpeed != .5 ) stopFastRev();
vid.playbackRate(rates[rates.indexOf(vid.playbackRate()*100)-1]/100); vid.playbackRate(rates[rates.indexOf(vid.playbackRate()*100)-1]/100);
if ( rates.indexOf(vid.playbackRate()*100)-1 == -1 ) { if ( rates.indexOf(vid.playbackRate()*100)-1 == -1 ) {
setButtonState($('fastFwdBtn'), 'unavail'); setButtonState('fastFwdBtn', 'unavail');
} }
$j('select[name="rate"]').val(vid.playbackRate()*100); $j('select[name="rate"]').val(vid.playbackRate()*100);
Cookie.write('zmEventRate', vid.playbackRate()*100, {duration: 10*365, samesite: 'strict'}); Cookie.write('zmEventRate', vid.playbackRate()*100, {duration: 10*365, samesite: 'strict'});
} else { } else {
streamReq.send(streamParms+"&command="+CMD_FASTFWD); streamReq({command: CMD_FASTFWD});
} }
} }
@ -391,7 +398,7 @@ function streamSlowFwd( action ) {
if ( vid ) { if ( vid ) {
vid.currentTime(vid.currentTime() + spf); vid.currentTime(vid.currentTime() + spf);
} else { } else {
streamReq.send(streamParms+"&command="+CMD_SLOWFWD); streamReq({command: CMD_SLOWFWD});
} }
} }
@ -399,7 +406,7 @@ function streamSlowRev( action ) {
if ( vid ) { if ( vid ) {
vid.currentTime(vid.currentTime() - spf); vid.currentTime(vid.currentTime() - spf);
} else { } else {
streamReq.send(streamParms+"&command="+CMD_SLOWREV); streamReq({command: CMD_SLOWREV});
} }
} }
@ -412,16 +419,16 @@ function stopFastRev() {
} }
function streamFastRev( action ) { function streamFastRev( action ) {
setButtonState( $('pauseBtn'), 'inactive' ); setButtonState( 'pauseBtn', 'inactive' );
setButtonState( $('playBtn'), 'inactive' ); setButtonState( 'playBtn', 'inactive' );
setButtonState( $('fastFwdBtn'), 'inactive' ); setButtonState( 'fastFwdBtn', 'inactive' );
setButtonState( $('slowFwdBtn'), 'unavail' ); setButtonState( 'slowFwdBtn', 'unavail' );
setButtonState( $('slowRevBtn'), 'unavail' ); setButtonState( 'slowRevBtn', 'unavail' );
setButtonState( $('fastRevBtn'), 'active' ); setButtonState( 'fastRevBtn', 'active' );
if ( vid ) { //There is no reverse play with mp4. Set the speed to 0 and manually set the time back. if ( vid ) { //There is no reverse play with mp4. Set the speed to 0 and manually set the time back.
revSpeed = rates[rates.indexOf(revSpeed*100)-1]/100; revSpeed = rates[rates.indexOf(revSpeed*100)-1]/100;
if ( rates.indexOf(revSpeed*100) == 0 ) { if ( rates.indexOf(revSpeed*100) == 0 ) {
setButtonState( $('fastRevBtn'), 'unavail' ); setButtonState( 'fastRevBtn', 'unavail' );
} }
clearInterval(intervalRewind); clearInterval(intervalRewind);
$j('select[name="rate"]').val(-revSpeed*100); $j('select[name="rate"]').val(-revSpeed*100);
@ -436,7 +443,7 @@ function streamFastRev( action ) {
} }
}, 500); //500ms is a compromise between smooth reverse and realistic performance }, 500); //500ms is a compromise between smooth reverse and realistic performance
} else { } else {
streamReq.send(streamParms+"&command="+CMD_FASTREV); streamReq({command: CMD_FASTREV});
} }
} }
@ -452,7 +459,7 @@ function streamPrev(action) {
} else if (zmsBroke || (vid && PrevEventDefVideoPath.indexOf("view_video") < 0) || $j("#vjsMessage").length || PrevEventDefVideoPath.indexOf("view_video") > 0) {//zms broke, leaving videojs, last event, moving to videojs } else if (zmsBroke || (vid && PrevEventDefVideoPath.indexOf("view_video") < 0) || $j("#vjsMessage").length || PrevEventDefVideoPath.indexOf("view_video") > 0) {//zms broke, leaving videojs, last event, moving to videojs
location.replace(thisUrl + '?view=event&eid=' + prevEventId + filterQuery + sortQuery); location.replace(thisUrl + '?view=event&eid=' + prevEventId + filterQuery + sortQuery);
} else { } else {
streamReq.send(streamParms+"&command="+CMD_PREV); streamReq({command: CMD_PREV});
streamPlay(); streamPlay();
} }
} }
@ -480,7 +487,7 @@ function streamNext(action) {
} else if ( zmsBroke || (vid && NextEventDefVideoPath.indexOf("view_video") < 0) || NextEventDefVideoPath.indexOf("view_video") > 0) {//reload zms, leaving vjs, moving to vjs } else if ( zmsBroke || (vid && NextEventDefVideoPath.indexOf("view_video") < 0) || NextEventDefVideoPath.indexOf("view_video") > 0) {//reload zms, leaving vjs, moving to vjs
location.replace(thisUrl + '?view=event&eid=' + nextEventId + filterQuery + sortQuery); location.replace(thisUrl + '?view=event&eid=' + nextEventId + filterQuery + sortQuery);
} else { } else {
streamReq.send(streamParms+"&command="+CMD_NEXT); streamReq({command: CMD_NEXT});
streamPlay(); streamPlay();
} }
} }
@ -531,7 +538,7 @@ function streamZoomIn( x, y ) {
if (vid) { if (vid) {
vjsPanZoom('zoom', x, y); vjsPanZoom('zoom', x, y);
} else { } else {
streamReq.send( streamParms+"&command="+CMD_ZOOMIN+"&x="+x+"&y="+y ); streamReq({command: CMD_ZOOMIN, x: x, y: y});
} }
} }
@ -539,28 +546,28 @@ function streamZoomOut() {
if (vid) { if (vid) {
vjsPanZoom('zoomOut'); vjsPanZoom('zoomOut');
} else { } else {
streamReq.send( streamParms+"&command="+CMD_ZOOMOUT ); streamReq({command: CMD_ZOOMOUT});
} }
} }
function streamScale( scale ) { function streamScale( scale ) {
streamReq.send( streamParms+"&command="+CMD_SCALE+"&scale="+scale ); streamReq({command: CMD_SCALE, scale: scale});
} }
function streamPan( x, y ) { function streamPan( x, y ) {
if (vid) { if (vid) {
vjsPanZoom('pan', x, y); vjsPanZoom('pan', x, y);
} else { } else {
streamReq.send( streamParms+"&command="+CMD_PAN+"&x="+x+"&y="+y ); streamReq({command: CMD_PAN, x: x, y: y});
} }
} }
function streamSeek( offset ) { function streamSeek( offset ) {
streamReq.send( streamParms+"&command="+CMD_SEEK+"&offset="+offset ); streamReq({command: CMD_SEEK, offset: offset});
} }
function streamQuery() { function streamQuery() {
streamReq.send( streamParms+"&command="+CMD_QUERY ); streamReq({command: CMD_QUERY});
} }
function getEventResponse(respObj, respText) { function getEventResponse(respObj, respText) {
@ -570,9 +577,9 @@ function getEventResponse(respObj, respText) {
} }
eventData = respObj.event; eventData = respObj.event;
var eventStills = $('eventStills'); var eventStills = $j('#eventStills');
if ( eventStills && !$('eventStills').hasClass( 'hidden' ) && currEventId != eventData.Id ) { if ( eventStills && !eventStills.hasClass('hidden') && currEventId != eventData.Id ) {
resetEventStills(); resetEventStills();
} }
currEventId = eventData.Id; currEventId = eventData.Id;
@ -602,9 +609,6 @@ function getEventResponse(respObj, respText) {
unarchiveBtn.prop('disabled', !(eventData.Archived && canEdit.Events)); unarchiveBtn.prop('disabled', !(eventData.Archived && canEdit.Events));
history.replaceState(null, null, '?view=event&eid=' + eventData.Id + filterQuery + sortQuery); //if popup removed, check if this allows forward history.replaceState(null, null, '?view=event&eid=' + eventData.Id + filterQuery + sortQuery); //if popup removed, check if this allows forward
// Technically, events can be different sizes, so may need to update the size of the image, but it might be better to have it stay scaled...
//var eventImg = $('eventImage');
//eventImg.setStyles( { 'width': eventData.width, 'height': eventData.height } );
if ( vid && CurEventDefVideoPath ) { if ( vid && CurEventDefVideoPath ) {
vid.src({type: 'video/mp4', src: CurEventDefVideoPath}); //Currently mp4 is all we use vid.src({type: 'video/mp4', src: CurEventDefVideoPath}); //Currently mp4 is all we use
console.log('getEventResponse'); console.log('getEventResponse');
@ -621,12 +625,14 @@ function getEventResponse(respObj, respText) {
nearEventsQuery( eventData.Id ); nearEventsQuery( eventData.Id );
} // end function getEventResponse } // end function getEventResponse
function eventQuery( eventId ) { function eventQuery(eventId) {
var eventParms = 'view=request&request=status&entity=event&id='+eventId; var data = {};
if ( auth_hash ) { data.id = eventId;
eventParms += '&auth='+auth_hash; if ( auth_hash ) data.auth = auth_hash;
}
eventReq.send( eventParms ); $j.getJSON(thisUrl + '?view=request&request=status&entity=event', data)
.done(getEventResponse)
.fail(logAjaxFail);
} }
function getNearEventsResponse( respObj, respText ) { function getNearEventsResponse( respObj, respText ) {
@ -640,10 +646,8 @@ function getNearEventsResponse( respObj, respText ) {
PrevEventDefVideoPath = respObj.nearevents.PrevEventDefVideoPath; PrevEventDefVideoPath = respObj.nearevents.PrevEventDefVideoPath;
NextEventDefVideoPath = respObj.nearevents.NextEventDefVideoPath; NextEventDefVideoPath = respObj.nearevents.NextEventDefVideoPath;
var prevEventBtn = $('prevEventBtn'); $j('#prevEventBtn').prop('disabled', !prevEventId);
if ( prevEventBtn ) prevEventBtn.disabled = !prevEventId; $j('#nextEventBtn').prop('disabled', !nextEventId);
var nextEventBtn = $('nextEventBtn');
if ( nextEventBtn ) nextEventBtn.disabled = !nextEventId;
$j('#prevBtn').prop('disabled', prevEventId == 0 ? true : false).attr('class', prevEventId == 0 ? 'unavail' : 'inactive'); $j('#prevBtn').prop('disabled', prevEventId == 0 ? true : false).attr('class', prevEventId == 0 ? 'unavail' : 'inactive');
$j('#nextBtn').prop('disabled', nextEventId == 0 ? true : false).attr('class', nextEventId == 0 ? 'unavail' : 'inactive'); $j('#nextBtn').prop('disabled', nextEventId == 0 ? true : false).attr('class', nextEventId == 0 ? 'unavail' : 'inactive');
} }
@ -656,7 +660,7 @@ function nearEventsQuery( eventId ) {
} }
function loadEventThumb( event, frame, loadImage ) { function loadEventThumb( event, frame, loadImage ) {
var thumbImg = $('eventThumb'+frame.FrameId); var thumbImg = $j('#eventThumb'+frame.FrameId);
if ( !thumbImg ) { if ( !thumbImg ) {
console.error('No holder found for frame '+frame.FrameId); console.error('No holder found for frame '+frame.FrameId);
return; return;
@ -664,12 +668,12 @@ function loadEventThumb( event, frame, loadImage ) {
var img = new Asset.image( imagePrefix+frame.EventId+"&fid="+frame.FrameId, var img = new Asset.image( imagePrefix+frame.EventId+"&fid="+frame.FrameId,
{ {
'onload': ( function( loadImage ) { 'onload': ( function( loadImage ) {
thumbImg.setProperty( 'src', img.getProperty( 'src' ) ); thumbImg.prop('src', img.prop('src'));
thumbImg.removeClass( 'placeholder' ); thumbImg.prop('class', frame.Type=='Alarm'?'alarm':'normal');
thumbImg.setProperty( 'class', frame.Type=='Alarm'?'alarm':'normal' ); thumbImg.prop('title', frame.FrameId+' / '+((frame.Type=='Alarm')?frame.Score:0));
thumbImg.setProperty( 'title', frame.FrameId+' / '+((frame.Type=='Alarm')?frame.Score:0) ); thumbImg.removeClass('placeholder');
thumbImg.removeEvents( 'click' ); thumbImg.off('click');
thumbImg.addEvent( 'click', function() { thumbImg.click(function() {
locateImage( frame.FrameId, true ); locateImage( frame.FrameId, true );
} ); } );
if ( loadImage ) { if ( loadImage ) {
@ -682,72 +686,73 @@ function loadEventThumb( event, frame, loadImage ) {
function loadEventImage(event, frame) { function loadEventImage(event, frame) {
console.debug('Loading '+event.Id+'/'+frame.FrameId); console.debug('Loading '+event.Id+'/'+frame.FrameId);
var eventImg = $('eventImage'); var eventImg = $j('#eventImage');
var thumbImg = $('eventThumb'+frame.FrameId); var thumbImg = $j('#eventThumb'+frame.FrameId);
if ( eventImg.getProperty('src') != thumbImg.getProperty('src') ) { if ( eventImg.prop('src') != thumbImg.prop('src') ) {
var eventImagePanel = $('eventImagePanel'); var eventImagePanel = $j('#eventImagePanel');
if ( eventImagePanel.getStyle('display') != 'none' ) { if ( eventImagePanel.css('display') != 'none' ) {
var lastThumbImg = $('eventThumb'+eventImg.getProperty('alt')); var lastThumbImg = $j('#eventThumb' + eventImg.prop('alt'));
lastThumbImg.removeClass('selected'); lastThumbImg.removeClass('selected');
lastThumbImg.setOpacity(1.0); lastThumbImg.css('opacity', '1.0');
} }
$('eventImageBar').setStyle('width', event.Width); $j('#eventImageBar').css('width', event.Width);
if ( frame.Type == 'Alarm' ) { if ( frame.Type == 'Alarm' ) {
$('eventImageStats').removeClass('hidden'); $j('#eventImageStats').removeClass('hidden');
} else { } else {
$('eventImageStats').addClass('hidden'); $j('#eventImageStats').addClass('hidden');
} }
thumbImg.addClass('selected'); thumbImg.addClass('selected');
thumbImg.setOpacity(0.5); thumbImg.css('opacity', '0.5');
if ( eventImagePanel.getStyle('display') == 'none' ) { if ( eventImagePanel.css('display') == 'none' ) {
eventImagePanel.setOpacity(0); eventImagePanel.css('opacity', '0');
eventImagePanel.setStyle('display', 'inline-block'); eventImagePanel.css('display', 'inline-block');
new Fx.Tween( eventImagePanel, {duration: 500, transition: Fx.Transitions.Sine} ).start( 'opacity', 0, 1 ); new Fx.Tween( eventImagePanel, {duration: 500, transition: Fx.Transitions.Sine} ).start( 'opacity', 0, 1 );
} }
eventImg.setProperties( { eventImg.prop( {
'class': frame.Type=='Alarm'?'alarm':'normal', 'class': frame.Type=='Alarm'?'alarm':'normal',
'src': thumbImg.getProperty( 'src' ), 'src': thumbImg.prop('src'),
'title': thumbImg.getProperty( 'title' ), 'title': thumbImg.prop('title'),
'alt': thumbImg.getProperty( 'alt' ), 'alt': thumbImg.prop('alt'),
'height': $j('#eventThumbs').height() - $j('#eventImageBar').outerHeight(true)-10 'height': $j('#eventThumbs').height() - $j('#eventImageBar').outerHeight(true)-10
} ); } );
$('eventImageNo').set('text', frame.FrameId); $j('#eventImageNo').text(frame.FrameId);
$('prevImageBtn').disabled = (frame.FrameId==1); $j('#prevImageBtn').prop('disabled', !frame.FrameId == 1);
$('nextImageBtn').disabled = (frame.FrameId==event.Frames); $j('#nextImageBtn').prop('disabled', !frame.FrameId == event.Frames);
} }
} }
function hideEventImageComplete() { function hideEventImageComplete() {
var thumbImg = $('eventThumb'+$('eventImage').getProperty('alt')); var thumbImg = $j('#eventThumb'+$j('#eventImage').prop('alt'));
if ( thumbImg ) { if ( thumbImg ) {
thumbImg.removeClass('selected'); thumbImg.removeClass('selected');
thumbImg.setOpacity(1.0); thumbImg.css('opacity', '1.0');
} else { } else {
console.log('Unable to find eventThumb at eventThumb'+$('eventImage').getProperty('alt')); console.log('Unable to find eventThumb at eventThumb'+$j('#eventImage').prop('alt'));
} }
$('prevImageBtn').disabled = true; $j('#prevImageBtn').prop('disabled', true);
$('nextImageBtn').disabled = true; $j('#nextImageBtn').prop('disabled', true);
$('eventImagePanel').setStyle('display', 'none'); $j('#eventImagePanel').css('display', 'none');
$('eventImageStats').addClass('hidden'); $j('#eventImageStats').addClass('hidden');
} }
function hideEventImage() { function hideEventImage() {
if ( $('eventImagePanel').getStyle('display') != 'none' ) { if ( $j('#eventImagePanel').css('display') != 'none' ) {
new Fx.Tween( $('eventImagePanel'), {duration: 500, transition: Fx.Transitions.Sine, onComplete: hideEventImageComplete} ).start('opacity', 1, 0); new Fx.Tween( $j('#eventImagePanel'), {duration: 500, transition: Fx.Transitions.Sine, onComplete: hideEventImageComplete} ).start('opacity', 1, 0);
} }
} }
function resetEventStills() { function resetEventStills() {
hideEventImage(); hideEventImage();
$('eventThumbs').empty(); $j('#eventThumbs').empty();
if ( true || !slider ) { if ( true || !slider ) {
slider = new Slider( $('thumbsSlider'), $('thumbsKnob'), { slider = new Slider( '#thumbsSlider', '#thumbsKnob', {
/*steps: eventData.Frames,*/ /*steps: eventData.Frames,*/
value: 0,
onChange: function( step ) { onChange: function( step ) {
if ( !step ) { if ( !step ) {
step = 0; step = 0;
@ -761,7 +766,7 @@ function resetEventStills() {
checkFrames( eventData.Id, fid, ($j('#eventImagePanel').css('display')=='none'?'':'true')); checkFrames( eventData.Id, fid, ($j('#eventImagePanel').css('display')=='none'?'':'true'));
scroll.toElement( 'eventThumb'+fid ); scroll.toElement( 'eventThumb'+fid );
} }
} ).set( 0 ); } );
} }
} }
@ -787,8 +792,13 @@ function getFrameResponse(respObj, respText) {
} }
function frameQuery( eventId, frameId, loadImage ) { function frameQuery( eventId, frameId, loadImage ) {
var parms = "view=request&request=status&entity=frameimage&id[0]="+eventId+"&id[1]="+frameId+"&loopback="+loadImage; var data = {};
frameReq.send(parms); data.loopback = loadImage;
data.id = {eventId, frameId};
$j.getJSON(thisUrl + '?view=request&request=status&entity=frameimage', data)
.done(getFrameResponse)
.fail(logAjaxFail);
} }
function checkFrames( eventId, frameId, loadImage ) { function checkFrames( eventId, frameId, loadImage ) {
@ -813,23 +823,30 @@ function checkFrames( eventId, frameId, loadImage ) {
} }
for ( var fid = loFid; fid <= hiFid; fid++ ) { for ( var fid = loFid; fid <= hiFid; fid++ ) {
if ( !$('eventThumb'+fid) ) { if ( !$j('#eventThumb'+fid) ) {
var img = new Element('img', {'id': 'eventThumb'+fid, 'src': 'graphics/transparent.png', 'alt': fid, 'class': 'placeholder'}); var img = $j('<img>');
img.addEvent('click', function() { img.attr({
'id': 'eventThumb'+fid,
'src': 'graphics/transparent.png',
'alt': fid,
'class': 'placeholder'
});
img.click(function() {
eventData['frames'][fid] = null; eventData['frames'][fid] = null;
checkFrames(eventId, fid); checkFrames(eventId, fid);
}); });
frameQuery(eventId, fid, loadImage && (fid == frameId)); frameQuery(eventId, fid, loadImage && (fid == frameId));
var imgs = $('eventThumbs').getElements('img'); var imgs = $j('#eventThumbs img');
var injected = false; var injected = false;
if ( fid < imgs.length ) { if ( fid < imgs.length ) {
img.inject(imgs[fid-1], 'before'); imgs.before(img);
injected = true; injected = true;
} else { } else {
injected = imgs.some( injected = imgs.toArray().some(
function( thumbImg, index ) { function( thumbImg, index ) {
if ( parseInt(img.getProperty('alt')) < parseInt(thumbImg.getProperty('alt')) ) { if ( parseInt(img.prop('alt')) < parseInt(thumbImg.prop('alt')) ) {
img.inject(thumbImg, 'before'); thumbImg.before(img);
return true; return true;
} }
return false; return false;
@ -837,10 +854,10 @@ function checkFrames( eventId, frameId, loadImage ) {
); );
} }
if ( !injected ) { if ( !injected ) {
img.inject($('eventThumbs')); $j('#eventThumbs').append(img);
} }
var scale = parseInt(img.getStyle('height')); var scale = parseInt(img.css('height'));
img.setStyles( { img.css( {
'width': parseInt((eventData.Width*scale)/100), 'width': parseInt((eventData.Width*scale)/100),
'height': parseInt((eventData.Height*scale)/100) 'height': parseInt((eventData.Height*scale)/100)
} ); } );
@ -850,8 +867,8 @@ function checkFrames( eventId, frameId, loadImage ) {
} }
} }
} }
$('prevThumbsBtn').disabled = (frameId==1); $j('#prevThumbsBtn').prop('disabled', frameId == 1);
$('nextThumbsBtn').disabled = (frameId==eventData.Frames); $j('#nextThumbsBtn').prop('disabled', frameId == eventData.Frames);
} }
function locateImage( frameId, loadImage ) { function locateImage( frameId, loadImage ) {
@ -876,13 +893,13 @@ function nextImage() {
function prevThumbs() { function prevThumbs() {
if ( currFrameId > 1 ) { if ( currFrameId > 1 ) {
locateImage( parseInt(currFrameId)>10?(parseInt(currFrameId)-10):1, $('eventImagePanel').getStyle('display')!="none" ); locateImage( parseInt(currFrameId)>10?(parseInt(currFrameId)-10):1, $j('#eventImagePanel').css('display')!="none" );
} }
} }
function nextThumbs() { function nextThumbs() {
if ( currFrameId < eventData.Frames ) { if ( currFrameId < eventData.Frames ) {
locateImage( parseInt(currFrameId)<(eventData.Frames-10)?(parseInt(currFrameId)+10):eventData.Frames, $('eventImagePanel').getStyle('display')!="none" ); locateImage( parseInt(currFrameId)<(eventData.Frames-10)?(parseInt(currFrameId)+10):eventData.Frames, $j('#eventImagePanel').css('display')!="none" );
} }
} }
@ -911,14 +928,15 @@ function getActResponse( respObj, respText ) {
} }
function actQuery(action, parms) { function actQuery(action, parms) {
var actParms = "view=request&request=event&id="+eventData.Id+"&action="+action; var data = {};
if ( auth_hash ) { if ( parms ) data = parms;
actParms += '&auth='+auth_hash; if ( auth_hash ) data.auth = auth_hash;
} data.id = eventData.Id;
if ( parms != null ) { data.action = action;
actParms += "&"+Object.toQueryString(parms);
} $j.getJSON(thisUrl + '?view=request&request=event', data)
actReq.send(actParms); .done(getActResponse)
.fail(logAjaxFail);
} }
function renameEvent() { function renameEvent() {
@ -937,19 +955,19 @@ function showEventFrames() {
} }
function showStream() { function showStream() {
$('eventStills').addClass('hidden'); $j('#eventStills').addClass('hidden');
$('eventVideo').removeClass('hidden'); $j('#eventVideo').removeClass('hidden');
$('stillsEvent').removeClass('hidden'); $j('#stillsEvent').removeClass('hidden');
$('streamEvent').addClass('hidden'); $j('#streamEvent').addClass('hidden');
streamMode = 'video'; streamMode = 'video';
if (scale == 'auto') changeScale(); if (scale == 'auto') changeScale();
} }
function showStills() { function showStills() {
$('eventStills').removeClass('hidden'); $j('#eventStills').removeClass('hidden');
$('eventVideo').addClass('hidden'); $j('#eventVideo').addClass('hidden');
if (vid && ( vid.paused != true ) ) { if (vid && ( vid.paused != true ) ) {
// Pause the video // Pause the video
@ -960,8 +978,8 @@ function showStills() {
//playButton.innerHTML = "Play"; //playButton.innerHTML = "Play";
} }
$('stillsEvent').addClass('hidden'); $j('#stillsEvent').addClass('hidden');
$('streamEvent').removeClass('hidden'); $j('#streamEvent').removeClass('hidden');
streamMode = 'stills'; streamMode = 'stills';
@ -980,7 +998,7 @@ function showStills() {
} }
function showFrameStats() { function showFrameStats() {
var fid = $('eventImageNo').get('text'); var fid = $j('#eventImageNo').text();
window.location.assign('?view=stats&eid='+eventData.Id+'&fid='+fid); window.location.assign('?view=stats&eid='+eventData.Id+'&fid='+fid);
} }
@ -1014,13 +1032,14 @@ function progressBarNav() {
function handleClick( event ) { function handleClick( event ) {
var target = event.target; var target = event.target;
var rect = target.getBoundingClientRect();
if ( vid ) { if ( vid ) {
if (target.id != 'videoobj') return; // ignore clicks on control bar if (target.id != 'videoobj') return; // ignore clicks on control bar
var x = event.offsetX; var x = event.offsetX;
var y = event.offsetY; var y = event.offsetY;
} else { } else {
var x = event.page.x - $(target).getLeft(); var x = event.page.x - rect.left;
var y = event.page.y - $(target).getTop(); var y = event.page.y - rect.top;
} }
if ( event.shift || event.shiftKey ) { // handle both jquery and mootools if ( event.shift || event.shiftKey ) { // handle both jquery and mootools
@ -1069,8 +1088,26 @@ function getStat() {
table.empty().append('<tbody>'); table.empty().append('<tbody>');
$j.each( eventDataStrings, function( key ) { $j.each( eventDataStrings, function( key ) {
var th = $j('<th>').addClass('text-right').text(eventDataStrings[key]); var th = $j('<th>').addClass('text-right').text(eventDataStrings[key]);
var tdString = ( eventData[key].length ) ? eventData[key] : 'n/a'; var tdString;
var td = $j('<td>').text(tdString);
switch (eventData[key].length ? key : 'n/a') {
case 'Frames':
tdString = '<a href="?view=frames&amp;eid=' + eventData.Id + '">' + eventData[key] + '</a>';
break;
case 'AlarmFrames':
tdString = '<a href="?view=frames&amp;eid=' + eventData.Id + '">' + eventData[key] + '</a>';
break;
case 'MaxScore':
tdString = '<a href="?view=frame&amp;eid=' + eventData.Id + '&amp;fid=0">' + eventData[key] + '</a>';
break;
case 'n/a':
tdString = 'n/a';
break;
default:
tdString = eventData[key];
}
var td = $j('<td>').html(tdString);
var row = $j('<tr>').append(th, td); var row = $j('<tr>').append(th, td);
$j('#eventStatsTable tbody').append(row); $j('#eventStatsTable tbody').append(row);
@ -1114,15 +1151,14 @@ function initPage() {
progressBarNav(); progressBarNav();
streamCmdTimer = streamQuery.delay(250); streamCmdTimer = streamQuery.delay(250);
if ( canStreamNative ) { if ( canStreamNative ) {
var imageFeed = $('imageFeed'); if ( !$j('#imageFeed') ) {
if ( !imageFeed ) {
console.log('No element with id tag imageFeed found.'); console.log('No element with id tag imageFeed found.');
} else { } else {
var streamImg = imageFeed.getElement('img'); var streamImg = $j('#imageFeed img');
if ( !streamImg ) { if ( !streamImg ) {
streamImg = imageFeed.getElement('object'); streamImg = $j('#imageFeed object');
} }
$(streamImg).addEvent('click', function(event) { $j(streamImg).click(function(event) {
handleClick(event); handleClick(event);
}); });
} }
@ -1253,6 +1289,12 @@ function initPage() {
} }
}); });
// Manage the FRAMES Button
document.getElementById("framesBtn").addEventListener("click", function onFramesClick(evt) {
evt.preventDefault();
window.location.assign('?view=frames&eid='+eventData.Id);
});
// Manage the DELETE button // Manage the DELETE button
document.getElementById("deleteBtn").addEventListener("click", function onDeleteClick(evt) { document.getElementById("deleteBtn").addEventListener("click", function onDeleteClick(evt) {
if ( ! canEdit.Events ) { if ( ! canEdit.Events ) {

View File

@ -126,19 +126,24 @@ function previewEvent(slot) {
} }
function loadEventImage( imagePath, eid, fid ) { function loadEventImage( imagePath, eid, fid ) {
var eventData = $j('#eventData');
var imageSrc = $j('#imageSrc'); var imageSrc = $j('#imageSrc');
imageSrc.show(); imageSrc.show();
imageSrc.attr('src', imagePath); imageSrc.attr('src', imagePath);
imageSrc.attr('data-event-id', eid); imageSrc.attr('data-event-id', eid);
imageSrc.attr('data-frame-id', fid); imageSrc.attr('data-frame-id', fid);
imageSrc.click(window['showEvent'].bind(imageSrc, imageSrc)); imageSrc.off('click');
imageSrc.click(function() {
showEvent(this);
});
var eventData = $j('#eventData'); eventData.attr('data-event-id', eid);
eventData.attr('data-frame-id', fid);
eventData.off('click'); eventData.off('click');
eventData.click(showEvent.pass()); eventData.click(function() {
showEvent(this);
divDataOnClick(); });
} }
function tlZoomBounds(event) { function tlZoomBounds(event) {

View File

@ -974,6 +974,8 @@ echo htmlSelect('newMonitor[OutputCodec]', $videowriter_codecs, $monitor->Output
$videowriter_encoders = array( $videowriter_encoders = array(
'' => translate('Auto'), '' => translate('Auto'),
'h264_omx' => 'h264_omx', 'h264_omx' => 'h264_omx',
'libx264' => 'libx264',
'h264_vaapi' => 'h264_vaapi',
'h264' => 'h264', 'h264' => 'h264',
'mjpeg' => 'mjpeg', 'mjpeg' => 'mjpeg',
'mpeg1' => 'mpeg1', 'mpeg1' => 'mpeg1',