diff --git a/src/zm_analysis_thread.cpp b/src/zm_analysis_thread.cpp index 1836cf6b1..7d803c16b 100644 --- a/src/zm_analysis_thread.cpp +++ b/src/zm_analysis_thread.cpp @@ -2,7 +2,7 @@ #include "zm_monitor.h" #include "zm_signal.h" -#include "zm_utils.h" +#include "zm_time.h" AnalysisThread::AnalysisThread(Monitor *monitor) : monitor_(monitor), terminate_(false) { diff --git a/src/zm_event.cpp b/src/zm_event.cpp index cd75ffbb7..32cb95f76 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -237,35 +237,37 @@ Event::~Event() { Warning("Empty endtime for event. Should not happen. Setting to now."); gettimeofday(&end_time, nullptr); } - struct DeltaTimeval delta_time; - DELTA_TIMEVAL(delta_time, end_time, start_time, DT_PREC_2); + + std::chrono::duration delta_time = + zm::chrono::duration_cast(end_time) - zm::chrono::duration_cast(start_time); Debug(2, "start_time: %" PRIi64 ".% " PRIi64 " end_time: %" PRIi64 ".%" PRIi64, static_cast(start_time.tv_sec), static_cast(start_time.tv_usec), static_cast(end_time.tv_sec), static_cast(end_time.tv_usec)); - if (frame_data.size()) WriteDbFrames(); + if (frame_data.size()){ + WriteDbFrames(); + } - // Should not be static because we might be multi-threaded - char sql[ZM_SQL_LGE_BUFSIZ]; - snprintf(sql, sizeof(sql), - "UPDATE Events SET Name='%s%" PRIu64 "', EndDateTime = from_unixtime(%ld), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d WHERE Id = %" PRIu64 " AND Name='New Event'", + std::string sql = stringtf( + "UPDATE Events SET Name='%s%" PRIu64 "', EndDateTime = from_unixtime(%ld), Length = %.2f, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d WHERE Id = %" PRIu64 " AND Name='New Event'", monitor->EventPrefix(), id, end_time.tv_sec, - delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, + delta_time.count(), frames, alarm_frames, - tot_score, (int)(alarm_frames?(tot_score/alarm_frames):0), max_score, + tot_score, static_cast(alarm_frames ? (tot_score / alarm_frames) : 0), max_score, id); - if (!zmDbDoUpdate(sql)) { + + if (!zmDbDoUpdate(sql.c_str())) { // Name might have been changed during recording, so just do the update without changing the name. - snprintf(sql, sizeof(sql), - "UPDATE Events SET EndDateTime = from_unixtime(%ld), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d WHERE Id = %" PRIu64, + sql = stringtf( + "UPDATE Events SET EndDateTime = from_unixtime(%ld), Length = %.2f, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d WHERE Id = %" PRIu64, end_time.tv_sec, - delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, + delta_time.count(), frames, alarm_frames, - tot_score, (int)(alarm_frames?(tot_score/alarm_frames):0), max_score, + tot_score, static_cast(alarm_frames ? (tot_score / alarm_frames) : 0), max_score, id); - zmDbDoUpdate(sql); + zmDbDoUpdate(sql.c_str()); } // end if no changed rows due to Name change during recording } // Event::~Event() @@ -578,53 +580,56 @@ void Event::AddFrame( or ( monitor_state == Monitor::PREALARM ); if (db_frame) { - - struct DeltaTimeval delta_time; - DELTA_TIMEVAL(delta_time, timestamp, start_time, DT_PREC_2); - Debug(1, "Frame delta is %" PRIi64 ".%" PRIi64 " - %" PRIi64 ".%" PRIi64 " = %lu.%lu, score %u zone_stats.size %zu", + std::chrono::duration delta_time = + zm::chrono::duration_cast(timestamp) - zm::chrono::duration_cast(start_time); + Debug(1, "Frame delta is %" PRIi64 ".%" PRIi64 " - %" PRIi64 ".%" PRIi64 " = %.2f, score %u zone_stats.size %zu", static_cast(start_time.tv_sec), static_cast(start_time.tv_usec), static_cast(timestamp.tv_sec), static_cast(timestamp.tv_usec), - delta_time.sec, delta_time.fsec, + delta_time.count(), score, zone_stats.size()); + Milliseconds delta_time_ms = std::chrono::duration_cast(delta_time); // The idea is to write out 1/sec - frame_data.push(new Frame(id, frames, frame_type, timestamp, delta_time, score, zone_stats)); + frame_data.push(new Frame(id, + frames, + frame_type, + timestamp, + zm::chrono::duration_cast(delta_time_ms), + score, + zone_stats)); double fps = monitor->get_capture_fps(); - if ( write_to_db - or - ( frame_data.size() >= MAX_DB_FRAMES ) - or - ( frame_type == BULK ) - or - ( fps and (frame_data.size() > fps) ) - ) { - Debug(1, "Adding %zu frames to DB because write_to_db:%d or frames > analysis fps %f or BULK(%d)", - frame_data.size(), write_to_db, fps, (frame_type == BULK)); + if (write_to_db + or + (frame_data.size() >= MAX_DB_FRAMES) + or + (frame_type == BULK) + or + (fps and (frame_data.size() > fps))) { + Debug(1, "Adding %zu frames to DB because write_to_db:%d or frames > analysis fps %f or BULK(%d)", + frame_data.size(), write_to_db, fps, (frame_type == BULK)); WriteDbFrames(); last_db_frame = frames; - char sql[ZM_SQL_MED_BUFSIZ]; - snprintf(sql, sizeof(sql), - "UPDATE Events SET Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d WHERE Id = %" PRIu64, - ( delta_time.positive?"":"-" ), - delta_time.sec, delta_time.fsec, - frames, + std::string sql = stringtf( + "UPDATE Events SET Length = %.2f, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d WHERE Id = %" PRIu64, + delta_time.count(), + frames, alarm_frames, tot_score, - (int)(alarm_frames?(tot_score/alarm_frames):0), + static_cast(alarm_frames ? (tot_score / alarm_frames) : 0), max_score, - id - ); + id); dbQueue.push(std::move(sql)); - } else { - Debug(1, "Not Adding %zu frames to DB because write_to_db:%d or frames > analysis fps %f or BULK", - frame_data.size(), write_to_db, fps); + } else { + Debug(1, "Not Adding %zu frames to DB because write_to_db:%d or frames > analysis fps %f or BULK", + frame_data.size(), write_to_db, fps); } // end if frame_type == BULK } // end if db_frame - if (score > (int)max_score) + if (score > (int) max_score) { max_score = score; + } end_time = timestamp; } // end void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *alarm_image) diff --git a/src/zm_frame.cpp b/src/zm_frame.cpp index f6c0e296d..79873efd0 100644 --- a/src/zm_frame.cpp +++ b/src/zm_frame.cpp @@ -4,7 +4,7 @@ Frame::Frame(event_id_t p_event_id, int p_frame_id, FrameType p_type, struct timeval p_timestamp, - struct DeltaTimeval &p_delta, + const DeltaTimeval &p_delta, int p_score, std::vector p_stats) : event_id(p_event_id), diff --git a/src/zm_frame.h b/src/zm_frame.h index 8f5a7e9cc..05f49791c 100644 --- a/src/zm_frame.h +++ b/src/zm_frame.h @@ -42,7 +42,7 @@ class Frame { int p_frame_id, FrameType p_type, struct timeval p_timestamp, - struct DeltaTimeval &p_delta, + const DeltaTimeval &p_delta, int p_score, std::vector p_stats ); diff --git a/src/zm_monitorstream.cpp b/src/zm_monitorstream.cpp index f7ff0fea5..a9fead28b 100644 --- a/src/zm_monitorstream.cpp +++ b/src/zm_monitorstream.cpp @@ -391,12 +391,16 @@ bool MonitorStream::sendFrame(Image *image, const timeval ×tamp) { fprintf(stdout, "Content-type: %s\r\n\r\n", vid_stream->MimeType()); vid_stream->OpenStream(); } + static struct timeval base_time; - struct DeltaTimeval delta_time; - if ( !frame_count ) + Milliseconds delta_time = + zm::chrono::duration_cast(timestamp) - zm::chrono::duration_cast(base_time); + + if (!frame_count) { base_time = timestamp; - DELTA_TIMEVAL(delta_time, timestamp, base_time, DT_PREC_3); - /* double pts = */ vid_stream->EncodeFrame(send_image->Buffer(), send_image->Size(), config.mpeg_timed_frames, delta_time.delta); + } + + /* double pts = */ vid_stream->EncodeFrame(send_image->Buffer(), send_image->Size(), config.mpeg_timed_frames, delta_time.count()); } else { static unsigned char temp_img_buffer[ZM_MAX_IMAGE_SIZE]; diff --git a/src/zm_time.h b/src/zm_time.h index 5a54bea46..c5e7fe75e 100644 --- a/src/zm_time.h +++ b/src/zm_time.h @@ -20,7 +20,8 @@ #ifndef ZM_TIME_H #define ZM_TIME_H -#include +#include "zm_logger.h" +#include #include // Structure used for storing the results of the subtraction @@ -50,28 +51,6 @@ struct DeltaTimeval #define DT_MAXGRAN DT_GRAN_1000000 -// This obviously wouldn't work for massive deltas but as it's mostly -// for frames it will only usually be a fraction of a second or so -#define DELTA_TIMEVAL( result, time1, time2, precision ) \ -{ \ - int delta = (((time1).tv_sec-(time2).tv_sec)*(precision))+(((time1).tv_usec-(time2).tv_usec)/(DT_MAXGRAN/(precision))); \ - result.positive = (delta>=0); \ - result.delta = abs(delta); \ - result.sec = result.delta/(precision); \ - result.fsec = result.delta%(precision); \ - result.prec = (precision); \ -} - -#define TIMEVAL_INTERVAL( result, time1, time2, precision ) \ -{ \ - int delta = (((time1).tv_sec-(time2).tv_sec)*(precision))+(((time1).tv_usec-(time2).tv_usec)/(DT_MAXGRAN/(precision))); \ - result.positive = (delta>=0); \ - result.delta = abs(delta); \ - result.sec = result.delta/(precision); \ - result.fsec = result.delta%(precision); \ - result.prec = (precision); \ -} - #define USEC_PER_SEC 1000000 #define MSEC_PER_SEC 1000 @@ -205,4 +184,89 @@ inline struct timeval tvMake( time_t sec, suseconds_t usec ) return( t ); } +typedef std::chrono::microseconds Microseconds; +typedef std::chrono::milliseconds Milliseconds; +typedef std::chrono::seconds Seconds; +typedef std::chrono::minutes Minutes; +typedef std::chrono::hours Hours; + +typedef std::chrono::steady_clock::time_point TimePoint; +typedef std::chrono::system_clock::time_point SystemTimePoint; + +namespace zm { +namespace chrono { +namespace impl { + +template +struct posix_duration_cast; + +// chrono -> timeval caster +template +struct posix_duration_cast, timeval> { + static timeval cast(std::chrono::duration const &d) { + timeval tv = {}; + + Seconds const sec = std::chrono::duration_cast(d); + + tv.tv_sec = sec.count(); + tv.tv_usec = std::chrono::duration_cast(d - sec).count(); + + return tv; + } +}; + +// timeval -> chrono caster +template +struct posix_duration_cast> { + static std::chrono::duration cast(timeval const &tv) { + return std::chrono::duration_cast>( + Seconds(tv.tv_sec) + Microseconds(tv.tv_usec) + ); + } +}; + +// chrono -> DeltaTimeval caster +template +struct posix_duration_cast, DeltaTimeval> { + template + static DeltaTimeval cast(std::chrono::duration const &d) { + typedef std::chrono::duration> fsec_t; + DeltaTimeval res = {}; + + Seconds secs = std::chrono::duration_cast(d); + fsec_t fsec = std::chrono::duration_cast>(d - secs); + + res.positive = fsec >= Seconds::zero(); + res.delta = abs((secs + fsec).count()); + res.sec = secs.count(); + res.fsec = fsec.count(); + res.prec = Prec; + + return res; + } +}; +} + +// chrono -> timeval +template +auto duration_cast(std::chrono::duration const &d) +-> typename std::enable_if::value, timeval>::type { + return impl::posix_duration_cast, timeval>::cast(d); +} + +// timeval -> chrono +template +Duration duration_cast(timeval const &tv) { + return impl::posix_duration_cast::cast(tv); +} + +// chrono -> DeltaTimeval +template +auto duration_cast(std::chrono::duration const &d) +-> typename std::enable_if::value, DeltaTimeval>::type { + return impl::posix_duration_cast, DeltaTimeval>::template cast(d); +} +} +} + #endif // ZM_TIME_H diff --git a/src/zm_utils.h b/src/zm_utils.h index 8ca58a22b..2d5ffb58e 100644 --- a/src/zm_utils.h +++ b/src/zm_utils.h @@ -136,15 +136,6 @@ template constexpr std::size_t size(const T(&)[N]) noexcept { return N; } } -typedef std::chrono::microseconds Microseconds; -typedef std::chrono::milliseconds Milliseconds; -typedef std::chrono::seconds Seconds; -typedef std::chrono::minutes Minutes; -typedef std::chrono::hours Hours; - -typedef std::chrono::steady_clock::time_point TimePoint; -typedef std::chrono::system_clock::time_point SystemTimePoint; - std::string UriDecode(const std::string &encoded); class QueryParameter { diff --git a/src/zmc.cpp b/src/zmc.cpp index 7ba91aa30..a266ebd23 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -286,8 +286,7 @@ int main(int argc, char *argv[]) { capture_delays[i], alarm_capture_delays[i]); } - struct timeval now; - struct DeltaTimeval delta_time; + timeval now; int sleep_time = 0; while (!zm_terminate) { @@ -319,19 +318,19 @@ int main(int argc, char *argv[]) { if (delay) { gettimeofday(&now, nullptr); if (last_capture_times[i].tv_sec) { - // DT_PREC_3 means that the value will be in thousands of a second - DELTA_TIMEVAL(delta_time, now, last_capture_times[i], DT_PREC_6); + Microseconds delta_time = zm::chrono::duration_cast(now) + - zm::chrono::duration_cast(last_capture_times[i]); // You have to add back in the previous sleep time - sleep_time = delay - (delta_time.delta - sleep_time); + sleep_time = delay - (delta_time.count() - sleep_time); Debug(4, - "Sleep time is %d from now: %" PRIi64 ".%" PRIi64" last: %" PRIi64 ".% " PRIi64 " delta %lu delay: %d", + "Sleep time is %d from now: %" PRIi64 ".%" PRIi64" last: %" PRIi64 ".% " PRIi64 " delta % " PRIi64 " delay: %d", sleep_time, static_cast(now.tv_sec), static_cast(now.tv_usec), static_cast(last_capture_times[i].tv_sec), static_cast(last_capture_times[i].tv_usec), - delta_time.delta, + static_cast(delta_time.count()), delay); if (sleep_time > 0) {