Merge branch 'storageareas' of github.com:connortechnology/ZoneMinder into storageareas

pull/2112/head
Isaac Connor 2018-05-10 17:47:12 -04:00
commit 8b8bcbd1e2
17 changed files with 493 additions and 180 deletions

View File

@ -439,7 +439,8 @@ sub start {
sigprocmask(SIG_BLOCK, $blockset, $sigset) or Fatal("Can't block SIGCHLD: $!");
Debug("forking");
if ( my $cpid = fork() ) {
#logReinit();
# This logReinit is required. Not sure why.
logReinit();
$process->{pid} = $cpid;
$process->{started} = time();
@ -503,6 +504,10 @@ sub start {
sub send_stop {
my ( $final, $process ) = @_;
my $sigset = POSIX::SigSet->new;
my $blockset = POSIX::SigSet->new(SIGCHLD);
sigprocmask(SIG_BLOCK, $blockset, $sigset) or die "dying at block...\n";
my $command = $process->{command};
if ( $process->{pending} ) {
@ -511,12 +516,19 @@ sub send_stop {
.strftime('%y/%m/%d %H:%M:%S', localtime())
."\n"
);
sigprocmask(SIG_UNBLOCK, $blockset) or die "dying at unblock...\n";
return();
}
my $pid = $process->{pid};
if ( !$pid ) {
dPrint(ZoneMinder::Logger::ERROR, "No process with command of '$command' is running\n");
sigprocmask(SIG_UNBLOCK, $blockset) or die "dying at unblock...\n";
return();
}
if ( !$pid_hash{$pid} ) {
dPrint(ZoneMinder::Logger::ERROR, "No process with command of '$command' pid $pid is running\n");
sigprocmask(SIG_UNBLOCK, $blockset) or die "dying at unblock...\n";
return();
}
@ -525,11 +537,12 @@ sub send_stop {
."\n"
);
$process->{keepalive} = !$final;
$process->{term_sent_at} = time;
$process->{term_sent_at} = time if ! $process->{term_sent_at};
$process->{pending} = 0;
$terminating_processes{$command} = $process;
kill('TERM', $pid);
sigprocmask(SIG_UNBLOCK, $blockset) or die "dying at unblock...\n";
return $pid;
} # end sub send_stop
@ -540,6 +553,16 @@ sub check_for_processes_to_kill {
sigprocmask(SIG_BLOCK, $blockset, $sigset) or die "dying at block...\n";
foreach my $command ( keys %terminating_processes ) {
my $process = $cmd_hash{$command};
if ( ! $process ) {
Debug("No process found for $command");
delete $terminating_processes{$command};
next;
}
if ( ! $$process{pid} ) {
Warning("Have no pid for $command.");
delete $terminating_processes{$command};
next;
}
my $now = time;
Debug("Have process $command at pid $$process{pid} $now - $$process{term_sent_at} = " . ( $now - $$process{term_sent_at} ));
if ( $$process{term_sent_at} and ( $now - $$process{term_sent_at} > KILL_DELAY ) ) {
@ -685,7 +708,7 @@ sub reaper {
} # end while waitpid
$SIG{CHLD} = \&reaper;
$! = $saved_status;
Debug("Leaving reaper");
Debug("Leaving reaper");
}
sub restartPending {
@ -697,7 +720,7 @@ sub restartPending {
start($process->{daemon}, @{$process->{args}});
}
}
dPrint(ZoneMinder::Logger::INFO, "done restartPending");
Debug("done restartPending");
}
sub shutdownAll {
@ -706,29 +729,17 @@ sub shutdownAll {
next if ! $pid_hash{$pid};
send_stop(1, $pid_hash{$pid});
}
my $count = KILL_DELAY;
while ( (keys %terminating_processes) and $count) {
while ( keys %terminating_processes ) {
check_for_processes_to_kill();
if ( %terminating_processes ) {
Debug("Still " . %terminating_processes . ' to die. count is: ' . $count . ' sleeping');
Debug("Still " . %terminating_processes . ' to die. sleeping');
sleep(1);
$count --;
}
}
foreach my $command ( keys %terminating_processes ) {
my $process = $cmd_hash{$command};
dPrint(ZoneMinder::Logger::WARNING, "'$$process{command}' has not stopped at "
.strftime('%y/%m/%d %H:%M:%S', localtime())
.' after ' . KILL_DELAY . ' seconds.'
." Sending KILL to pid $$process{pid}\n"
);
kill('KILL', $$process{pid});
dPrint(ZoneMinder::Logger::INFO, "Server shutdown at "
.strftime('%y/%m/%d %H:%M:%S', localtime())
."\n"
);
}
dPrint(ZoneMinder::Logger::INFO, 'Server shutdown at '
.strftime('%y/%m/%d %H:%M:%S', localtime())
."\n"
);
unlink(main::SOCK_FILE) or Error("Unable to unlink " . main::SOCK_FILE .". Error message was: $!") if ( -e main::SOCK_FILE );
unlink(ZM_PID) or Error("Unable to unlink " . ZM_PID .". Error message was: $!") if ( -e ZM_PID );
close(CLIENT);

View File

@ -1,51 +1,66 @@
//
// ZoneMinder Camera Class Implementation, $Date$, $Revision$
// Copyright (C) 2001-2008 Philip Coombes
//
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
//
#include "zm.h"
#include "zm_camera.h"
Camera::Camera( unsigned int p_monitor_id, SourceType p_type, unsigned int p_width, unsigned int p_height, int p_colours, int p_subpixelorder, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ) :
monitor_id( p_monitor_id ),
type( p_type ),
width( p_width),
height( p_height ),
colours( p_colours ),
subpixelorder( p_subpixelorder ),
brightness( p_brightness ),
hue( p_hue ),
colour( p_colour ),
contrast( p_contrast ),
capture( p_capture ),
record_audio( p_record_audio )
Camera::Camera(
unsigned int p_monitor_id,
SourceType p_type,
unsigned int p_width,
unsigned int p_height,
int p_colours,
int p_subpixelorder,
int p_brightness,
int p_contrast,
int p_hue,
int p_colour,
bool p_capture,
bool p_record_audio
) :
monitor_id(p_monitor_id),
type(p_type),
width(p_width),
height(p_height),
colours(p_colours),
subpixelorder(p_subpixelorder),
brightness(p_brightness),
hue(p_hue),
colour(p_colour),
contrast(p_contrast),
capture(p_capture),
record_audio(p_record_audio),
bytes(0)
{
pixels = width * height;
imagesize = pixels * colours;
Debug(2,"New camera id: %d width: %d height: %d colours: %d subpixelorder: %d capture: %d",monitor_id,width,height,colours,subpixelorder,capture);
Debug(2,"New camera id: %d width: %d height: %d colours: %d subpixelorder: %d capture: %d",
monitor_id,width,height,colours,subpixelorder,capture);
/* Because many loops are unrolled and work on 16 colours/time or 4 pixels/time, we have to meet requirements */
if((colours == ZM_COLOUR_GRAY8 || colours == ZM_COLOUR_RGB32) && (imagesize % 64) != 0) {
if ( (colours == ZM_COLOUR_GRAY8 || colours == ZM_COLOUR_RGB32) && (imagesize % 64) != 0 ) {
Fatal("Image size is not multiples of 64");
} else if(colours == ZM_COLOUR_RGB24 && ((imagesize % 64) != 0 || (imagesize % 12) != 0)) {
} else if ( colours == ZM_COLOUR_RGB24 && ((imagesize % 64) != 0 || (imagesize % 12) != 0) ) {
Fatal("Image size is not multiples of 12 and 64");
}
monitor = NULL;
monitor = NULL;
}
Camera::~Camera() {
@ -53,11 +68,11 @@ Camera::~Camera() {
Monitor *Camera::getMonitor() {
if ( ! monitor )
monitor = Monitor::Load( monitor_id, false, Monitor::QUERY );
monitor = Monitor::Load(monitor_id, false, Monitor::QUERY);
return monitor;
}
}
void Camera::setMonitor( Monitor *p_monitor ) {
void Camera::setMonitor(Monitor *p_monitor) {
monitor = p_monitor;
monitor_id = monitor->Id();
}

View File

@ -341,11 +341,13 @@ int FfmpegCamera::OpenFfmpeg() {
Debug(1, "Calling avformat_open_input for %s", mPath.c_str());
//mFormatContext = avformat_alloc_context( );
mFormatContext = avformat_alloc_context( );
// Speed up find_stream_info
//FIXME can speed up initial analysis but need sensible parameters...
//mFormatContext->probesize = 32;
//mFormatContext->max_analyze_duration = 32;
mFormatContext->interrupt_callback.callback = FfmpegInterruptCallback;
mFormatContext->interrupt_callback.opaque = this;
if ( avformat_open_input(&mFormatContext, mPath.c_str(), NULL, &opts) != 0 )
#endif
@ -691,7 +693,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event
int frameComplete = false;
while ( ! frameComplete ) {
av_init_packet( &packet );
av_init_packet(&packet);
ret = av_read_frame(mFormatContext, &packet);
if ( ret < 0 ) {
@ -739,11 +741,11 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event
videoStore = NULL;
have_video_keyframe = false;
monitor->SetVideoWriterEventId( 0 );
monitor->SetVideoWriterEventId(0);
} // end if videoStore
} // end if end of recording
if ( last_event_id and ! videoStore ) {
if ( last_event_id and !videoStore ) {
//Instantiate the video storage module
if ( record_audio ) {
@ -820,7 +822,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event
delete videoStore;
videoStore = NULL;
have_video_keyframe = false;
monitor->SetVideoWriterEventId( 0 );
monitor->SetVideoWriterEventId(0);
}
// Buffer video packets, since we are not recording.
@ -828,18 +830,18 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event
if ( packet.stream_index == mVideoStreamId ) {
if ( keyframe ) {
Debug(3, "Clearing queue");
packetqueue.clearQueue( monitor->GetPreEventCount(), mVideoStreamId );
packetqueue.queuePacket( &packet );
packetqueue.clearQueue(monitor->GetPreEventCount(), mVideoStreamId);
packetqueue.queuePacket(&packet);
} else if ( packetqueue.size() ) {
// it's a keyframe or we already have something in the queue
packetqueue.queuePacket( &packet );
packetqueue.queuePacket(&packet);
}
} else if ( packet.stream_index == mAudioStreamId ) {
// The following lines should ensure that the queue always begins with a video keyframe
//Debug(2, "Have audio packet, reocrd_audio is (%d) and packetqueue.size is (%d)", record_audio, packetqueue.size() );
if ( record_audio && packetqueue.size() ) {
// if it's audio, and we are doing audio, and there is already something in the queue
packetqueue.queuePacket( &packet );
packetqueue.queuePacket(&packet);
}
}
} // end if recording or not
@ -851,25 +853,25 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event
if ( videoStore ) {
//Write the packet to our video store
int ret = videoStore->writeVideoFramePacket( &packet );
int ret = videoStore->writeVideoFramePacket(&packet);
if ( ret < 0 ) { //Less than zero and we skipped a frame
zm_av_packet_unref( &packet );
zm_av_packet_unref(&packet);
return 0;
}
have_video_keyframe = true;
}
} // end if keyframe or have_video_keyframe
Debug(4, "about to decode video" );
Debug(4, "about to decode video");
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
ret = avcodec_send_packet( mVideoCodecContext, &packet );
if ( ret < 0 ) {
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
Error( "Unable to send packet at frame %d: %s, continuing", frameCount, errbuf );
zm_av_packet_unref( &packet );
continue;
}
ret = avcodec_send_packet(mVideoCodecContext, &packet);
if ( ret < 0 ) {
av_strerror(ret, errbuf, AV_ERROR_MAX_STRING_SIZE);
Error("Unable to send packet at frame %d: %s, continuing", frameCount, errbuf);
zm_av_packet_unref(&packet);
continue;
}
#if HAVE_AVUTIL_HWCONTEXT_H
if ( hwaccel ) {
ret = avcodec_receive_frame( mVideoCodecContext, hwFrame );
@ -888,11 +890,11 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event
}
} else {
#endif
ret = avcodec_receive_frame( mVideoCodecContext, mRawFrame );
ret = avcodec_receive_frame(mVideoCodecContext, mRawFrame);
if ( ret < 0 ) {
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
Warning( "Unable to receive frame %d: %s, continuing", frameCount, errbuf );
zm_av_packet_unref( &packet );
av_strerror(ret, errbuf, AV_ERROR_MAX_STRING_SIZE);
Warning("Unable to receive frame %d: %s, continuing", frameCount, errbuf);
zm_av_packet_unref(&packet);
continue;
}
@ -902,10 +904,10 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event
frameComplete = 1;
# else
ret = zm_avcodec_decode_video( mVideoCodecContext, mRawFrame, &frameComplete, &packet );
ret = zm_avcodec_decode_video(mVideoCodecContext, mRawFrame, &frameComplete, &packet);
if ( ret < 0 ) {
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
Error( "Unable to decode frame at frame %d: %s, continuing", frameCount, errbuf );
av_strerror(ret, errbuf, AV_ERROR_MAX_STRING_SIZE);
Error("Unable to decode frame at frame %d: %s, continuing", frameCount, errbuf);
zm_av_packet_unref( &packet );
continue;
}
@ -921,15 +923,13 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event
if ( directbuffer == NULL ) {
Error("Failed requesting writeable buffer for the captured image.");
zm_av_packet_unref( &packet );
return (-1);
return -1;
}
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
av_image_fill_arrays(mFrame->data, mFrame->linesize, directbuffer, imagePixFormat, width, height, 1);
#else
avpicture_fill( (AVPicture *)mFrame, directbuffer, imagePixFormat, width, height);
#endif
if (sws_scale(mConvertContext, mRawFrame->data, mRawFrame->linesize,
0, mVideoCodecContext->height, mFrame->data, mFrame->linesize) < 0) {
Error("Unable to convert raw format %u to target format %u at frame %d",
@ -980,6 +980,10 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event
return frameCount;
} // end FfmpegCamera::CaptureAndRecord
int FfmpegCamera::FfmpegInterruptCallback(void *ctx) {
//FfmpegCamera* camera = reinterpret_cast<FfmpegCamera*>(ctx);
return zm_terminate;
}
#endif // HAVE_LIBAVFORMAT

View File

@ -99,11 +99,12 @@ class FfmpegCamera : public Camera {
void Initialise();
void Terminate();
static int FfmpegInterruptCallback(void*ctx);
int PrimeCapture();
int PreCapture();
int Capture( Image &image );
int CaptureAndRecord( Image &image, timeval recording, char* event_directory );
int PostCapture();
};
#endif // ZM_FFMPEG_CAMERA_H

View File

@ -18,6 +18,7 @@
*/
#include "zm.h"
#include "zm_signal.h"
#include "zm_libvlc_camera.h"
#if HAVE_LIBVLC
@ -39,7 +40,7 @@ void LibvlcUnlockBuffer(void* opaque, void* picture, void *const *planes) {
LibvlcPrivateData* data = reinterpret_cast<LibvlcPrivateData*>(opaque);
bool newFrame = false;
for( uint32_t i = 0; i < data->bufferSize; i++ ) {
for( unsigned int i=0; i < data->bufferSize; i++ ) {
if ( data->buffer[i] != data->prevBuffer[i] ) {
newFrame = true;
break;
@ -56,11 +57,38 @@ void LibvlcUnlockBuffer(void* opaque, void* picture, void *const *planes) {
}
}
LibvlcCamera::LibvlcCamera( int p_id, const std::string &p_path, const std::string &p_method, const std::string &p_options, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ) :
Camera( p_id, LIBVLC_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio ),
mPath( p_path ),
mMethod( p_method ),
mOptions( p_options )
LibvlcCamera::LibvlcCamera(
int p_id,
const std::string &p_path,
const std::string &p_method,
const std::string &p_options,
int p_width,
int p_height,
int p_colours,
int p_brightness,
int p_contrast,
int p_hue,
int p_colour,
bool p_capture,
bool p_record_audio
) :
Camera(
p_id,
LIBVLC_SRC,
p_width,
p_height,
p_colours,
ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours),
p_brightness,
p_contrast,
p_hue,
p_colour,
p_capture,
p_record_audio
),
mPath(p_path),
mMethod(p_method),
mOptions(p_options)
{
mLibvlcInstance = NULL;
mLibvlcMedia = NULL;
@ -70,15 +98,15 @@ LibvlcCamera::LibvlcCamera( int p_id, const std::string &p_path, const std::stri
mOptArgV = NULL;
/* Has to be located inside the constructor so other components such as zma will receive correct colours and subpixel order */
if(colours == ZM_COLOUR_RGB32) {
if ( colours == ZM_COLOUR_RGB32 ) {
subpixelorder = ZM_SUBPIX_ORDER_BGRA;
mTargetChroma = "RV32";
mBpp = 4;
} else if(colours == ZM_COLOUR_RGB24) {
} else if ( colours == ZM_COLOUR_RGB24 ) {
subpixelorder = ZM_SUBPIX_ORDER_BGR;
mTargetChroma = "RV24";
mBpp = 3;
} else if(colours == ZM_COLOUR_GRAY8) {
} else if ( colours == ZM_COLOUR_GRAY8 ) {
subpixelorder = ZM_SUBPIX_ORDER_NONE;
mTargetChroma = "GREY";
mBpp = 1;
@ -118,11 +146,13 @@ void LibvlcCamera::Initialise() {
void LibvlcCamera::Terminate() {
libvlc_media_player_stop(mLibvlcMediaPlayer);
if(mLibvlcData.buffer != NULL) {
if ( mLibvlcData.buffer ) {
zm_freealigned(mLibvlcData.buffer);
mLibvlcData.buffer = NULL;
}
if(mLibvlcData.prevBuffer != NULL) {
if ( mLibvlcData.prevBuffer ) {
zm_freealigned(mLibvlcData.prevBuffer);
mLibvlcData.prevBuffer = NULL;
}
}
@ -139,6 +169,8 @@ int LibvlcCamera::PrimeCapture() {
else if ( Method() == "rtpRtspHttp" )
opVect.push_back("--rtsp-http");
opVect.push_back("--no-audio");
if ( opVect.size() > 0 ) {
mOptArgV = new char*[opVect.size()];
Debug(2, "Number of Options: %d",opVect.size());
@ -149,17 +181,23 @@ int LibvlcCamera::PrimeCapture() {
}
}
mLibvlcInstance = libvlc_new (opVect.size(), (const char* const*)mOptArgV);
if ( mLibvlcInstance == NULL )
Fatal("Unable to create libvlc instance due to: %s", libvlc_errmsg());
mLibvlcInstance = libvlc_new(opVect.size(), (const char* const*)mOptArgV);
if ( mLibvlcInstance == NULL ) {
Error("Unable to create libvlc instance due to: %s", libvlc_errmsg());
return -1;
}
mLibvlcMedia = libvlc_media_new_location(mLibvlcInstance, mPath.c_str());
if(mLibvlcMedia == NULL)
Fatal("Unable to open input %s due to: %s", mPath.c_str(), libvlc_errmsg());
if ( mLibvlcMedia == NULL ) {
Error("Unable to open input %s due to: %s", mPath.c_str(), libvlc_errmsg());
return -1;
}
mLibvlcMediaPlayer = libvlc_media_player_new_from_media(mLibvlcMedia);
if(mLibvlcMediaPlayer == NULL)
Fatal("Unable to create player for %s due to: %s", mPath.c_str(), libvlc_errmsg());
if ( mLibvlcMediaPlayer == NULL ) {
Error("Unable to create player for %s due to: %s", mPath.c_str(), libvlc_errmsg());
return -1;
}
libvlc_video_set_format(mLibvlcMediaPlayer, mTargetChroma.c_str(), width, height, width * mBpp);
libvlc_video_set_callbacks(mLibvlcMediaPlayer, &LibvlcLockBuffer, &LibvlcUnlockBuffer, NULL, &mLibvlcData);
@ -177,13 +215,18 @@ int LibvlcCamera::PrimeCapture() {
}
int LibvlcCamera::PreCapture() {
return(0);
return 0;
}
// Should not return -1 as cancels capture. Always wait for image if available.
int LibvlcCamera::Capture( Image &image ) {
while(!mLibvlcData.newImage.getValueImmediate())
int LibvlcCamera::Capture(Image &image) {
// newImage is a mutex/condition based flag to tell us when there is an image available
while( !mLibvlcData.newImage.getValueImmediate() ) {
if (zm_terminate)
return 0;
mLibvlcData.newImage.getUpdatedValue(1);
}
mLibvlcData.mutex.lock();
image.Assign(width, height, colours, subpixelorder, mLibvlcData.buffer, width * height * mBpp);
@ -193,13 +236,12 @@ int LibvlcCamera::Capture( Image &image ) {
return 1;
}
// Should not return -1 as cancels capture. Always wait for image if available.
int LibvlcCamera::CaptureAndRecord(Image &image, timeval recording, char* event_directory) {
return (0);
return 0;
}
int LibvlcCamera::PostCapture() {
return(0);
return 0;
}
#endif // HAVE_LIBVLC

View File

@ -41,8 +41,7 @@ struct LibvlcPrivateData
ThreadData<bool> newImage;
};
class LibvlcCamera : public Camera
{
class LibvlcCamera : public Camera {
protected:
std::string mPath;
std::string mMethod;

View File

@ -330,7 +330,7 @@ bool MonitorStream::sendFrame(const char *filepath, struct timeval *timestamp) {
fprintf(stdout, "Content-Length: %d\r\n", img_buffer_size);
if ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) {
if ( ! zm_terminate )
Error("Unable to send stream frame: %s", strerror(errno));
Warning("Unable to send stream frame: %s", strerror(errno));
return false;
}
fputs("\r\n\r\n", stdout);
@ -407,7 +407,7 @@ bool MonitorStream::sendFrame(Image *image, struct timeval *timestamp) {
if ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) {
if ( !zm_terminate ){
// If the pipe was closed, we will get signalled SIGPIPE to exit, which will set zm_terminate
Error("Unable to send stream frame: %s", strerror(errno));
Warning("Unable to send stream frame: %s", strerror(errno));
}
return false;
}

View File

@ -142,31 +142,29 @@ template <class T> const T ThreadData<T>::getValue() const {
mMutex.lock();
const T valueCopy = mValue;
mMutex.unlock();
return( valueCopy );
return valueCopy;
}
template <class T> T ThreadData<T>::setValue( const T value ) {
template <class T> T ThreadData<T>::setValue(const T value) {
mMutex.lock();
const T valueCopy = mValue = value;
mMutex.unlock();
return( valueCopy );
return valueCopy;
}
template <class T> const T ThreadData<T>::getUpdatedValue() const {
Debug( 8, "Waiting for value update, %p", this );
Debug(8, "Waiting for value update, %p", this);
mMutex.lock();
mChanged = false;
//do {
mCondition.wait();
//} while ( !mChanged );
mCondition.wait();
const T valueCopy = mValue;
mMutex.unlock();
Debug( 9, "Got value update, %p", this );
return( valueCopy );
Debug(9, "Got value update, %p", this);
return valueCopy;
}
template <class T> const T ThreadData<T>::getUpdatedValue( double secs ) const {
Debug( 8, "Waiting for value update, %.2f secs, %p", secs, this );
template <class T> const T ThreadData<T>::getUpdatedValue(double secs) const {
Debug(8, "Waiting for value update, %.2f secs, %p", secs, this);
mMutex.lock();
mChanged = false;
//do {
@ -174,41 +172,41 @@ template <class T> const T ThreadData<T>::getUpdatedValue( double secs ) const {
//} while ( !mChanged );
const T valueCopy = mValue;
mMutex.unlock();
Debug( 9, "Got value update, %p", this );
return( valueCopy );
Debug(9, "Got value update, %p", this );
return valueCopy;
}
template <class T> const T ThreadData<T>::getUpdatedValue( int secs ) const {
Debug( 8, "Waiting for value update, %d secs, %p", secs, this );
template <class T> const T ThreadData<T>::getUpdatedValue(int secs) const {
Debug(8, "Waiting for value update, %d secs, %p", secs, this);
mMutex.lock();
mChanged = false;
//do {
mCondition.wait( secs );
mCondition.wait(secs);
//} while ( !mChanged );
const T valueCopy = mValue;
mMutex.unlock();
Debug( 9, "Got value update, %p", this );
return( valueCopy );
Debug(9, "Got value update, %p", this);
return valueCopy;
}
template <class T> void ThreadData<T>::updateValueSignal( const T value ) {
Debug( 8, "Updating value with signal, %p", this );
template <class T> void ThreadData<T>::updateValueSignal(const T value) {
Debug(8, "Updating value with signal, %p", this);
mMutex.lock();
mValue = value;
mChanged = true;
mCondition.signal();
mMutex.unlock();
Debug( 9, "Updated value, %p", this );
Debug(9, "Updated value, %p", this);
}
template <class T> void ThreadData<T>::updateValueBroadcast( const T value ) {
Debug( 8, "Updating value with broadcast, %p", this );
Debug(8, "Updating value with broadcast, %p", this);
mMutex.lock();
mValue = value;
mChanged = true;
mCondition.broadcast();
mMutex.unlock();
Debug( 9, "Updated value, %p", this );
Debug(9, "Updated value, %p", this);
}
Thread::Thread() :

View File

@ -125,6 +125,9 @@ class EventsController extends AppController {
$event['Event']['Next'] = $event_neighbors['next']['Event']['Id'];
$event['Event']['Prev'] = $event_neighbors['prev']['Event']['Id'];
$event['Event']['fileExists'] = $this->Event->fileExists($event['Event']);
$event['Event']['fileSize'] = $this->Event->fileSize($event['Event']);
# Also get the previous and next events for the same monitor
$event_monitor_neighbors = $this->Event->find('neighbors', array(
'conditions'=>array('Event.MonitorId'=>$event['Event']['MonitorId'])

View File

@ -30,20 +30,37 @@ class HostController extends AppController {
));
}
function getAuthHash() {
if ( $zmOptAuth == '1' ) {
require_once '../../../includes/auth.php';
$this->set(array(
'auth_hash' => generateAuthHash(ZM_AUTH_HASH_IPS),
'_serialize' => array('auth_hash')
) );
} else {
$this->set(array(
'auth_hash' => '',
'_serialize' => array('auth_hash')
) );
function getCredentials() {
// ignore debug warnings from other functions
$this->view='Json';
$credentials = "";
$appendPassword = 0;
$this->loadModel('Config');
$isZmAuth = $this->Config->find('first',array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_OPT_USE_AUTH')))['Config']['Value'];
if ($isZmAuth) {
$zmAuthRelay = $this->Config->find('first',array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_AUTH_RELAY')))['Config']['Value'];
if ($zmAuthRelay == 'hashed') {
$zmAuthHashIps= $this->Config->find('first',array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_AUTH_HASH_IPS')))['Config']['Value'];
$credentials = 'auth='.generateAuthHash($zmAuthHashIps);
}
elseif ($zmAuthRelay == 'plain') {
// user will need to append the store password here
$credentials = "user=".$this->Session->read('user.Username')."&pass=";
$appendPassword = 1;
}
elseif ($zmAuthRelay == 'none') {
$credentials = "user=".$this->Session->read('user.Username');
}
}
}
$this->set(array(
'credentials'=> $credentials,
'append_password'=>$appendPassword,
'_serialize' => array('credentials', 'append_password')
) );
}
// If $mid is set, only return disk usage for that monitor
// Else, return an array of total disk usage, and per-monitor

View File

@ -44,7 +44,15 @@ class Event extends AppModel {
'conditions' => '',
'fields' => '',
'order' => ''
)
),
'Storage' => array(
'className' => 'Storage',
'joinTable' => 'Storage',
'foreignKey' => 'StorageId',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
/**
@ -92,4 +100,40 @@ class Event extends AppModel {
),
);
public function Relative_Path($event) {
$event_path = '';
if ( $event['Scheme'] == 'Deep' ) {
$event_path = $event['MonitorId'] .'/'.strftime('%y/%m/%d/%H/%M/%S', strtotime($event['StartTime']));
} else if ( $event['Scheme'] == 'Medium' ) {
$event_path = $event['MonitorId'] .'/'.strftime('%Y-%m-%d', strtotime($event['StartTime'])) . '/'.$event['Id'];
} else {
$event_path = $event['MonitorId'] .'/'.$event['Id'];
}
return $event_path;
} // end function Relative_Path()
public function fileExists($event) {
//$data = $this->findById($id);
//return $data['Event']['dataset_filename'];
$storage = $this->Storage->findById($event['StorageId']);
if ( $event['DefaultVideo'] ) {
if ( file_exists($storage['Storage']['Path'].'/'.$this->Relative_Path($event).'/'.$event['DefaultVideo']) ) {
return 1;
} else {
Logger::Debug("FIle does not exist at " . $storage['Storage']['Path'].'/'.$this->Relative_Path($event).'/'.$event['DefaultVideo'] );
}
} else {
Logger::Debug("No DefaultVideo in Event" . $this->Event);
return 0;
}
} // end function fileExists($event)
public function fileSize($event) {
$storage = $this->Storage->findById($event['StorageId']);
return filesize($storage['Storage']['Path'].'/'.$this->Relative_Path($event).'/'.$event['DefaultVideo']);
}
}

View File

@ -0,0 +1,69 @@
<?php
App::uses('AppModel', 'Model');
/**
* Storage Model
*
* @property Event $Event
* @property Zone $Zone
*/
class Storage extends AppModel {
/**
* Use table
*
* @var mixed False or table name
*/
public $useTable = 'Storage';
/**
* Primary key field
*
* @var string
*/
public $primaryKey = 'Id';
/**
* Display field
*
* @var string
*/
public $displayField = 'Name';
public $recursive = -1;
/**
* Validation rules
*
* @var array
*/
public $validate = array(
'Id' => array(
'numeric' => array(
'rule' => array('numeric'),
//'message' => 'Your custom message here',
//'allowEmpty' => false,
//'required' => false,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
),
);
//The Associations below have been created with all possible keys, those that are not needed can be removed
/**
* hasMany associations
*
* @var array
*/
public $belongsTo = array(
'Server' => array(
'className' => 'Server',
'foreignKey' => 'ServerId',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
)
);
}

@ -1 +1 @@
Subproject commit c3976f1478c681b0bbc132ec3a3e82c3984eeed5
Subproject commit 0bd63fb464957080ead342db58ca9e01532cf1ef

View File

@ -522,6 +522,94 @@ class Event {
return '<a href="?view=event&amp;eid='. $this->{'Id'}.'">'.$text.'</a>';
}
public function file_exists() {
if ( file_exists( $this->Path().'/'.$this->DefaultVideo() ) ) {
return true;
}
$Storage= $this->Storage();
$Server = $Storage->ServerId() ? $Storage->Server() : $this->Monitor()->Server();
if ( $Server->Id() != ZM_SERVER_ID ) {
$url = $Server->Url() . '/zm/api/events/'.$this->{'Id'}.'.json';
if ( ZM_OPT_USE_AUTH ) {
if ( ZM_AUTH_RELAY == 'hashed' ) {
$url .= '?auth='.generateAuthHash( ZM_AUTH_HASH_IPS );
} elseif ( ZM_AUTH_RELAY == 'plain' ) {
$url = '?user='.$_SESSION['username'];
$url = '?pass='.$_SESSION['password'];
} elseif ( ZM_AUTH_RELAY == 'none' ) {
$url = '?user='.$_SESSION['username'];
}
}
Logger::Debug("sending command to $url");
// use key 'http' even if you send the request to https://...
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'GET',
'content' => ''
)
);
$context = stream_context_create($options);
try {
$result = file_get_contents($url, false, $context);
if ($result === FALSE) { /* Handle error */
Error("Error restarting zmc using $url");
}
$event_data = json_decode($result,true);
Logger::Debug(print_r($event_data['event']['Event'],1));
return $event_data['event']['Event']['fileExists'];
} catch ( Exception $e ) {
Error("Except $e thrown trying to get event data");
}
} # end if not local
return false;
} # end public function file_exists()
public function file_size() {
if ( file_exists($this->Path().'/'.$this->DefaultVideo()) ) {
return filesize($this->Path().'/'.$this->DefaultVideo());
}
$Storage= $this->Storage();
$Server = $Storage->ServerId() ? $Storage->Server() : $this->Monitor()->Server();
if ( $Server->Id() != ZM_SERVER_ID ) {
$url = $Server->Url() . '/zm/api/events/'.$this->{'Id'}.'.json';
if ( ZM_OPT_USE_AUTH ) {
if ( ZM_AUTH_RELAY == 'hashed' ) {
$url .= '?auth='.generateAuthHash( ZM_AUTH_HASH_IPS );
} elseif ( ZM_AUTH_RELAY == 'plain' ) {
$url = '?user='.$_SESSION['username'];
$url = '?pass='.$_SESSION['password'];
} elseif ( ZM_AUTH_RELAY == 'none' ) {
$url = '?user='.$_SESSION['username'];
}
}
Logger::Debug("sending command to $url");
// use key 'http' even if you send the request to https://...
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'GET',
'content' => ''
)
);
$context = stream_context_create($options);
try {
$result = file_get_contents($url, false, $context);
if ($result === FALSE) { /* Handle error */
Error("Error restarting zmc using $url");
}
$event_data = json_decode($result,true);
Logger::Debug(print_r($event_data['event']['Event'],1));
return $event_data['event']['Event']['fileSize'];
} catch ( Exception $e ) {
Error("Except $e thrown trying to get event data");
}
} # end if not local
return 0;
} # end public function file_size()
} # end class
?>

View File

@ -172,6 +172,7 @@ class Storage {
}
return $this->{'DiskSpace'};
} // end function event_disk_space
public function Server() {
if ( ! array_key_exists('Server',$this) ) {
$this->{'Server'}= new Server( $this->{'ServerId'} );

View File

@ -195,16 +195,15 @@ $html .= htmlSelect( 'Status[]', $status_options,
$Monitor = new Monitor($monitors[$i]);
ini_set('track_errors', 'on');
$php_errormsg = '';
@preg_match($_SESSION['MonitorName'], '');
if ( !$php_errormsg ) {
# regexp is valid
if ( !preg_match($_SESSION['MonitorName'], $Monitor->Name()) ) {
continue;
}
} else {
if ( ! strstr($Monitor->Name(), $_SESSION['MonitorName']) ) {
continue;
}
$regexp = $_SESSION['MonitorName'];
@preg_match($regexp, '');
if ( $php_errormsg ) {
$regexp = '/'.preg_quote($regexp,'/').'/i';
}
if ( !preg_match($regexp, $Monitor->Name()) ) {
continue;
}
}
@ -212,16 +211,14 @@ $html .= htmlSelect( 'Status[]', $status_options,
$Monitor = new Monitor($monitors[$i]);
ini_set('track_errors', 'on');
$php_errormsg = '';
@preg_match($_SESSION['Source'], '');
if ( !$php_errormsg ) {
# regexp is valid
if ( !preg_match($_SESSION['Source'], $Monitor->Source()) ) {
continue;
}
} else {
if ( ! strstr($Monitor->Source(), $_SESSION['Source']) ) {
continue;
}
$regexp = $_SESSION['Source'];
@preg_match($regexp, '');
if ( $php_errormsg ) {
$regexp = '/'.preg_quote($regexp,'/').'/i';
}
if ( !preg_match($regexp, $Monitor->Source()) ) {
continue;
}
}

View File

@ -27,14 +27,15 @@ ob_end_clean();
noCacheHeaders();
xhtmlHeaders( __FILE__, translate('Console') );
if ( !isset($_REQUEST['minTime']) && !isset($_REQUEST['maxTime']) ) {
$time = time();
$maxTime = strftime('%FT%T',$time - 3600);
$minTime = strftime('%FT%T',$time - (2*3600) );
} else if ( isset($_REQUEST['minTime']) ) {
if ( isset($_REQUEST['minTime']) ) {
$minTime = validHtmlStr($_REQUEST['minTime']);
} else if ( isset($_REQUEST['maxTime']) ) {
} else {
$minTime = strftime('%FT%T',time() - (2*3600) );
}
if ( isset($_REQUEST['maxTime']) ) {
$maxTime = validHtmlStr($_REQUEST['maxTime']);
} else {
$maxTime = strftime('%FT%T',time() - 3600);
}
$filter = array(
@ -63,8 +64,6 @@ parseFilter($filter);
$filterQuery = $filter['query'];
Logger::Debug($filterQuery);
$eventsSql = 'SELECT *,
UNIX_TIMESTAMP(E.StartTime) AS StartTimeSecs,
UNIX_TIMESTAMP(EndTime) AS EndTimeSecs
@ -91,7 +90,7 @@ $EventsByMonitor = array();
while( $event = $result->fetch(PDO::FETCH_ASSOC) ) {
$Event = new Event($event);
if ( ! isset($EventsByMonitor[$event['MonitorId']]) )
$EventsByMonitor[$event['MonitorId']] = array( 'Events'=>array(), 'MinGap'=>0, 'MaxGap'=>0, 'FileMissing'=>0, 'ZeroSize'=>array() );
$EventsByMonitor[$event['MonitorId']] = array( 'Events'=>array(), 'MinGap'=>0, 'MaxGap'=>0, 'FileMissing'=>array(), 'ZeroSize'=>array() );
if ( count($EventsByMonitor[$event['MonitorId']]['Events']) ) {
$last_event = end($EventsByMonitor[$event['MonitorId']]['Events']);
@ -104,9 +103,9 @@ while( $event = $result->fetch(PDO::FETCH_ASSOC) ) {
$EventsByMonitor[$event['MonitorId']]['MaxGap'] = $gap;
} # end if has previous events
if ( ! file_exists( $Event->Path().'/'.$Event->DefaultVideo() ) ) {
$EventsByMonitor[$event['MonitorId']]['FileMissing'] += 1;
} else if ( ! filesize( $Event->Path().'/'.$Event->DefaultVideo() ) ) {
if ( ! $Event->file_exists() ) {
$EventsByMonitor[$event['MonitorId']]['FileMissing'][] = $Event;
} else if ( ! $Event->file_size() ) {
$EventsByMonitor[$event['MonitorId']]['ZeroSize'][] = $Event;
}
$EventsByMonitor[$event['MonitorId']]['Events'][] = $Event;
@ -169,12 +168,33 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) {
} else {
$MinGap = 0;
$MaxGap = 0;
$FileMissing = 0;
$ZeroSize = 0;
$FileMissing = array();
$ZeroSize = array();
$FirstEvent = 0;
$LastEvent = 0;
}
if ( count($FileMissing) ) {
$FileMissing_filter = array(
'Query' => array(
'terms' => array(
array('attr'=>'Id','op'=>'IN', 'val'=>implode(',',array_map(function($Event){return $Event->Id();},$FileMissing)))
)
)
);
parseFilter($FileMissing_filter);
}
if ( count($ZeroSize) ) {
$ZeroSize_filter = array(
'Query' => array(
'terms' => array(
array('attr'=>'Id','op'=>'IN', 'val'=>implode(',',array_map(function($Event){return $Event->Id();},$ZeroSize)))
)
)
);
}
?>
<tr id="<?php echo 'monitor_id-'.$monitor['Id'] ?>" title="<?php echo $monitor['Id'] ?>">
<td class="colId"><a href="<?php echo $montagereview_link ?>"><?php echo $monitor['Id'] ?></a></td>
@ -195,8 +215,12 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) {
<td class="colLastEvent"><?php echo $LastEvent ? $LastEvent->link_to($LastEvent->Id().' at ' . $LastEvent->StartTime()) : 'none'?></td>
<td class="colMinGap"><?php echo $MinGap ?></td>
<td class="colMaxGap"><?php echo $MaxGap ?></td>
<td class="colFileMissing<?php echo $FileMissing ? ' errorText' : ''?>"><?php echo $FileMissing ?></td>
<td class="colZeroSize<?php echo count($ZeroSize) ? ' errorText' : ''?>"><?php echo count($ZeroSize) ?></td>
<td class="colFileMissing<?php echo count($FileMissing) ? ' errorText' : ''?>">
<?php echo count($FileMissing) ? '<a href="?view='.ZM_WEB_EVENTS_VIEW .'&amp;page=1'.$FileMissing_filter['query'].'">'.count($FileMissing).'</a>' : '0' ?>
</td>
<td class="colZeroSize<?php echo count($ZeroSize) ? ' errorText' : ''?>">
<?php echo count($ZeroSize) ? '<a href="?view='.ZM_WEB_EVENTS_VIEW .'&amp;page=1'.$ZeroSize_filter['query'].'">'.count($FileMissing).'</a>' : '0' ?>
</td>
</tr>
<?php
} # end for each monitor