pull/3122/head
Isaac Connor 2017-11-20 15:32:40 -05:00
parent c70a9f665a
commit 43b71fc49b
10 changed files with 148 additions and 129 deletions

View File

@ -81,7 +81,7 @@ use constant EVENT_PATH => ($Config{ZM_DIR_EVENTS}=~m|/|)
? $Config{ZM_DIR_EVENTS}
: ($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS})
;
use constant ZM_AUDIT_PID => $Config{ZM_RUNDIR}.'/zm.pid'
use constant ZM_AUDIT_PID => '@ZM_RUNDIR@/zmaudit.pid';
$| = 1;

View File

@ -579,7 +579,6 @@ Image * EventStream::getImage( ) {
Debug( 2, "EventStream::getImage path(%s) frame(%d)", event_data->path, curr_frame_id );
snprintf( filepath, sizeof(filepath), staticConfig.capture_file_format, event_data->path, curr_frame_id );
Debug( 2, "EventStream::getImage path(%s) ", filepath, curr_frame_id );
Image *image = new Image( filepath );
return image;
}
@ -657,7 +656,7 @@ bool EventStream::sendFrame( int delta_us ) {
} else if ( ffmpeg_input ) {
// Get the frame from the mp4 input
Debug(1,"Getting frame from ffmpeg");
AVFrame *frame = ffmpeg_input->get_frame( ffmpeg_input->get_video_stream_id() );
AVFrame *frame = ffmpeg_input->get_frame( ffmpeg_input->get_video_stream_id(), curr_frame_id );
if ( frame ) {
image = new Image( frame );
av_frame_free(&frame);

View File

@ -373,3 +373,48 @@ bool is_audio_stream( AVStream * stream ) {
}
return false;
}
int zm_receive_frame( AVCodecContext *context, AVFrame *frame, AVPacket &packet ) {
int ret;
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
if ( (ret = avcodec_send_packet(context, &packet)) < 0 ) {
Error( "Unable to send packet %s, continuing",
av_make_error_string(ret).c_str() );
return 0;
}
#if HAVE_AVUTIL_HWCONTEXT_H
if ( hwaccel ) {
if ( (ret = avcodec_receive_frame(context, hwFrame)) < 0 ) {
Error( "Unable to receive frame %d: %s, continuing", streams[packet.stream_index].frame_count,
av_make_error_string(ret).c_str() );
return 0;
}
if ( (ret = av_hwframe_transfer_data(frame, hwFrame, 0)) < 0 ) {
Error( "Unable to transfer frame at frame %d: %s, continuing", streams[packet.stream_index].frame_count,
av_make_error_string(ret).c_str() );
return 0;
}
} else {
#endif
if ( (ret = avcodec_receive_frame(context, frame)) < 0 ) {
Error( "Unable to send packet %s, continuing", av_make_error_string(ret).c_str() );
return 0;
}
#if HAVE_AVUTIL_HWCONTEXT_H
}
#endif
# else
int frameComplete;
while ( !frameComplete ) {
if ( (ret = zm_avcodec_decode_video( context, frame, &frameComplete, &packet )) < 0 ) {
Error( "Unable to decode frame at frame %d: %s, continuing",
streams[packet.stream_index].frame_count,
av_make_error_string(ret).c_str() );
return 0;
}
}
#endif
return 1;
} // end int zm_receive_frame( AVCodecContext *context, AVFrame *frame, AVPacket &packet )

View File

@ -237,9 +237,8 @@ enum _AVPIXELFORMAT GetFFMPEGPixelFormat(unsigned int p_colours, unsigned p_subp
*/
#ifdef __cplusplus
inline static const std::string av_make_error_string(int errnum)
{
char errbuf[AV_ERROR_MAX_STRING_SIZE];
inline static const std::string av_make_error_string(int errnum) {
static char errbuf[AV_ERROR_MAX_STRING_SIZE];
#if LIBAVUTIL_VERSION_CHECK(50, 13, 0, 13, 0)
av_strerror(errnum, errbuf, AV_ERROR_MAX_STRING_SIZE);
#else
@ -327,4 +326,5 @@ int check_sample_fmt(AVCodec *codec, enum AVSampleFormat sample_fmt);
bool is_video_stream( AVStream * stream );
bool is_audio_stream( AVStream * stream );
int zm_receive_frame( AVCodecContext *context, AVFrame *frame, AVPacket &packet );
#endif // ZM_FFMPEG_H

View File

@ -13,6 +13,9 @@ FFmpeg_Input::FFmpeg_Input() {
}
FFmpeg_Input::~FFmpeg_Input() {
if ( input_format_context ) {
Close();
}
if ( streams ) {
delete streams;
streams = NULL;
@ -25,7 +28,6 @@ int FFmpeg_Input::Open( const char *filepath ) {
/** Open the input file to read from it. */
if ( (error = avformat_open_input( &input_format_context, filepath, NULL, NULL)) < 0 ) {
Error("Could not open input file '%s' (error '%s')\n",
filepath, av_make_error_string(error).c_str() );
input_format_context = NULL;
@ -94,94 +96,73 @@ int FFmpeg_Input::Open( const char *filepath ) {
return 0;
} // end int FFmpeg_Input::Open( const char * filepath )
AVFrame *FFmpeg_Input::get_frame( int stream_id ) {
Debug(1, "Getting frame from stream %d", stream_id );
int FFmpeg_Input::Close( ) {
for ( unsigned int i = 0; i < input_format_context->nb_streams; i += 1 ) {
if ( streams[i].context ) {
avcodec_close( streams[i].context );
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
avcodec_free_context(& streams[i].context );
#endif
streams[i].context = 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;
}
return 1;
} // end int FFmpeg_Input::Close()
AVFrame *FFmpeg_Input::get_frame( int stream_id, int frame_number ) {
Debug(1, "Getting frame from stream %d, frame_number(%d)", stream_id, frame_number );
int frameComplete = false;
AVPacket packet;
av_init_packet( &packet );
AVFrame *frame = zm_av_frame_alloc();
char errbuf[AV_ERROR_MAX_STRING_SIZE];
while ( !frameComplete ) {
while ( frame_number >= streams[stream_id].frame_count ) {
int ret = av_read_frame(input_format_context, &packet);
if ( ret < 0 ) {
av_strerror(ret, errbuf, AV_ERROR_MAX_STRING_SIZE);
if (
// Check if EOF.
(ret == AVERROR_EOF || (input_format_context->pb && input_format_context->pb->eof_reached)) ||
// Check for Connection failure.
(ret == -110)
) {
Info( "av_read_frame returned %s.", errbuf );
return NULL;
Info( "av_read_frame returned %s.", av_make_error_string(ret).c_str() );
} else {
Error( "Unable to read packet from stream %d: error %d \"%s\".", packet.stream_index, ret,
av_make_error_string(ret).c_str() );
}
Error( "Unable to read packet from stream %d: error %d \"%s\".", packet.stream_index, ret, errbuf );
return NULL;
}
if ( (stream_id < 0 ) || ( packet.stream_index == stream_id ) ) {
Debug(1,"Packet is for our stream (%d)", packet.stream_index );
if ( ( stream_id < 0 ) || ( packet.stream_index != stream_id ) ) {
Warning("Packet is not for our stream (%d)", packet.stream_index);
return NULL;
}
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
AVCodecContext *context = streams[packet.stream_index].context;
ret = avcodec_send_packet( context, &packet );
if ( ret < 0 ) {
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
Error( "Unable to send packet at frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf );
if ( ! zm_receive_frame( streams[packet.stream_index].context, frame, packet ) ) {
Error("Unable to get frame %d, continuing", streams[packet.stream_index].frame_count);
zm_av_packet_unref( &packet );
continue;
} else {
Debug(1, "Success getting a packet");
Debug(1, "Success getting a packet at frame (%d)", streams[packet.stream_index].frame_count);
streams[packet.stream_index].frame_count += 1;
}
#if HAVE_AVUTIL_HWCONTEXT_H
if ( hwaccel ) {
ret = avcodec_receive_frame( context, hwFrame );
if ( ret < 0 ) {
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
Error( "Unable to receive frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf );
zm_av_packet_unref( &packet );
continue;
}
ret = av_hwframe_transfer_data(frame, hwFrame, 0);
if (ret < 0) {
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
Error( "Unable to transfer frame at frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf );
zm_av_packet_unref( &packet );
continue;
}
} else {
#endif
Debug(1,"Getting a frame?");
ret = avcodec_receive_frame( context, frame );
if ( ret < 0 ) {
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
Error( "Unable to send packet at frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf );
zm_av_packet_unref( &packet );
continue;
}
#if HAVE_AVUTIL_HWCONTEXT_H
}
#endif
frameComplete = 1;
# else
ret = zm_avcodec_decode_video( context, frame, &frameComplete, &packet );
if ( ret < 0 ) {
av_strerror( ret, errbuf, AV_ERROR_MAX_STRING_SIZE );
Error( "Unable to decode frame at frame %d: %s, continuing", streams[packet.stream_index].frame_count, errbuf );
zm_av_packet_unref( &packet );
continue;
}
#endif
} // end if it's the right stream
zm_av_packet_unref( &packet );
} // end while ! frameComplete
if ( frame_number == -1 )
break;
} // end while frame_number > streams.frame_count
return frame;
} // end AVFrame *FFmpeg_Input::get_frame

View File

@ -21,7 +21,7 @@ class FFmpeg_Input {
int Open( const char *filename );
int Close();
AVFrame *get_frame( int stream_id=-1 );
AVFrame *get_frame( int stream_id=-1, int frame_number=-1 );
int get_video_stream_id() {
return video_stream_id;
}

View File

@ -1216,7 +1216,7 @@ bool Monitor::Analyse() {
// if have event, sent frames until we find a video packet, at which point do analysis. Adaptive skip should only affect which frames we do analysis on.
int skip_index = 0;
unsigned int skip_index = 0;
if ( adaptive_skip ) {
int read_margin = shared_data->last_read_index - shared_data->last_write_index;
@ -1295,6 +1295,7 @@ bool Monitor::Analyse() {
Debug(3, "Motion detection is enabled signal(%d) signal_change(%d)", signal, signal_change);
// if we have been told to be OFF, then we are off and don't do any processing.
if ( trigger_data->trigger_state != TRIGGER_OFF ) {
Debug(4, "Trigger not oFF state is (%d)", trigger_data->trigger_state );
unsigned int score = 0;
@ -1304,8 +1305,8 @@ Debug(4, "Ready");
std::string cause;
Event::StringSetMap noteSetMap;
// Specifically told to be on. Setting the score here will trigger the alarm.
if ( trigger_data->trigger_state == TRIGGER_ON ) {
score += trigger_data->trigger_score;
if ( !event ) {
if ( cause.length() )
@ -1372,7 +1373,6 @@ Debug(3,"before DetectMotion");
// If we aren't recording, check linked monitors to see if we should be.
if ( (!(signal_change && signal)) && (n_linked_monitors > 0) ) {
bool first_link = true;
Event::StringSet noteSet;
for ( int i=0; i < n_linked_monitors; i++ ) {
if ( ! linked_monitors[i]->isConnected() )
@ -1434,6 +1434,7 @@ Debug(3,"before DetectMotion");
}
} // end if ! event
}
if ( score ) {
Debug(9, "Score: (%d)", score );
if ( (state == IDLE || state == TAPE || state == PREALARM ) ) {
@ -1520,7 +1521,7 @@ Debug(3, "creating new event");
shared_data->state = state = ALARM;
}
last_alarm_count = image_count;
} else {
} else { // no score?
if ( state == ALARM ) {
Info( "%s: %03d - Gone into alert state", name, image_count );
shared_data->state = state = ALERT;
@ -1536,17 +1537,14 @@ Debug(3, "creating new event");
shared_data->state = state = TAPE;
}
}
}
if ( state == PREALARM ) {
if ( function != MOCORD ) {
shared_data->state = state = IDLE;
} else {
shared_data->state = state = TAPE;
}
} else if ( state == PREALARM ) {
// Back to IDLE
shared_data->state = state = function != MOCORD ? IDLE : TAPE;
}
if ( Event::PreAlarmCount() )
Event::EmptyPreAlarmFrames();
}
} // end if score or not
if ( state != IDLE ) {
if ( state == PREALARM || state == ALARM ) {
if ( config.create_analysis_images ) {
@ -1565,6 +1563,7 @@ Debug(3, "creating new event");
}
if ( got_anal_image ) {
if ( state == PREALARM )
// AddPreAlarmFrame just copies/buffers these frames in the event. If we go back to idle, we will drop them.
Event::AddPreAlarmFrame( snap_image, *timestamp, score, &alarm_image );
else
//event->AddFrame( snap_image, *timestamp, score, &alarm_image );
@ -1593,22 +1592,16 @@ Debug(3, "creating new event");
if ( event && noteSetMap.size() > 0 )
event->updateNotes( noteSetMap );
} else if ( state == ALERT ) {
event->AddFrame( snap_image, *timestamp );
// Alert means this frame has no motion, but we were alarmed and are still recording.
event->AddPacket( snap );
if ( noteSetMap.size() > 0 )
event->updateNotes( noteSetMap );
} else if ( state == TAPE ) {
//Video Storage: activate only for supported cameras. Event::AddFrame knows whether or not we are recording video and saves frames accordingly
//if((GetOptVideoWriter() == 2) && camera->SupportsNativeVideo()) {
// I don't think this is required, and causes problems, as the event file hasn't been setup yet.
//Warning("In state TAPE,
//video_store_data->recording = event->StartTime();
//}
if ( !(image_count%(frame_skip+1)) ) {
if ( config.bulk_frame_interval > 1 ) {
event->AddPacket( snap, (event->Frames()<pre_event_count?0:-1) );
//event->AddFrame( snap_image, *timestamp, (event->Frames()<pre_event_count?0:-1) );
} else {
//event->AddFrame( snap_image, *timestamp );
event->AddPacket( snap );
}
}

View File

@ -285,7 +285,7 @@ protected:
int ready_count;
int first_alarm_count;
int last_alarm_count;
static bool last_signal;
bool last_signal;
int buffer_count;
int prealarm_count;
State state;
@ -294,7 +294,6 @@ protected:
time_t last_analysis_fps_time;
time_t auto_resume_time;
unsigned int last_motion_score;
bool last_signal;
EventCloseMode event_close_mode;

View File

@ -148,7 +148,7 @@ User *zmLoadAuthUser( const char *auth, bool use_remote_addr ) {
}
}
Debug( 1, "Attempting to authenticate user from auth string '%s'", auth );
Debug( 1, "Attempting to authenticate user from auth string '%s', remote addr(%s)", auth, remote_addr );
char sql[ZM_SQL_SML_BUFSIZ] = "";
snprintf( sql, sizeof(sql), "SELECT Username, Password, Enabled, Stream+0, Events+0, Control+0, Monitors+0, System+0, MonitorIds FROM Users WHERE Enabled = 1" );
@ -170,6 +170,17 @@ User *zmLoadAuthUser( const char *auth, bool use_remote_addr ) {
return( 0 );
}
// getting the time is expensive, so only do it once.
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, time is %d", hours, now );
}
while( MYSQL_ROW dbrow = mysql_fetch_row( result ) ) {
const char *user = dbrow[0];
const char *pass = dbrow[1];
@ -179,18 +190,9 @@ User *zmLoadAuthUser( const char *auth, bool use_remote_addr ) {
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 );
time_t now_copy = now;
for ( unsigned int i = 0; i < hours; i++, now_copy -= 3600 ) {
struct tm *now_tm = localtime(&now_copy);
snprintf( auth_key, sizeof(auth_key), "%s%s%s%s%d%d%d%d",
config.auth_hash_secret,
@ -221,11 +223,10 @@ User *zmLoadAuthUser( const char *auth, bool use_remote_addr ) {
Debug(1, "Authenticated user '%s'", user->getUsername() );
mysql_free_result( result );
return( user );
} else {
}
} // end foreach hours
} // end foreach user
Debug(1, "No match for %s", auth );
}
}
}
mysql_free_result( result );
#else // HAVE_DECL_MD5
Error( "You need to build with gnutls or openssl installed to use hash based authentication" );

View File

@ -138,26 +138,27 @@ function getAuthUser( $auth ) {
$authHash = md5( $authKey );
if ( $auth == $authHash ) {
return( $user );
return $user;
}
} // end foreach hour
} // end foreach user
} // end if using auth hash
Error( "Unable to authenticate user from auth hash '$auth'" );
return( false );
}
} // end getAuthUser($auth)
function generateAuthHash( $useRemoteAddr ) {
if ( ZM_OPT_USE_AUTH and ZM_AUTH_RELAY == 'hashed' and isset($_SESSION['username']) and $_SESSION['passwordHash'] ) {
# regenerate a hash at half the liftetime of a hash, an hour is 3600 so half is 1800
if ( ( ! isset($_SESSION['AuthHash']) ) or ( $_SESSION['AuthHashGeneratedAt'] < time() - ( ZM_AUTH_HASH_TTL * 1800 ) ) ) {
$time = time();
if ( ( ! isset($_SESSION['AuthHash']) ) or ( $_SESSION['AuthHashGeneratedAt'] < ( $time - ( ZM_AUTH_HASH_TTL * 1800 ) ) ) ) {
# Don't both regenerating Auth Hash if an hour hasn't gone by yet
$time = localtime();
$local_time = localtime();
$authKey = '';
if ( $useRemoteAddr ) {
$authKey = ZM_AUTH_HASH_SECRET.$_SESSION['username'].$_SESSION['passwordHash'].$_SESSION['remoteAddr'].$time[2].$time[3].$time[4].$time[5];
$authKey = ZM_AUTH_HASH_SECRET.$_SESSION['username'].$_SESSION['passwordHash'].$_SESSION['remoteAddr'].$local_time[2].$local_time[3].$local_time[4].$local_time[5];
} else {
$authKey = ZM_AUTH_HASH_SECRET.$_SESSION['username'].$_SESSION['passwordHash'].$time[2].$time[3].$time[4].$time[5];
$authKey = ZM_AUTH_HASH_SECRET.$_SESSION['username'].$_SESSION['passwordHash'].$local_time[2].$local_time[3].$local_time[4].$local_time[5];
}
$auth = md5( $authKey );
if ( session_status() == PHP_SESSION_NONE ) {
@ -167,10 +168,10 @@ function generateAuthHash( $useRemoteAddr ) {
Warning("Session is not active. AuthHash will not be cached. called from $file:$line");
}
$_SESSION['AuthHash'] = $auth;
$_SESSION['AuthHashGeneratedAt'] = time();
$_SESSION['AuthHashGeneratedAt'] = $time;
Logger::Debug("Generated new auth $auth at " . $_SESSION['AuthHashGeneratedAt']. " using $authKey" );
} else {
Logger::Debug( "Using cached auth " . $_SESSION['AuthHash'] );
Logger::Debug( "Using cached auth " . $_SESSION['AuthHash'] ." beacuse " . $_SESSION['AuthHashGeneratedAt'] . ' < '. $time . ' - ' . ZM_AUTH_HASH_TTL . ' * 1800 = '.( $time - (ZM_AUTH_HASH_TTL * 1800) ));
} # end if AuthHash is not cached
return $_SESSION['AuthHash'];
} else {