Merge branch 'fix_zms'
commit
e21ffbea7d
|
@ -22,7 +22,7 @@
|
|||
#endif
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef _WIN32 || _WIN64
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
// On windows we need to generate random bytes differently.
|
||||
typedef __int64 ssize_t;
|
||||
#define BCRYPT_HASHSIZE 60
|
||||
|
@ -117,7 +117,7 @@ int bcrypt_gensalt(int factor, char salt[BCRYPT_HASHSIZE])
|
|||
char *aux;
|
||||
|
||||
// Note: Windows does not have /dev/urandom sadly.
|
||||
#ifdef _WIN32 || _WIN64
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
HCRYPTPROV p;
|
||||
ULONG i;
|
||||
|
||||
|
|
|
@ -164,7 +164,22 @@ bool EventStream::loadEventData(uint64_t event_id) {
|
|||
event_data->Orientation = (Monitor::Orientation)(dbrow[8] == NULL ? 0 : atoi(dbrow[8]));
|
||||
mysql_free_result(result);
|
||||
|
||||
Storage * storage = new Storage(event_data->storage_id);
|
||||
if ( !monitor ) {
|
||||
monitor = Monitor::Load(event_data->monitor_id, false, Monitor::QUERY);
|
||||
} else if ( monitor->Id() != event_data->monitor_id ) {
|
||||
delete monitor;
|
||||
monitor = Monitor::Load(event_data->monitor_id, false, Monitor::QUERY);
|
||||
}
|
||||
if ( !monitor ) {
|
||||
Fatal("Unable to load monitor id %d for streaming", event_data->monitor_id);
|
||||
}
|
||||
|
||||
if ( !storage ) {
|
||||
storage = new Storage(event_data->storage_id);
|
||||
} else if ( storage->Id() != event_data->storage_id ) {
|
||||
delete storage;
|
||||
storage = new Storage(event_data->storage_id);
|
||||
}
|
||||
const char *storage_path = storage->Path();
|
||||
|
||||
if ( event_data->scheme == Storage::DEEP ) {
|
||||
|
@ -206,7 +221,6 @@ bool EventStream::loadEventData(uint64_t event_id) {
|
|||
staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id,
|
||||
event_data->event_id);
|
||||
}
|
||||
delete storage; storage = NULL;
|
||||
|
||||
updateFrameRate((double)event_data->frame_count/event_data->duration);
|
||||
Debug(3, "fps set by frame_count(%d)/duration(%f)",
|
||||
|
@ -246,7 +260,7 @@ bool EventStream::loadEventData(uint64_t event_id) {
|
|||
event_data->frames[i-1].timestamp = last_timestamp + ((i-last_id)*frame_delta);
|
||||
event_data->frames[i-1].offset = event_data->frames[i-1].timestamp - event_data->start_time;
|
||||
event_data->frames[i-1].in_db = false;
|
||||
Debug(3,"Frame %d timestamp:(%f), offset(%f) delta(%f), in_db(%d)",
|
||||
Debug(3, "Frame %d timestamp:(%f), offset(%f) delta(%f), in_db(%d)",
|
||||
i,
|
||||
event_data->frames[i-1].timestamp,
|
||||
event_data->frames[i-1].offset,
|
||||
|
@ -262,7 +276,7 @@ bool EventStream::loadEventData(uint64_t event_id) {
|
|||
last_id = id;
|
||||
last_delta = delta;
|
||||
last_timestamp = event_data->frames[id-1].timestamp;
|
||||
Debug(4, "Frame %d timestamp:(%f), offset(%f) delta(%f), in_db(%d)",
|
||||
Debug(3, "Frame %d timestamp:(%f), offset(%f) delta(%f), in_db(%d)",
|
||||
id,
|
||||
event_data->frames[id-1].timestamp,
|
||||
event_data->frames[id-1].offset,
|
||||
|
@ -277,7 +291,10 @@ bool EventStream::loadEventData(uint64_t event_id) {
|
|||
|
||||
mysql_free_result(result);
|
||||
|
||||
if ( event_data->video_file[0] ) {
|
||||
if ( event_data->video_file[0] || (monitor->GetOptVideoWriter() > 0) ) {
|
||||
if ( !event_data->video_file[0] ) {
|
||||
snprintf(event_data->video_file, sizeof(event_data->video_file), "%" PRIu64 "-%s", event_data->event_id, "video.mp4");
|
||||
}
|
||||
std::string filepath = std::string(event_data->path) + "/" + std::string(event_data->video_file);
|
||||
//char filepath[PATH_MAX];
|
||||
//snprintf(filepath, sizeof(filepath), "%s/%s", event_data->path, event_data->video_file);
|
||||
|
@ -305,7 +322,7 @@ bool EventStream::loadEventData(uint64_t event_id) {
|
|||
void EventStream::processCommand(const CmdMsg *msg) {
|
||||
Debug(2, "Got message, type %d, msg %d", msg->msg_type, msg->msg_data[0]);
|
||||
// Check for incoming command
|
||||
switch( (MsgCommand)msg->msg_data[0] ) {
|
||||
switch ( (MsgCommand)msg->msg_data[0] ) {
|
||||
case CMD_PAUSE :
|
||||
Debug(1, "Got PAUSE command");
|
||||
|
||||
|
@ -504,6 +521,7 @@ void EventStream::processCommand(const CmdMsg *msg) {
|
|||
// Do nothing, for now
|
||||
break;
|
||||
}
|
||||
|
||||
struct {
|
||||
uint64_t event_id;
|
||||
int progress;
|
||||
|
@ -541,9 +559,9 @@ void EventStream::processCommand(const CmdMsg *msg) {
|
|||
exit(0);
|
||||
|
||||
updateFrameRate((double)event_data->frame_count/event_data->duration);
|
||||
} // void EventStream::processCommand(const CmdMsg *msg)
|
||||
} // void EventStream::processCommand(const CmdMsg *msg)
|
||||
|
||||
void EventStream::checkEventLoaded() {
|
||||
bool EventStream::checkEventLoaded() {
|
||||
static char sql[ZM_SQL_SML_BUFSIZ];
|
||||
|
||||
if ( curr_frame_id <= 0 ) {
|
||||
|
@ -558,7 +576,7 @@ void EventStream::checkEventLoaded() {
|
|||
// No event change required
|
||||
Debug(3, "No event change required, as curr frame %d <=> event frames %d",
|
||||
curr_frame_id, event_data->frame_count);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Event change required.
|
||||
|
@ -592,6 +610,7 @@ void EventStream::checkEventLoaded() {
|
|||
else
|
||||
curr_frame_id = 1;
|
||||
Debug(2, "New frame id = %d", curr_frame_id);
|
||||
return true;
|
||||
} else {
|
||||
Debug(2, "No next event loaded using %s. Pausing", sql);
|
||||
if ( curr_frame_id <= 0 )
|
||||
|
@ -600,7 +619,7 @@ void EventStream::checkEventLoaded() {
|
|||
curr_frame_id = event_data->frame_count;
|
||||
paused = true;
|
||||
sendTextFrame("No more event data found");
|
||||
} // end if found a new event or not
|
||||
} // end if found a new event or not
|
||||
mysql_free_result(result);
|
||||
forceEventChange = false;
|
||||
} else {
|
||||
|
@ -611,7 +630,8 @@ void EventStream::checkEventLoaded() {
|
|||
curr_frame_id = event_data->frame_count;
|
||||
paused = true;
|
||||
}
|
||||
} // void EventStream::checkEventLoaded()
|
||||
return false;
|
||||
} // void EventStream::checkEventLoaded()
|
||||
|
||||
Image * EventStream::getImage( ) {
|
||||
static char filepath[PATH_MAX];
|
||||
|
@ -656,7 +676,8 @@ bool EventStream::sendFrame(int delta_us) {
|
|||
Image *send_image = prepareImage(&image);
|
||||
|
||||
if ( !vid_stream ) {
|
||||
vid_stream = new VideoStream("pipe:", format, bitrate, effective_fps, send_image->Colours(), send_image->SubpixelOrder(), send_image->Width(), send_image->Height());
|
||||
vid_stream = new VideoStream("pipe:", format, bitrate, effective_fps,
|
||||
send_image->Colours(), send_image->SubpixelOrder(), send_image->Width(), send_image->Height());
|
||||
fprintf(stdout, "Content-type: %s\r\n\r\n", vid_stream->MimeType());
|
||||
vid_stream->OpenStream();
|
||||
}
|
||||
|
@ -699,9 +720,10 @@ Debug(1, "Loading image");
|
|||
} else if ( ffmpeg_input ) {
|
||||
// Get the frame from the mp4 input
|
||||
Debug(1,"Getting frame from ffmpeg");
|
||||
AVFrame *frame;
|
||||
FrameData *frame_data = &event_data->frames[curr_frame_id-1];
|
||||
frame = ffmpeg_input->get_frame( ffmpeg_input->get_video_stream_id(), frame_data->offset );
|
||||
AVFrame *frame = ffmpeg_input->get_frame(
|
||||
ffmpeg_input->get_video_stream_id(),
|
||||
frame_data->offset);
|
||||
if ( frame ) {
|
||||
image = new Image(frame);
|
||||
//av_frame_free(&frame);
|
||||
|
@ -766,6 +788,10 @@ Debug(1, "Loading image");
|
|||
Fatal("Unexpected frame type %d", type);
|
||||
break;
|
||||
}
|
||||
if ( send_image != image ) {
|
||||
delete send_image;
|
||||
send_image = NULL;
|
||||
}
|
||||
delete image;
|
||||
image = NULL;
|
||||
} // end if send_raw or not
|
||||
|
@ -839,6 +865,10 @@ void EventStream::runStream() {
|
|||
updateFrameRate((double)event_data->frame_count/event_data->duration);
|
||||
gettimeofday(&start, NULL);
|
||||
uint64_t start_usec = start.tv_sec * 1000000 + start.tv_usec;
|
||||
uint64_t last_frame_offset = 0;
|
||||
|
||||
bool in_event = true;
|
||||
double time_to_event = 0;
|
||||
|
||||
while ( !zm_terminate ) {
|
||||
gettimeofday(&now, NULL);
|
||||
|
@ -862,73 +892,14 @@ void EventStream::runStream() {
|
|||
// Get current frame data
|
||||
FrameData *frame_data = &event_data->frames[curr_frame_id-1];
|
||||
|
||||
//Info( "cst:%.2f", curr_stream_time );
|
||||
//Info( "cfid:%d", curr_frame_id );
|
||||
//Info( "fdt:%d", frame_data->timestamp );
|
||||
if ( !paused ) {
|
||||
Debug(3, "Not paused at frame %d", curr_frame_id);
|
||||
|
||||
// This next bit is to determine if we are in the current event time wise
|
||||
// and whether to show an image saying how long until the next event.
|
||||
bool in_event = true;
|
||||
double time_to_event = 0;
|
||||
if ( replay_rate > 0 ) {
|
||||
time_to_event = event_data->frames[0].timestamp - curr_stream_time;
|
||||
if ( time_to_event > 0 )
|
||||
in_event = false;
|
||||
} else if ( replay_rate < 0 ) {
|
||||
time_to_event = curr_stream_time - event_data->frames[event_data->frame_count-1].timestamp;
|
||||
if ( time_to_event > 0 )
|
||||
in_event = false;
|
||||
}
|
||||
Debug(1, "replay rate(%d) in_event(%d) time_to_event(%f)=curr_stream_time(%f)-frame timestamp:%f",
|
||||
replay_rate, in_event, time_to_event, curr_stream_time, event_data->frames[event_data->frame_count-1].timestamp);
|
||||
if ( !in_event ) {
|
||||
double actual_delta_time = TV_2_FLOAT(now) - last_frame_sent;
|
||||
Debug(1, "Ctual delta time = %f = %f - %f", actual_delta_time , TV_2_FLOAT(now) , last_frame_sent);
|
||||
// > 1 second
|
||||
if ( actual_delta_time > 1 ) {
|
||||
Debug(1, "Sending time to next event frame");
|
||||
static char frame_text[64];
|
||||
snprintf(frame_text, sizeof(frame_text), "Time to next event = %d seconds", (int)time_to_event);
|
||||
if ( !sendTextFrame(frame_text) )
|
||||
zm_terminate = true;
|
||||
} else {
|
||||
Debug(1, "Not Sending time to next event frame because actual delta time is %f", actual_delta_time);
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// FIXME ICON But we are not paused. We are somehow still in the event?
|
||||
double sleep_time = (replay_rate>0?1:-1) * ((1.0L * replay_rate * STREAM_PAUSE_WAIT)/(ZM_RATE_BASE * 1000000));
|
||||
//double sleep_time = (replay_rate * STREAM_PAUSE_WAIT)/(ZM_RATE_BASE * 1000000);
|
||||
//// ZM_RATE_BASE == 100, and 1x replay_rate is 100
|
||||
//double sleep_time = ((replay_rate/ZM_RATE_BASE) * STREAM_PAUSE_WAIT)/1000000;
|
||||
if ( ! sleep_time ) {
|
||||
sleep_time += STREAM_PAUSE_WAIT/1000000;
|
||||
}
|
||||
curr_stream_time += sleep_time;
|
||||
Debug(2, "Sleeping (%dus) because we are not at the next event yet, adding %f", STREAM_PAUSE_WAIT, sleep_time);
|
||||
usleep(STREAM_PAUSE_WAIT);
|
||||
|
||||
//curr_stream_time += (1.0L * replay_rate * STREAM_PAUSE_WAIT)/(ZM_RATE_BASE * 1000000);
|
||||
//}
|
||||
continue;
|
||||
} // end if !in_event
|
||||
|
||||
// Figure out if we should send this frame
|
||||
Debug(3, "cur_frame_id (%d-1) mod frame_mod(%d)", curr_frame_id, frame_mod);
|
||||
Debug(3, "not paused at cur_frame_id (%d-1) mod frame_mod(%d)", curr_frame_id, frame_mod);
|
||||
// If we are streaming and this frame is due to be sent
|
||||
// frame mod defaults to 1 and if we are going faster than max_fps will get multiplied by 2
|
||||
// so if it is 2, then we send every other frame, if is it 4 then every fourth frame, etc.
|
||||
|
||||
if ( (frame_mod == 1) || (((curr_frame_id-1)%frame_mod) == 0) ) {
|
||||
delta_us = (unsigned int)(frame_data->delta * 1000000);
|
||||
Debug(3, "frame delta %uus ", delta_us);
|
||||
// if effective > base we should speed up frame delivery
|
||||
delta_us = (unsigned int)((delta_us * base_fps)/effective_fps);
|
||||
Debug(3, "delta %u = base_fps(%f)/effective fps(%f)", delta_us, base_fps, effective_fps);
|
||||
// but must not exceed maxfps
|
||||
delta_us = max(delta_us, 1000000 / maxfps);
|
||||
Debug(3, "delta %u = base_fps(%f)/effective fps(%f) from 30fps", delta_us, base_fps, effective_fps);
|
||||
send_frame = true;
|
||||
}
|
||||
} else if ( step != 0 ) {
|
||||
|
@ -937,16 +908,48 @@ void EventStream::runStream() {
|
|||
step = 0;
|
||||
send_frame = true;
|
||||
} else if ( !send_frame ) {
|
||||
// We are paused, not stepping and doing nothing
|
||||
// We are paused, not stepping and doing nothing, meaning that comms didn't set send_frame to true
|
||||
double actual_delta_time = TV_2_FLOAT(now) - last_frame_sent;
|
||||
if ( actual_delta_time > MAX_STREAM_DELAY ) {
|
||||
// Send keepalive
|
||||
Debug(2, "Sending keepalive frame");
|
||||
send_frame = true;
|
||||
//} else {
|
||||
//Debug(2, "Not Sending keepalive frame");
|
||||
}
|
||||
} // end if streaming stepping or doing nothing
|
||||
} // end if streaming stepping or doing nothing
|
||||
|
||||
// time_to_event > 0 means that we are not in the event
|
||||
if ( time_to_event > 0 ) {
|
||||
double actual_delta_time = TV_2_FLOAT(now) - last_frame_sent;
|
||||
Debug(1, "Actual delta time = %f = %f - %f", actual_delta_time, TV_2_FLOAT(now), last_frame_sent);
|
||||
// > 1 second
|
||||
if ( actual_delta_time > 1 ) {
|
||||
Debug(1, "Sending time to next event frame");
|
||||
static char frame_text[64];
|
||||
snprintf(frame_text, sizeof(frame_text), "Time to next event = %d seconds", (int)time_to_event);
|
||||
if ( !sendTextFrame(frame_text) )
|
||||
zm_terminate = true;
|
||||
} else {
|
||||
Debug(1, "Not Sending time to next event frame because actual delta time is %f", actual_delta_time);
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// FIXME ICON But we are not paused. We are somehow still in the event?
|
||||
double sleep_time = (replay_rate>0?1:-1) * ((1.0L * replay_rate * STREAM_PAUSE_WAIT)/(ZM_RATE_BASE * 1000000));
|
||||
//double sleep_time = (replay_rate * STREAM_PAUSE_WAIT)/(ZM_RATE_BASE * 1000000);
|
||||
//// ZM_RATE_BASE == 100, and 1x replay_rate is 100
|
||||
//double sleep_time = ((replay_rate/ZM_RATE_BASE) * STREAM_PAUSE_WAIT)/1000000;
|
||||
if ( !sleep_time ) {
|
||||
sleep_time += STREAM_PAUSE_WAIT/1000000;
|
||||
}
|
||||
curr_stream_time += sleep_time;
|
||||
time_to_event -= sleep_time;
|
||||
Debug(2, "Sleeping (%dus) because we are not at the next event yet, adding %f", STREAM_PAUSE_WAIT, sleep_time);
|
||||
usleep(STREAM_PAUSE_WAIT);
|
||||
|
||||
//curr_stream_time += (1.0L * replay_rate * STREAM_PAUSE_WAIT)/(ZM_RATE_BASE * 1000000);
|
||||
//}
|
||||
continue;
|
||||
} // end if !in_event
|
||||
|
||||
if ( send_frame ) {
|
||||
if ( !sendFrame(delta_us) ) {
|
||||
|
@ -958,6 +961,17 @@ void EventStream::runStream() {
|
|||
curr_stream_time = frame_data->timestamp;
|
||||
|
||||
if ( !paused ) {
|
||||
|
||||
// delta is since the last frame
|
||||
delta_us = (unsigned int)(frame_data->delta * 1000000);
|
||||
Debug(3, "frame delta %uus ", delta_us);
|
||||
// if effective > base we should speed up frame delivery
|
||||
delta_us = (unsigned int)((delta_us * base_fps)/effective_fps);
|
||||
Debug(3, "delta %u = base_fps(%f)/effective fps(%f)", delta_us, base_fps, effective_fps);
|
||||
// but must not exceed maxfps
|
||||
delta_us = max(delta_us, 1000000/maxfps);
|
||||
Debug(3, "delta %u = base_fps(%f)/effective fps(%f) from 30fps", delta_us, base_fps, effective_fps);
|
||||
|
||||
// +/- 1? What if we are skipping frames?
|
||||
curr_frame_id += (replay_rate>0) ? frame_mod : -1*frame_mod;
|
||||
// sending the frame may have taken some time, so reload now
|
||||
|
@ -965,7 +979,12 @@ void EventStream::runStream() {
|
|||
uint64_t now_usec = (now.tv_sec * 1000000 + now.tv_usec);
|
||||
|
||||
// we incremented by replay_rate, so might have jumped past frame_count
|
||||
if ( (mode == MODE_SINGLE) && ((unsigned int)curr_frame_id >= event_data->frame_count) ) {
|
||||
if ( (mode == MODE_SINGLE) && (
|
||||
(curr_frame_id < 1 )
|
||||
||
|
||||
((unsigned int)curr_frame_id >= event_data->frame_count)
|
||||
)
|
||||
) {
|
||||
Debug(2, "Have mode==MODE_SINGLE and at end of event, looping back to start");
|
||||
curr_frame_id = 1;
|
||||
// Have to reset start_usec to now when replaying
|
||||
|
@ -980,9 +999,21 @@ void EventStream::runStream() {
|
|||
// There are two ways to go about this, not sure which is correct.
|
||||
// you can calculate the relationship between now and the start
|
||||
// or calc the relationship from the last frame. I think from the start is better as it self-corrects
|
||||
//
|
||||
if ( last_frame_offset ) {
|
||||
// We assume that we are going forward and the next frame is in the future.
|
||||
delta_us = frame_data->offset * 1000000 - (now_usec-start_usec);
|
||||
// - (now_usec - start_usec);
|
||||
Debug(2, "New delta_us now %" PRIu64 " - start %" PRIu64 " = %d offset %" PRId64 " - elapsed = %dusec",
|
||||
now_usec, start_usec, now_usec-start_usec, frame_data->offset * 1000000, delta_us);
|
||||
} else {
|
||||
Debug(2, "No last frame_offset, no sleep");
|
||||
delta_us = 0;
|
||||
}
|
||||
last_frame_offset = frame_data->offset * 1000000;
|
||||
|
||||
if ( send_frame && type != STREAM_MPEG ) {
|
||||
if ( delta_us > 0) {
|
||||
if ( send_frame && (type != STREAM_MPEG) ) {
|
||||
if ( delta_us > 0 ) {
|
||||
if ( delta_us > MAX_SLEEP_USEC ) {
|
||||
Debug(1, "Limiting sleep to %d because calculated sleep is too long %d", MAX_SLEEP_USEC, delta_us);
|
||||
delta_us = MAX_SLEEP_USEC;
|
||||
|
@ -1007,16 +1038,34 @@ void EventStream::runStream() {
|
|||
}
|
||||
usleep(delta_us);
|
||||
}
|
||||
} // end if !paused
|
||||
|
||||
//if ( step != 0 )// Adding 0 is cheaper than an if 0
|
||||
// curr_frame_id starts at 1 though, so we might skip the first frame?
|
||||
// We are paused, so might be stepping
|
||||
//if ( step != 0 )// Adding 0 is cheaper than an if 0
|
||||
// curr_frame_id starts at 1 though, so we might skip the first frame?
|
||||
curr_frame_id += step;
|
||||
|
||||
// Detects when we hit end of event and will load the next event or previous event
|
||||
if ( !paused )
|
||||
checkEventLoaded();
|
||||
} // end while ! zm_terminate
|
||||
// Detects when we hit end of event and will load the next event or previous event
|
||||
if ( checkEventLoaded() ) {
|
||||
// Have change of event
|
||||
|
||||
// This next bit is to determine if we are in the current event time wise
|
||||
// and whether to show an image saying how long until the next event.
|
||||
if ( replay_rate > 0 ) {
|
||||
// This doesn't make sense unless we have hit the end of the event.
|
||||
time_to_event = event_data->frames[0].timestamp - curr_stream_time;
|
||||
Debug(1, "replay rate(%d) time_to_event(%f)=frame timestamp:%f - curr_stream_time(%f)",
|
||||
replay_rate, time_to_event,
|
||||
event_data->frames[0].timestamp,
|
||||
curr_stream_time);
|
||||
|
||||
} else if ( replay_rate < 0 ) {
|
||||
time_to_event = curr_stream_time - event_data->frames[event_data->frame_count-1].timestamp;
|
||||
Debug(1, "replay rate(%d) time_to_event(%f)=curr_stream_time(%f)-frame timestamp:%f",
|
||||
replay_rate, time_to_event, curr_stream_time, event_data->frames[event_data->frame_count-1].timestamp);
|
||||
} // end if forward or reverse
|
||||
|
||||
} // end if checkEventLoaded
|
||||
} // end if !paused
|
||||
} // end while ! zm_terminate
|
||||
#if HAVE_LIBAVCODEC
|
||||
if ( type == STREAM_MPEG )
|
||||
delete vid_stream;
|
||||
|
@ -1025,18 +1074,12 @@ void EventStream::runStream() {
|
|||
closeComms();
|
||||
} // void EventStream::runStream()
|
||||
|
||||
void EventStream::setStreamStart( uint64_t init_event_id, unsigned int init_frame_id=0 ) {
|
||||
void EventStream::setStreamStart(
|
||||
uint64_t init_event_id,
|
||||
unsigned int init_frame_id=0) {
|
||||
loadInitialEventData(init_event_id, init_frame_id);
|
||||
if ( !(monitor = Monitor::Load(event_data->monitor_id, false, Monitor::QUERY)) ) {
|
||||
Fatal("Unable to load monitor id %d for streaming", event_data->monitor_id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} // end void EventStream::setStreamStart(init_event_id,init_frame_id=0)
|
||||
|
||||
void EventStream::setStreamStart(int monitor_id, time_t event_time) {
|
||||
loadInitialEventData(monitor_id, event_time);
|
||||
if ( !(monitor = Monitor::Load(event_data->monitor_id, false, Monitor::QUERY)) ) {
|
||||
Fatal("Unable to load monitor id %d for streaming", monitor_id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,13 +81,12 @@ class EventStream : public StreamBase {
|
|||
|
||||
EventData *event_data;
|
||||
|
||||
|
||||
protected:
|
||||
bool loadEventData( uint64_t event_id );
|
||||
bool loadInitialEventData( uint64_t init_event_id, unsigned int init_frame_id );
|
||||
bool loadInitialEventData( int monitor_id, time_t event_time );
|
||||
|
||||
void checkEventLoaded();
|
||||
bool checkEventLoaded();
|
||||
void processCommand( const CmdMsg *msg );
|
||||
bool sendFrame( int delta_us );
|
||||
|
||||
|
@ -99,12 +98,30 @@ class EventStream : public StreamBase {
|
|||
curr_stream_time(0.0),
|
||||
send_frame(false),
|
||||
event_data(0),
|
||||
|
||||
storage(NULL),
|
||||
ffmpeg_input(NULL),
|
||||
// Used when loading frames from an mp4
|
||||
input_codec_context(0),
|
||||
input_codec(0)
|
||||
{}
|
||||
~EventStream() {
|
||||
if ( event_data ) {
|
||||
delete event_data;
|
||||
event_data = NULL;
|
||||
}
|
||||
if ( monitor ) {
|
||||
delete monitor;
|
||||
monitor = NULL;
|
||||
}
|
||||
if ( storage ) {
|
||||
delete storage;
|
||||
storage = NULL;
|
||||
}
|
||||
if ( ffmpeg_input ) {
|
||||
delete ffmpeg_input;
|
||||
ffmpeg_input = NULL;
|
||||
}
|
||||
}
|
||||
void setStreamStart( uint64_t init_event_id, unsigned int init_frame_id );
|
||||
void setStreamStart( int monitor_id, time_t event_time );
|
||||
void setStreamMode( StreamMode p_mode ) {
|
||||
|
@ -113,6 +130,7 @@ class EventStream : public StreamBase {
|
|||
void runStream();
|
||||
Image *getImage();
|
||||
private:
|
||||
Storage *storage;
|
||||
FFmpeg_Input *ffmpeg_input;
|
||||
AVCodecContext *input_codec_context;
|
||||
AVCodec *input_codec;
|
||||
|
|
|
@ -15,10 +15,26 @@ FFmpeg_Input::FFmpeg_Input() {
|
|||
|
||||
FFmpeg_Input::~FFmpeg_Input() {
|
||||
if ( streams ) {
|
||||
for ( unsigned int i = 0; i < input_format_context->nb_streams; i += 1 ) {
|
||||
avcodec_close(streams[i].context);
|
||||
streams[i].context = NULL;
|
||||
}
|
||||
delete streams;
|
||||
streams = NULL;
|
||||
}
|
||||
}
|
||||
if ( frame ) {
|
||||
av_frame_free(&frame);
|
||||
frame = NULL;
|
||||
}
|
||||
if ( input_format_context ) {
|
||||
#if !LIBAVFORMAT_VERSION_CHECK(53, 17, 0, 25, 0)
|
||||
av_close_input_file(input_format_context);
|
||||
#else
|
||||
avformat_close_input(&input_format_context);
|
||||
#endif
|
||||
input_format_context = NULL;
|
||||
}
|
||||
} // end ~FFmpeg_Input()
|
||||
|
||||
int FFmpeg_Input::Open(const char *filepath) {
|
||||
|
||||
|
@ -90,6 +106,7 @@ int FFmpeg_Input::Open(const char *filepath) {
|
|||
avcodec_free_context(&streams[i].context);
|
||||
#endif
|
||||
avformat_close_input(&input_format_context);
|
||||
input_format_context = NULL;
|
||||
return error;
|
||||
}
|
||||
} // end foreach stream
|
||||
|
@ -103,7 +120,6 @@ int FFmpeg_Input::Open(const char *filepath) {
|
|||
} // end int FFmpeg_Input::Open( const char * filepath )
|
||||
|
||||
AVFrame *FFmpeg_Input::get_frame(int stream_id) {
|
||||
|
||||
int frameComplete = false;
|
||||
AVPacket packet;
|
||||
av_init_packet(&packet);
|
||||
|
@ -139,8 +155,8 @@ AVFrame *FFmpeg_Input::get_frame(int stream_id) {
|
|||
}
|
||||
ret = zm_send_packet_receive_frame(context, frame, packet);
|
||||
if ( ret < 0 ) {
|
||||
Error("Unable to decode frame at frame %d: %s, continuing",
|
||||
streams[packet.stream_index].frame_count, av_make_error_string(ret).c_str());
|
||||
Error("Unable to decode frame at frame %d: %d %s, continuing",
|
||||
streams[packet.stream_index].frame_count, ret, av_make_error_string(ret).c_str());
|
||||
zm_av_packet_unref(&packet);
|
||||
av_frame_free(&frame);
|
||||
continue;
|
||||
|
@ -211,15 +227,17 @@ AVFrame *FFmpeg_Input::get_frame(int stream_id, double at) {
|
|||
last_seek_request = seek_target;
|
||||
|
||||
// Seeking seems to typically seek to a keyframe, so then we have to decode until we get the frame we want.
|
||||
if ( frame->pts <= seek_target ) {
|
||||
if ( frame->pts <= seek_target ) {
|
||||
zm_dump_frame(frame, "pts <= seek_target");
|
||||
while ( frame && (frame->pts < seek_target) ) {
|
||||
if ( !get_frame(stream_id) )
|
||||
if ( !get_frame(stream_id) ) {
|
||||
Warning("Got no frame. returning nothing");
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
zm_dump_frame(frame, "frame->pts <= seek_target, got");
|
||||
return frame;
|
||||
}
|
||||
|
||||
return get_frame(stream_id);
|
||||
|
||||
} // end AVFrame *FFmpeg_Input::get_frame( int stream_id, struct timeval at)
|
||||
} // end AVFrame *FFmpeg_Input::get_frame( int stream_id, struct timeval at)
|
||||
|
|
|
@ -48,6 +48,8 @@ static short *g_v_table;
|
|||
static short *g_u_table;
|
||||
static short *b_u_table;
|
||||
|
||||
struct SwsContext *sws_convert_context = NULL;
|
||||
|
||||
jpeg_compress_struct *Image::writejpg_ccinfo[101] = { 0 };
|
||||
jpeg_compress_struct *Image::encodejpg_ccinfo[101] = { 0 };
|
||||
jpeg_decompress_struct *Image::readjpg_dcinfo = 0;
|
||||
|
@ -160,7 +162,7 @@ Image::Image( int p_width, int p_height, int p_colours, int p_subpixelorder, uin
|
|||
update_function_pointers();
|
||||
}
|
||||
|
||||
Image::Image( const AVFrame *frame ) {
|
||||
Image::Image(const AVFrame *frame) {
|
||||
AVFrame *dest_frame = zm_av_frame_alloc();
|
||||
text[0] = '\0';
|
||||
|
||||
|
@ -185,26 +187,28 @@ Image::Image( const AVFrame *frame ) {
|
|||
#endif
|
||||
|
||||
#if HAVE_LIBSWSCALE
|
||||
struct SwsContext *mConvertContext = sws_getContext(
|
||||
sws_convert_context = sws_getCachedContext(
|
||||
sws_convert_context,
|
||||
width,
|
||||
height,
|
||||
(AVPixelFormat)frame->format,
|
||||
width, height,
|
||||
AV_PIX_FMT_RGBA, SWS_BICUBIC, NULL,
|
||||
NULL, NULL);
|
||||
if ( mConvertContext == NULL )
|
||||
Fatal( "Unable to create conversion context" );
|
||||
if ( sws_convert_context == NULL )
|
||||
Fatal("Unable to create conversion context");
|
||||
|
||||
if ( sws_scale(mConvertContext, frame->data, frame->linesize, 0, frame->height, dest_frame->data, dest_frame->linesize) < 0 )
|
||||
if ( sws_scale(sws_convert_context, frame->data, frame->linesize, 0, frame->height,
|
||||
dest_frame->data, dest_frame->linesize) < 0 )
|
||||
Fatal("Unable to convert raw format %u to target format %u", frame->format, AV_PIX_FMT_RGBA);
|
||||
#else // HAVE_LIBSWSCALE
|
||||
Fatal("You must compile ffmpeg with the --enable-swscale option to use ffmpeg cameras");
|
||||
#endif // HAVE_LIBSWSCALE
|
||||
av_frame_free( &dest_frame );
|
||||
av_frame_free(&dest_frame);
|
||||
update_function_pointers();
|
||||
}
|
||||
} // end Image::Image(const AVFrame *frame)
|
||||
|
||||
Image::Image( const Image &p_image ) {
|
||||
Image::Image(const Image &p_image) {
|
||||
if ( !initialised )
|
||||
Initialise();
|
||||
width = p_image.width;
|
||||
|
@ -217,7 +221,7 @@ Image::Image( const Image &p_image ) {
|
|||
holdbuffer = 0;
|
||||
AllocImgBuffer(size);
|
||||
(*fptr_imgbufcpy)(buffer, p_image.buffer, size);
|
||||
strncpy( text, p_image.text, sizeof(text) );
|
||||
strncpy(text, p_image.text, sizeof(text));
|
||||
update_function_pointers();
|
||||
}
|
||||
|
||||
|
@ -227,35 +231,39 @@ Image::~Image() {
|
|||
|
||||
/* Should be called as part of program shutdown to free everything */
|
||||
void Image::Deinitialise() {
|
||||
if ( initialised ) {
|
||||
/*
|
||||
delete[] y_table;
|
||||
delete[] uv_table;
|
||||
delete[] r_v_table;
|
||||
delete[] g_v_table;
|
||||
delete[] g_u_table;
|
||||
delete[] b_u_table;
|
||||
if ( !initialised ) return;
|
||||
/*
|
||||
delete[] y_table;
|
||||
delete[] uv_table;
|
||||
delete[] r_v_table;
|
||||
delete[] g_v_table;
|
||||
delete[] g_u_table;
|
||||
delete[] b_u_table;
|
||||
*/
|
||||
initialised = false;
|
||||
if ( readjpg_dcinfo ) {
|
||||
jpeg_destroy_decompress( readjpg_dcinfo );
|
||||
delete readjpg_dcinfo;
|
||||
readjpg_dcinfo = 0;
|
||||
}
|
||||
if ( decodejpg_dcinfo ) {
|
||||
jpeg_destroy_decompress( decodejpg_dcinfo );
|
||||
delete decodejpg_dcinfo;
|
||||
decodejpg_dcinfo = 0;
|
||||
}
|
||||
for ( unsigned int quality=0; quality <= 100; quality += 1 ) {
|
||||
if ( writejpg_ccinfo[quality] ) {
|
||||
jpeg_destroy_compress( writejpg_ccinfo[quality] );
|
||||
delete writejpg_ccinfo[quality];
|
||||
writejpg_ccinfo[quality] = NULL;
|
||||
}
|
||||
} // end foreach quality
|
||||
initialised = false;
|
||||
if ( readjpg_dcinfo ) {
|
||||
jpeg_destroy_decompress( readjpg_dcinfo );
|
||||
delete readjpg_dcinfo;
|
||||
readjpg_dcinfo = 0;
|
||||
}
|
||||
}
|
||||
if ( decodejpg_dcinfo ) {
|
||||
jpeg_destroy_decompress( decodejpg_dcinfo );
|
||||
delete decodejpg_dcinfo;
|
||||
decodejpg_dcinfo = 0;
|
||||
}
|
||||
for ( unsigned int quality=0; quality <= 100; quality += 1 ) {
|
||||
if ( writejpg_ccinfo[quality] ) {
|
||||
jpeg_destroy_compress( writejpg_ccinfo[quality] );
|
||||
delete writejpg_ccinfo[quality];
|
||||
writejpg_ccinfo[quality] = NULL;
|
||||
}
|
||||
} // end foreach quality
|
||||
|
||||
if ( sws_convert_context ) {
|
||||
sws_freeContext(sws_convert_context);
|
||||
sws_convert_context = NULL;
|
||||
}
|
||||
} // end void Image::Deinitialise()
|
||||
|
||||
void Image::Initialise() {
|
||||
/* Assign the blend pointer to function */
|
||||
|
@ -657,15 +665,16 @@ void Image::Assign( const Image &image ) {
|
|||
return;
|
||||
}
|
||||
|
||||
if ( !buffer || image.width != width || image.height != height || image.colours != colours || image.subpixelorder != subpixelorder) {
|
||||
if ( !buffer || image.width != width || image.height != height
|
||||
|| image.colours != colours || image.subpixelorder != subpixelorder) {
|
||||
|
||||
if (holdbuffer && buffer) {
|
||||
if (new_size > allocation) {
|
||||
if ( holdbuffer && buffer ) {
|
||||
if ( new_size > allocation ) {
|
||||
Error("Held buffer is undersized for assigned buffer");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if(new_size > allocation || !buffer) {
|
||||
if ( new_size > allocation || !buffer) {
|
||||
// DumpImgBuffer(); This is also done in AllocImgBuffer
|
||||
AllocImgBuffer(new_size);
|
||||
}
|
||||
|
|
|
@ -121,7 +121,7 @@ protected:
|
|||
};
|
||||
|
||||
inline void DumpImgBuffer() {
|
||||
DumpBuffer(buffer,buffertype);
|
||||
DumpBuffer(buffer, buffertype);
|
||||
buffer = NULL;
|
||||
allocation = 0;
|
||||
}
|
||||
|
|
|
@ -417,14 +417,14 @@ Monitor::Monitor(
|
|||
|
||||
auto_resume_time = 0;
|
||||
|
||||
if ( strcmp( config.event_close_mode, "time" ) == 0 )
|
||||
if ( strcmp(config.event_close_mode, "time") == 0 )
|
||||
event_close_mode = CLOSE_TIME;
|
||||
else if ( strcmp( config.event_close_mode, "alarm" ) == 0 )
|
||||
else if ( strcmp(config.event_close_mode, "alarm") == 0 )
|
||||
event_close_mode = CLOSE_ALARM;
|
||||
else
|
||||
event_close_mode = CLOSE_IDLE;
|
||||
|
||||
Debug( 1, "monitor purpose=%d", purpose );
|
||||
Debug(1, "monitor purpose=%d", purpose);
|
||||
|
||||
mem_size = sizeof(SharedData)
|
||||
+ sizeof(TriggerData)
|
||||
|
@ -444,17 +444,15 @@ Monitor::Monitor(
|
|||
storage = new Storage(storage_id);
|
||||
Debug(1, "Storage path: %s", storage->Path());
|
||||
// Should maybe store this for later use
|
||||
char monitor_dir[PATH_MAX] = "";
|
||||
char monitor_dir[PATH_MAX];
|
||||
snprintf(monitor_dir, sizeof(monitor_dir), "%s/%d", storage->Path(), id);
|
||||
|
||||
if ( purpose == CAPTURE ) {
|
||||
if ( mkdir(monitor_dir, 0755) ) {
|
||||
if ( errno != EEXIST ) {
|
||||
Error("Can't mkdir %s: %s", monitor_dir, strerror(errno));
|
||||
}
|
||||
if ( mkdir(monitor_dir, 0755) && ( errno != EEXIST ) ) {
|
||||
Error("Can't mkdir %s: %s", monitor_dir, strerror(errno));
|
||||
}
|
||||
|
||||
if ( ! this->connect() ) {
|
||||
if ( !this->connect() ) {
|
||||
Error("unable to connect, but doing capture");
|
||||
exit(-1);
|
||||
}
|
||||
|
@ -490,20 +488,16 @@ Monitor::Monitor(
|
|||
video_store_data->size = sizeof(VideoStoreData);
|
||||
//video_store_data->frameNumber = 0;
|
||||
} else if ( purpose == ANALYSIS ) {
|
||||
if ( ! ( this->connect() && mem_ptr ) ) exit(-1);
|
||||
if ( ! (this->connect() && mem_ptr && shared_data->valid) ) {
|
||||
Error("Shared data not initialised by capture daemon for monitor %s", name);
|
||||
exit(-1);
|
||||
}
|
||||
shared_data->state = IDLE;
|
||||
shared_data->last_read_time = 0;
|
||||
shared_data->alarm_x = -1;
|
||||
shared_data->alarm_y = -1;
|
||||
}
|
||||
|
||||
if ( ( ! mem_ptr ) || ! shared_data->valid ) {
|
||||
if ( purpose != QUERY ) {
|
||||
Error("Shared data not initialised by capture daemon for monitor %s", name);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
start_time = last_fps_time = time( 0 );
|
||||
|
||||
event = 0;
|
||||
|
@ -549,9 +543,8 @@ Monitor::Monitor(
|
|||
FifoStream::fifo_create_if_missing(diag_path_d.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
} // end if purpose == ANALYSIS
|
||||
} // Monitor::Monitor
|
||||
} // end if purpose == ANALYSIS
|
||||
} // Monitor::Monitor
|
||||
|
||||
bool Monitor::connect() {
|
||||
Debug(3, "Connecting to monitor. Purpose is %d", purpose );
|
||||
|
|
|
@ -114,7 +114,7 @@ bool StreamBase::checkCommandQueue() {
|
|||
return false;
|
||||
}
|
||||
|
||||
Image *StreamBase::prepareImage( Image *image ) {
|
||||
Image *StreamBase::prepareImage(Image *image) {
|
||||
|
||||
// Do not bother to scale zoomed in images, just crop them and let the browser scale
|
||||
// Works in FF2 but breaks FF3 which doesn't like image sizes changing in mid stream.
|
||||
|
@ -124,50 +124,51 @@ Image *StreamBase::prepareImage( Image *image ) {
|
|||
|
||||
int mag = (scale * zoom) / ZM_SCALE_BASE;
|
||||
int act_mag = optimisedScaling?(mag > ZM_SCALE_BASE?ZM_SCALE_BASE:mag):mag;
|
||||
Debug( 3, "Scaling by %d, zooming by %d = magnifying by %d(%d)", scale, zoom, mag, act_mag );
|
||||
|
||||
int last_mag = (last_scale * last_zoom) / ZM_SCALE_BASE;
|
||||
int last_act_mag = last_mag > ZM_SCALE_BASE?ZM_SCALE_BASE:last_mag;
|
||||
Debug( 3, "Last scaling by %d, zooming by %d = magnifying by %d(%d)", last_scale, last_zoom, last_mag, last_act_mag );
|
||||
|
||||
int base_image_width = image->Width(), base_image_height = image->Height();
|
||||
Debug( 3, "Base image width = %d, height = %d", base_image_width, base_image_height );
|
||||
|
||||
int virt_image_width = (base_image_width * mag) / ZM_SCALE_BASE, virt_image_height = (base_image_height * mag) / ZM_SCALE_BASE;
|
||||
Debug( 3, "Virtual image width = %d, height = %d", virt_image_width, virt_image_height );
|
||||
|
||||
int last_virt_image_width = (base_image_width * last_mag) / ZM_SCALE_BASE, last_virt_image_height = (base_image_height * last_mag) / ZM_SCALE_BASE;
|
||||
Debug( 3, "Last virtual image width = %d, height = %d", last_virt_image_width, last_virt_image_height );
|
||||
|
||||
int act_image_width = (base_image_width * act_mag ) / ZM_SCALE_BASE, act_image_height = (base_image_height * act_mag ) / ZM_SCALE_BASE;
|
||||
Debug( 3, "Actual image width = %d, height = %d", act_image_width, act_image_height );
|
||||
|
||||
int last_act_image_width = (base_image_width * last_act_mag ) / ZM_SCALE_BASE, last_act_image_height = (base_image_height * last_act_mag ) / ZM_SCALE_BASE;
|
||||
Debug( 3, "Last actual image width = %d, height = %d", last_act_image_width, last_act_image_height );
|
||||
|
||||
int disp_image_width = (image->Width() * scale) / ZM_SCALE_BASE, disp_image_height = (image->Height() * scale) / ZM_SCALE_BASE;
|
||||
Debug( 3, "Display image width = %d, height = %d", disp_image_width, disp_image_height );
|
||||
|
||||
int last_disp_image_width = (image->Width() * last_scale) / ZM_SCALE_BASE, last_disp_image_height = (image->Height() * last_scale) / ZM_SCALE_BASE;
|
||||
Debug( 3, "Last display image width = %d, height = %d", last_disp_image_width, last_disp_image_height );
|
||||
|
||||
int send_image_width = (disp_image_width * act_mag ) / mag, send_image_height = (disp_image_height * act_mag ) / mag;
|
||||
Debug( 3, "Send image width = %d, height = %d", send_image_width, send_image_height );
|
||||
|
||||
int last_send_image_width = (last_disp_image_width * last_act_mag ) / last_mag, last_send_image_height = (last_disp_image_height * last_act_mag ) / last_mag;
|
||||
Debug( 3, "Last send image width = %d, height = %d", last_send_image_width, last_send_image_height );
|
||||
|
||||
if ( mag != ZM_SCALE_BASE ) {
|
||||
if ( act_mag != ZM_SCALE_BASE ) {
|
||||
Debug(3, "Magnifying by %d", mag);
|
||||
if ( !image_copied ) {
|
||||
static Image copy_image;
|
||||
copy_image.Assign(*image);
|
||||
image = ©_image;
|
||||
image_copied = true;
|
||||
}
|
||||
image->Scale(mag);
|
||||
}
|
||||
Debug(3,
|
||||
"Scaling by %d, zooming by %d = magnifying by %d(%d)\n"
|
||||
"Last scaling by %d, zooming by %d = magnifying by %d(%d)\n"
|
||||
"Base image width = %d, height = %d\n"
|
||||
"Virtual image width = %d, height = %d\n"
|
||||
"Last virtual image width = %d, height = %d\n"
|
||||
"Actual image width = %d, height = %d\n"
|
||||
"Last actual image width = %d, height = %d\n"
|
||||
"Display image width = %d, height = %d\n"
|
||||
"Last display image width = %d, height = %d\n"
|
||||
"Send image width = %d, height = %d\n"
|
||||
"Last send image width = %d, height = %d\n",
|
||||
scale, zoom, mag, act_mag,
|
||||
last_scale, last_zoom, last_mag, last_act_mag,
|
||||
base_image_width, base_image_height,
|
||||
virt_image_width, virt_image_height,
|
||||
last_virt_image_width, last_virt_image_height,
|
||||
act_image_width, act_image_height,
|
||||
last_act_image_width, last_act_image_height,
|
||||
disp_image_width, disp_image_height,
|
||||
last_disp_image_width, last_disp_image_height,
|
||||
send_image_width, send_image_height,
|
||||
last_send_image_width, last_send_image_height
|
||||
);
|
||||
|
||||
if ( ( mag != ZM_SCALE_BASE ) && (act_mag != ZM_SCALE_BASE) ) {
|
||||
Debug(3, "Magnifying by %d", mag);
|
||||
static Image copy_image;
|
||||
copy_image.Assign(*image);
|
||||
image = ©_image;
|
||||
image_copied = true;
|
||||
image->Scale(mag);
|
||||
}
|
||||
|
||||
Debug(3, "Real image width = %d, height = %d", image->Width(), image->Height());
|
||||
|
@ -176,26 +177,22 @@ Image *StreamBase::prepareImage( Image *image ) {
|
|||
static Box last_crop;
|
||||
|
||||
if ( mag != last_mag || x != last_x || y != last_y ) {
|
||||
Debug( 3, "Got click at %d,%d x %d", x, y, mag );
|
||||
|
||||
//if ( !last_mag )
|
||||
//last_mag = mag;
|
||||
Debug(3, "Got click at %d,%d x %d", x, y, mag);
|
||||
|
||||
if ( !(last_disp_image_width < last_virt_image_width || last_disp_image_height < last_virt_image_height) )
|
||||
last_crop = Box();
|
||||
|
||||
Debug( 3, "Recalculating crop" );
|
||||
// Recalculate crop parameters, as %ges
|
||||
int click_x = (last_crop.LoX() * 100 ) / last_act_image_width; // Initial crop offset from last image
|
||||
click_x += ( x * 100 ) / last_virt_image_width;
|
||||
int click_y = (last_crop.LoY() * 100 ) / last_act_image_height; // Initial crop offset from last image
|
||||
click_y += ( y * 100 ) / last_virt_image_height;
|
||||
Debug( 3, "Got adjusted click at %d%%,%d%%", click_x, click_y );
|
||||
Debug(3, "Got adjusted click at %d%%,%d%%", click_x, click_y);
|
||||
|
||||
// Convert the click locations to the current image pixels
|
||||
click_x = ( click_x * act_image_width ) / 100;
|
||||
click_y = ( click_y * act_image_height ) / 100;
|
||||
Debug( 3, "Got readjusted click at %d,%d", click_x, click_y );
|
||||
Debug(3, "Got readjusted click at %d,%d", click_x, click_y);
|
||||
|
||||
int lo_x = click_x - (send_image_width/2);
|
||||
if ( lo_x < 0 )
|
||||
|
@ -214,23 +211,25 @@ Image *StreamBase::prepareImage( Image *image ) {
|
|||
lo_y = hi_y - (send_image_height - 1);
|
||||
}
|
||||
last_crop = Box( lo_x, lo_y, hi_x, hi_y );
|
||||
}
|
||||
Debug( 3, "Cropping to %d,%d -> %d,%d", last_crop.LoX(), last_crop.LoY(), last_crop.HiX(), last_crop.HiY() );
|
||||
} // end if ( mag != last_mag || x != last_x || y != last_y )
|
||||
|
||||
Debug(3, "Cropping to %d,%d -> %d,%d", last_crop.LoX(), last_crop.LoY(), last_crop.HiX(), last_crop.HiY());
|
||||
if ( !image_copied ) {
|
||||
static Image copy_image;
|
||||
copy_image.Assign( *image );
|
||||
copy_image.Assign(*image);
|
||||
image = ©_image;
|
||||
image_copied = true;
|
||||
}
|
||||
image->Crop( last_crop );
|
||||
}
|
||||
image->Crop(last_crop);
|
||||
} // end if difference in image vs displayed dimensions
|
||||
|
||||
last_scale = scale;
|
||||
last_zoom = zoom;
|
||||
last_x = x;
|
||||
last_y = y;
|
||||
|
||||
return image;
|
||||
}
|
||||
} // end Image *StreamBase::prepareImage(Image *image)
|
||||
|
||||
bool StreamBase::sendTextFrame(const char *frame_text) {
|
||||
Debug(2, "Sending %dx%d * %d text frame '%s'",
|
||||
|
|
152
src/zm_user.cpp
152
src/zm_user.cpp
|
@ -115,12 +115,13 @@ User *zmLoadUser(const char *username, const char *password) {
|
|||
" `MonitorIds`"
|
||||
" FROM `Users` WHERE `Username` = '%s' AND `Enabled` = 1",
|
||||
safer_username);
|
||||
delete safer_username;
|
||||
safer_username = NULL;
|
||||
|
||||
if ( mysql_query(&dbconn, sql) ) {
|
||||
Error("Can't run query: %s", mysql_error(&dbconn));
|
||||
exit(mysql_errno(&dbconn));
|
||||
}
|
||||
delete safer_username;
|
||||
|
||||
MYSQL_RES *result = mysql_store_result(&dbconn);
|
||||
if ( !result ) {
|
||||
|
@ -128,29 +129,24 @@ User *zmLoadUser(const char *username, const char *password) {
|
|||
exit(mysql_errno(&dbconn));
|
||||
}
|
||||
|
||||
if ( mysql_num_rows(result) != 1 ) {
|
||||
if ( mysql_num_rows(result) == 1 ) {
|
||||
MYSQL_ROW dbrow = mysql_fetch_row(result);
|
||||
User *user = new User(dbrow);
|
||||
mysql_free_result(result);
|
||||
Warning("Unable to authenticate user %s", username);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MYSQL_ROW dbrow = mysql_fetch_row(result);
|
||||
User *user = new User(dbrow);
|
||||
if (
|
||||
(! password ) // relay type must be none
|
||||
||
|
||||
verifyPassword(username, password, user->getPassword()) ) {
|
||||
Info("Authenticated user '%s'", user->getUsername());
|
||||
return user;
|
||||
}
|
||||
} // end if 1 result from db
|
||||
mysql_free_result(result);
|
||||
|
||||
if ( !password ) {
|
||||
// relay type must be none
|
||||
return user;
|
||||
}
|
||||
|
||||
if ( verifyPassword(username, password, user->getPassword()) ) {
|
||||
Info("Authenticated user '%s'", user->getUsername());
|
||||
return user;
|
||||
}
|
||||
|
||||
Warning("Unable to authenticate user %s", username);
|
||||
return NULL;
|
||||
}
|
||||
} // end User *zmLoadUser(const char *username, const char *password)
|
||||
|
||||
User *zmLoadTokenUser(std::string jwt_token_str, bool use_remote_addr) {
|
||||
std::string key = config.auth_hash_secret;
|
||||
|
@ -172,53 +168,50 @@ User *zmLoadTokenUser(std::string jwt_token_str, bool use_remote_addr) {
|
|||
unsigned int iat = ans.second;
|
||||
Debug(1, "retrieved user '%s' from token", username.c_str());
|
||||
|
||||
if ( username != "" ) {
|
||||
char sql[ZM_SQL_MED_BUFSIZ] = "";
|
||||
snprintf(sql, sizeof(sql),
|
||||
"SELECT `Id`, `Username`, `Password`, `Enabled`,"
|
||||
" `Stream`+0, `Events`+0, `Control`+0, `Monitors`+0, `System`+0,"
|
||||
" `MonitorIds`, `TokenMinExpiry`"
|
||||
" FROM `Users` WHERE `Username` = '%s' AND `Enabled` = 1",
|
||||
username.c_str());
|
||||
|
||||
if ( mysql_query(&dbconn, sql) ) {
|
||||
Error("Can't run query: %s", mysql_error(&dbconn));
|
||||
exit(mysql_errno(&dbconn));
|
||||
}
|
||||
|
||||
MYSQL_RES *result = mysql_store_result(&dbconn);
|
||||
if ( !result ) {
|
||||
Error("Can't use query result: %s", mysql_error(&dbconn));
|
||||
exit(mysql_errno(&dbconn));
|
||||
}
|
||||
int n_users = mysql_num_rows(result);
|
||||
|
||||
if ( n_users != 1 ) {
|
||||
mysql_free_result(result);
|
||||
Error("Unable to authenticate user '%s'", username.c_str());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MYSQL_ROW dbrow = mysql_fetch_row(result);
|
||||
User *user = new User(dbrow);
|
||||
unsigned int stored_iat = strtoul(dbrow[10], NULL, 0);
|
||||
|
||||
if ( stored_iat > iat ) { // admin revoked tokens
|
||||
mysql_free_result(result);
|
||||
Error("Token was revoked for '%s'", username.c_str());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Debug(1, "Authenticated user '%s' via token with last revoke time: %u",
|
||||
username.c_str(), stored_iat);
|
||||
mysql_free_result(result);
|
||||
return user;
|
||||
|
||||
} else {
|
||||
if ( username == "" ) {
|
||||
return NULL;
|
||||
}
|
||||
} // end User *zmLoadTokenUser(std::string jwt_token_str, bool use_remote_addr)
|
||||
|
||||
char sql[ZM_SQL_MED_BUFSIZ] = "";
|
||||
snprintf(sql, sizeof(sql),
|
||||
"SELECT `Id`, `Username`, `Password`, `Enabled`, `Stream`+0, `Events`+0,"
|
||||
" `Control`+0, `Monitors`+0, `System`+0, `MonitorIds`, `TokenMinExpiry`"
|
||||
" FROM `Users` WHERE `Username` = '%s' AND `Enabled` = 1", username.c_str());
|
||||
|
||||
if ( mysql_query(&dbconn, sql) ) {
|
||||
Error("Can't run query: %s", mysql_error(&dbconn));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MYSQL_RES *result = mysql_store_result(&dbconn);
|
||||
if ( !result ) {
|
||||
Error("Can't use query result: %s", mysql_error(&dbconn));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int n_users = mysql_num_rows(result);
|
||||
if ( n_users != 1 ) {
|
||||
mysql_free_result(result);
|
||||
Error("Unable to authenticate user '%s'", username.c_str());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MYSQL_ROW dbrow = mysql_fetch_row(result);
|
||||
User *user = new User(dbrow);
|
||||
unsigned int stored_iat = strtoul(dbrow[10], NULL, 0);
|
||||
|
||||
if ( stored_iat > iat ) { // admin revoked tokens
|
||||
mysql_free_result(result);
|
||||
Error("Token was revoked for '%s'", username.c_str());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Debug(1, "Authenticated user '%s' via token with last revoke time: %u",
|
||||
username.c_str(), stored_iat);
|
||||
mysql_free_result(result);
|
||||
return user;
|
||||
} // User *zmLoadTokenUser(std::string jwt_token_str, bool use_remote_addr)
|
||||
|
||||
// Function to validate an authentication string
|
||||
User *zmLoadAuthUser(const char *auth, bool use_remote_addr) {
|
||||
#if HAVE_DECL_MD5 || HAVE_DECL_GNUTLS_FINGERPRINT
|
||||
|
@ -255,36 +248,33 @@ User *zmLoadAuthUser(const char *auth, bool use_remote_addr) {
|
|||
MYSQL_RES *result = mysql_store_result(&dbconn);
|
||||
if ( !result ) {
|
||||
Error("Can't use query result: %s", mysql_error(&dbconn));
|
||||
exit(mysql_errno(&dbconn));
|
||||
return NULL;
|
||||
}
|
||||
int n_users = mysql_num_rows(result);
|
||||
|
||||
if ( n_users < 1 ) {
|
||||
mysql_free_result(result);
|
||||
Warning("Unable to authenticate user");
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
time_t now = time(0);
|
||||
unsigned int hours = config.auth_hash_ttl;
|
||||
if ( ! hours ) {
|
||||
Warning("No value set for ZM_AUTH_HASH_TTL. Defaulting to 2.");
|
||||
hours = 2;
|
||||
} else {
|
||||
Debug(1, "AUTH_HASH_TTL is %d", hours);
|
||||
}
|
||||
char auth_key[512] = "";
|
||||
char auth_md5[32+1] = "";
|
||||
size_t md5len = 16;
|
||||
unsigned char md5sum[md5len];
|
||||
|
||||
const char * hex = "0123456789abcdef";
|
||||
while ( MYSQL_ROW dbrow = mysql_fetch_row(result) ) {
|
||||
const char *user = dbrow[1];
|
||||
const char *pass = dbrow[2];
|
||||
|
||||
char auth_key[512] = "";
|
||||
char auth_md5[32+1] = "";
|
||||
size_t md5len = 16;
|
||||
unsigned char md5sum[md5len];
|
||||
|
||||
time_t now = time(0);
|
||||
unsigned int hours = config.auth_hash_ttl;
|
||||
|
||||
if ( !hours ) {
|
||||
Warning("No value set for ZM_AUTH_HASH_TTL. Defaulting to 2.");
|
||||
hours = 2;
|
||||
} else {
|
||||
Debug(1, "AUTH_HASH_TTL is %d", hours);
|
||||
}
|
||||
|
||||
for ( unsigned int i = 0; i < hours; i++, now -= 3600 ) {
|
||||
struct tm *now_tm = localtime(&now);
|
||||
|
||||
|
@ -332,7 +322,7 @@ User *zmLoadAuthUser(const char *auth, bool use_remote_addr) {
|
|||
Error("You need to build with gnutls or openssl to use hash based auth");
|
||||
#endif // HAVE_DECL_MD5 || HAVE_DECL_GNUTLS_FINGERPRINT
|
||||
Debug(1, "No user found for auth_key %s", auth);
|
||||
return 0;
|
||||
return NULL;
|
||||
} // end User *zmLoadAuthUser( const char *auth, bool use_remote_addr )
|
||||
|
||||
// Function to check Username length
|
||||
|
|
|
@ -53,7 +53,7 @@ void Zone::Setup(
|
|||
|
||||
id = p_id;
|
||||
label = new char[strlen(p_label)+1];
|
||||
strcpy( label, p_label );
|
||||
strcpy(label, p_label);
|
||||
type = p_type;
|
||||
polygon = p_polygon;
|
||||
alarm_rgb = p_alarm_rgb;
|
||||
|
@ -89,10 +89,10 @@ void Zone::Setup(
|
|||
overload_count = 0;
|
||||
extend_alarm_count = 0;
|
||||
|
||||
pg_image = new Image( monitor->Width(), monitor->Height(), 1, ZM_SUBPIX_ORDER_NONE );
|
||||
pg_image = new Image(monitor->Width(), monitor->Height(), 1, ZM_SUBPIX_ORDER_NONE);
|
||||
pg_image->Clear();
|
||||
pg_image->Fill( 0xff, polygon );
|
||||
pg_image->Outline( 0xff, polygon );
|
||||
pg_image->Fill(0xff, polygon);
|
||||
pg_image->Outline(0xff, polygon);
|
||||
|
||||
ranges = new Range[monitor->Height()];
|
||||
for ( unsigned int y = 0; y < monitor->Height(); y++ ) {
|
||||
|
@ -113,8 +113,10 @@ void Zone::Setup(
|
|||
}
|
||||
|
||||
if ( config.record_diag_images ) {
|
||||
snprintf(diag_path, sizeof(diag_path), config.record_diag_images_fifo ? "%s/diagpipe-%d-poly.jpg" : "%s/diag-%d-poly.jpg", monitor->getStorage()->Path(), id);
|
||||
if (config.record_diag_images_fifo)
|
||||
snprintf(diag_path, sizeof(diag_path),
|
||||
config.record_diag_images_fifo ? "%s/diagpipe-%d-poly.jpg" : "%s/diag-%d-poly.jpg",
|
||||
monitor->getStorage()->Path(), id);
|
||||
if ( config.record_diag_images_fifo )
|
||||
FifoStream::fifo_create_if_missing(diag_path);
|
||||
pg_image->WriteJpeg(diag_path, config.record_diag_images_fifo);
|
||||
} else {
|
||||
|
|
24
src/zms.cpp
24
src/zms.cpp
|
@ -184,7 +184,7 @@ int main(int argc, const char *argv[]) {
|
|||
logInit(log_id_string);
|
||||
|
||||
if ( config.opt_use_auth ) {
|
||||
User *user = 0;
|
||||
User *user = NULL;
|
||||
|
||||
if ( jwt_token_str != "" ) {
|
||||
// user = zmLoadTokenUser(jwt_token_str, config.auth_hash_ips);
|
||||
|
@ -195,19 +195,11 @@ int main(int argc, const char *argv[]) {
|
|||
} else {
|
||||
Error("Bad username");
|
||||
}
|
||||
|
||||
} else {
|
||||
// if ( strcmp( config.auth_relay, "hashed" ) == 0 )
|
||||
{
|
||||
if ( *auth ) {
|
||||
user = zmLoadAuthUser(auth, config.auth_hash_ips);
|
||||
}
|
||||
}
|
||||
// else if ( strcmp( config.auth_relay, "plain" ) == 0 )
|
||||
{
|
||||
if ( username.length() && password.length() ) {
|
||||
user = zmLoadUser(username.c_str(), password.c_str());
|
||||
}
|
||||
if ( *auth ) {
|
||||
user = zmLoadAuthUser(auth, config.auth_hash_ips);
|
||||
} else if ( username.length() && password.length() ) {
|
||||
user = zmLoadUser(username.c_str(), password.c_str());
|
||||
}
|
||||
}
|
||||
if ( !user ) {
|
||||
|
@ -218,11 +210,15 @@ int main(int argc, const char *argv[]) {
|
|||
return 0;
|
||||
}
|
||||
if ( !ValidateAccess(user, monitor_id) ) {
|
||||
delete user;
|
||||
user = NULL;
|
||||
fputs("HTTP/1.0 403 Forbidden\r\n\r\n", stdout);
|
||||
logTerm();
|
||||
zmDbClose();
|
||||
return 0;
|
||||
}
|
||||
delete user;
|
||||
user = NULL;
|
||||
} // end if config.opt_use_auth
|
||||
|
||||
hwcaps_detect();
|
||||
|
@ -336,5 +332,5 @@ int main(int argc, const char *argv[]) {
|
|||
logTerm();
|
||||
zmDbClose();
|
||||
|
||||
return(0);
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue