diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 49a89b60b..283e2bde3 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -578,17 +578,16 @@ void Event::AddFrame( SystemTimePoint timestamp_us = SystemTimePoint(zm::chrono::duration_cast(timestamp)); if (db_frame) { - FPSeconds delta_time = timestamp_us - start_time; - Debug(1, "Frame delta is %.2f - %.2f = %.2f, score %u zone_stats.size %zu", - std::chrono::duration_cast(timestamp_us.time_since_epoch()).count(), - std::chrono::duration_cast(start_time.time_since_epoch()).count(), - delta_time.count(), + Microseconds delta_time = std::chrono::duration_cast(timestamp_us - start_time); + Debug(1, "Frame delta is %.2f s - %.2f s = %.2f s, score %u zone_stats.size %zu", + FPSeconds(timestamp_us.time_since_epoch()).count(), + FPSeconds(start_time.time_since_epoch()).count(), + FPSeconds(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_ms, score, zone_stats)); + frame_data.push(new Frame(id, frames, frame_type, timestamp, delta_time, score, zone_stats)); double fps = monitor->get_capture_fps(); if (write_to_db or @@ -604,7 +603,7 @@ void Event::AddFrame( 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(), + FPSeconds(delta_time).count(), frames, alarm_frames, tot_score, diff --git a/src/zm_eventstream.cpp b/src/zm_eventstream.cpp index 25949624d..6c18940d2 100644 --- a/src/zm_eventstream.cpp +++ b/src/zm_eventstream.cpp @@ -27,7 +27,6 @@ #include "zm_storage.h" #include #include -#include #ifdef __FreeBSD__ #include @@ -40,7 +39,9 @@ const std::string EventStream::StreamMode_Strings[4] = { "Gapless" }; -bool EventStream::loadInitialEventData(int monitor_id, time_t event_time) { +constexpr Milliseconds EventStream::STREAM_PAUSE_WAIT; + +bool EventStream::loadInitialEventData(int monitor_id, SystemTimePoint event_time) { std::string sql = stringtf("SELECT `Id` FROM `Events` WHERE " "`MonitorId` = %d AND unix_timestamp(`EndDateTime`) > %ld " "ORDER BY `Id` ASC LIMIT 1", monitor_id, event_time); @@ -62,23 +63,26 @@ bool EventStream::loadInitialEventData(int monitor_id, time_t event_time) { loadEventData(init_event_id); - if ( event_time ) { + if (event_time.time_since_epoch() == Seconds(0)) { curr_stream_time = event_time; curr_frame_id = 1; // curr_frame_id is 1-based - if ( event_time >= event_data->start_time ) { + if (event_time >= event_data->start_time) { Debug(2, "event time is after event start"); - for ( unsigned int i = 0; i < event_data->frame_count; i++ ) { + for (unsigned int i = 0; i < event_data->frame_count; i++) { //Info( "eft %d > et %d", event_data->frames[i].timestamp, event_time ); - if ( event_data->frames[i].timestamp >= event_time ) { - curr_frame_id = i+1; - Debug(3, "Set curr_stream_time:%.2f, curr_frame_id:%ld", curr_stream_time, curr_frame_id); + if (event_data->frames[i].timestamp >= event_time) { + curr_frame_id = i + 1; + Debug(3, "Set curr_stream_time: %.2f, curr_frame_id: %ld", + FPSeconds(curr_stream_time.time_since_epoch()).count(), + curr_frame_id); break; } } // end foreach frame Debug(3, "Skipping %ld frames", event_data->frame_count); } else { Warning("Requested an event time less than the start of the event. event_time %" PRIi64 " < start_time %" PRIi64, - static_cast(event_time), static_cast(event_data->start_time)); + static_cast(std::chrono::duration_cast(event_time.time_since_epoch()).count()), + static_cast(std::chrono::duration_cast(event_data->start_time.time_since_epoch()).count())); } } // end if have a start time return true; @@ -136,11 +140,12 @@ bool EventStream::loadEventData(uint64_t event_id) { event_data->monitor_id = atoi(dbrow[0]); event_data->storage_id = dbrow[1] ? atoi(dbrow[1]) : 0; event_data->frame_count = dbrow[2] == nullptr ? 0 : atoi(dbrow[2]); - event_data->start_time = atoi(dbrow[3]); - event_data->end_time = dbrow[4] ? atoi(dbrow[4]) : 0; - event_data->duration = event_data->end_time - event_data->start_time; - event_data->frames_duration = dbrow[5] ? atof(dbrow[5]) : 0.0; - strncpy(event_data->video_file, dbrow[6], sizeof(event_data->video_file)-1); + event_data->start_time = SystemTimePoint(Seconds(atoi(dbrow[3]))); + event_data->end_time = dbrow[4] ? SystemTimePoint(Seconds(atoi(dbrow[4]))) : SystemTimePoint(); + event_data->duration = std::chrono::duration_cast(event_data->end_time - event_data->start_time); + event_data->frames_duration = + std::chrono::duration_cast(dbrow[5] ? FPSeconds(atof(dbrow[5])) : FPSeconds(0.0)); + strncpy(event_data->video_file, dbrow[6], sizeof(event_data->video_file) - 1); std::string scheme_str = std::string(dbrow[7]); if ( scheme_str == "Deep" ) { event_data->scheme = Storage::DEEP; @@ -172,7 +177,8 @@ bool EventStream::loadEventData(uint64_t event_id) { if ( event_data->scheme == Storage::DEEP ) { tm event_time = {}; - localtime_r(&event_data->start_time, &event_time); + time_t start_time_t = std::chrono::system_clock::to_time_t(event_data->start_time); + localtime_r(&start_time_t, &event_time); if ( storage_path[0] == '/' ) snprintf(event_data->path, sizeof(event_data->path), @@ -188,7 +194,9 @@ bool EventStream::loadEventData(uint64_t event_id) { event_time.tm_hour, event_time.tm_min, event_time.tm_sec); } else if ( event_data->scheme == Storage::MEDIUM ) { tm event_time = {}; - localtime_r(&event_data->start_time, &event_time); + time_t start_time_t = std::chrono::system_clock::to_time_t(event_data->start_time); + localtime_r(&start_time_t, &event_time); + if ( storage_path[0] == '/' ) snprintf(event_data->path, sizeof(event_data->path), "%s/%u/%04d-%02d-%02d/%" PRIu64, @@ -212,7 +220,11 @@ bool EventStream::loadEventData(uint64_t event_id) { event_data->event_id); } - updateFrameRate((event_data->frame_count and event_data->duration) ? (double)event_data->frame_count/event_data->duration : 1); + double fps = 1.0; + if ((event_data->frame_count and event_data->duration != Seconds(0))) { + fps = static_cast(event_data->frame_count) / FPSeconds(event_data->duration).count(); + } + updateFrameRate(fps); sql = stringtf("SELECT `FrameId`, unix_timestamp(`TimeStamp`), `Delta` " "FROM `Frames` WHERE `EventId` = %" PRIu64 " ORDER BY `FrameId` ASC", event_id); @@ -226,46 +238,47 @@ bool EventStream::loadEventData(uint64_t event_id) { event_data->frames = new FrameData[event_data->frame_count]; int last_id = 0; - double last_timestamp = event_data->start_time; - double last_delta = 0.0; + SystemTimePoint last_timestamp = event_data->start_time; + Microseconds last_delta = Seconds(0); while ( ( dbrow = mysql_fetch_row(result) ) ) { int id = atoi(dbrow[0]); //timestamp = atof(dbrow[1]); - double delta = atof(dbrow[2]); + Microseconds delta = std::chrono::duration_cast(FPSeconds(atof(dbrow[2]))); int id_diff = id - last_id; - double frame_delta = id_diff ? (delta-last_delta)/id_diff : (delta-last_delta); + Microseconds frame_delta = + std::chrono::duration_cast(id_diff ? (delta - last_delta) / id_diff : (delta - last_delta)); + // Fill in data between bulk frames - if ( id_diff > 1 ) { - for ( int i = last_id+1; i < id; i++ ) { + if (id_diff > 1) { + for (int i = last_id + 1; i < id; i++) { // Delta is the time since last frame, no since beginning of Event - event_data->frames[i-1].delta = frame_delta; - 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)", - i, - event_data->frames[i-1].timestamp, - event_data->frames[i-1].offset, - event_data->frames[i-1].delta, - event_data->frames[i-1].in_db - ); + event_data->frames[i - 1].delta = frame_delta; + event_data->frames[i - 1].timestamp = last_timestamp + ((i - last_id) * frame_delta); + event_data->frames[i - 1].offset = + std::chrono::duration_cast(event_data->frames[i - 1].timestamp - event_data->start_time); + event_data->frames[i - 1].in_db = false; + Debug(3, "Frame %d timestamp (%f s), offset (%f s) delta (%f s), in_db (%d)", + i, + FPSeconds(event_data->frames[i - 1].timestamp.time_since_epoch()).count(), + FPSeconds(event_data->frames[i - 1].offset).count(), + FPSeconds(event_data->frames[i - 1].delta).count(), + event_data->frames[i - 1].in_db); } } - event_data->frames[id-1].timestamp = event_data->start_time + delta; - event_data->frames[id-1].offset = delta; - event_data->frames[id-1].delta = frame_delta; - event_data->frames[id-1].in_db = true; + event_data->frames[id - 1].timestamp = event_data->start_time + delta; + event_data->frames[id - 1].offset = delta; + event_data->frames[id - 1].delta = frame_delta; + event_data->frames[id - 1].in_db = true; last_id = id; last_delta = delta; last_timestamp = event_data->frames[id-1].timestamp; - 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, - event_data->frames[id-1].delta, - event_data->frames[id-1].in_db - ); + Debug(3, "Frame %d timestamp (%f s), offset (%f s), delta(%f s), in_db(%d)", + id, + FPSeconds(event_data->frames[id - 1].timestamp.time_since_epoch()).count(), + FPSeconds(event_data->frames[id - 1].offset).count(), + FPSeconds(event_data->frames[id - 1].delta).count(), + event_data->frames[id - 1].in_db); } // Incomplete events might not have any frame data event_data->last_frame_id = last_id; @@ -300,8 +313,12 @@ bool EventStream::loadEventData(uint64_t event_id) { else curr_stream_time = event_data->frames[event_data->last_frame_id-1].timestamp; } - Debug(2, "Event:%" PRIu64 ", Frames:%ld, Last Frame ID(%ld, Duration: %.2f Frames Duration: %.2f", - event_data->event_id, event_data->frame_count, event_data->last_frame_id, event_data->duration, event_data->frames_duration); + Debug(2, "Event: %" PRIu64 ", Frames: %ld, Last Frame ID (%ld, Duration: %.2f s Frames Duration: %.2f s", + event_data->event_id, + event_data->frame_count, + event_data->last_frame_id, + FPSeconds(event_data->duration).count(), + FPSeconds(event_data->frames_duration).count()); return true; } // bool EventStream::loadEventData( int event_id ) @@ -316,7 +333,7 @@ void EventStream::processCommand(const CmdMsg *msg) { // Set paused flag paused = true; replay_rate = ZM_RATE_BASE; - last_frame_sent = TV_2_FLOAT(now); + last_frame_sent = now; break; case CMD_PLAY : Debug(1, "Got PLAY command"); @@ -503,25 +520,25 @@ void EventStream::processCommand(const CmdMsg *msg) { break; case CMD_SEEK : { - // offset is in seconds + double int_part = ((unsigned char) msg->msg_data[1] << 24) | ((unsigned char) msg->msg_data[2] << 16) + | ((unsigned char) msg->msg_data[3] << 8) | (unsigned char) msg->msg_data[4]; + double dec_part = ((unsigned char) msg->msg_data[5] << 24) | ((unsigned char) msg->msg_data[6] << 16) + | ((unsigned char) msg->msg_data[7] << 8) | (unsigned char) msg->msg_data[8]; - int int_part = ((unsigned char)msg->msg_data[1]<<24)|((unsigned char)msg->msg_data[2]<<16)|((unsigned char)msg->msg_data[3]<<8)|(unsigned char)msg->msg_data[4]; - int dec_part = ((unsigned char)msg->msg_data[5]<<24)|((unsigned char)msg->msg_data[6]<<16)|((unsigned char)msg->msg_data[7]<<8)|(unsigned char)msg->msg_data[8]; - - double offset = (double)int_part + (double)(dec_part / (double)1000000); - if ( offset < 0.0 ) { + FPSeconds offset = FPSeconds(int_part + dec_part / 1000000.0); + if (offset < Seconds(0)) { Warning("Invalid offset, not seeking"); break; } + // This should get us close, but not all frames will have the same duration - curr_frame_id = (int)(event_data->frame_count*offset/event_data->duration)+1; - if ( event_data->frames[curr_frame_id-1].offset > offset ) { - while ( (curr_frame_id --) && ( event_data->frames[curr_frame_id-1].offset > offset ) ) { - } - } else if ( event_data->frames[curr_frame_id-1].offset < offset ) { - while ( (curr_frame_id ++) && ( event_data->frames[curr_frame_id-1].offset > offset ) ) { - } + curr_frame_id = (int) (event_data->frame_count * offset / event_data->duration) + 1; + if (event_data->frames[curr_frame_id - 1].offset > offset) { + while ((curr_frame_id--) && (event_data->frames[curr_frame_id - 1].offset > offset)) {} + } else if (event_data->frames[curr_frame_id - 1].offset < offset) { + while ((curr_frame_id++) && (event_data->frames[curr_frame_id - 1].offset > offset)) {} } + if ( curr_frame_id < 1 ) { curr_frame_id = 1; } else if ( (unsigned long)curr_frame_id > event_data->last_frame_id ) { @@ -529,8 +546,10 @@ void EventStream::processCommand(const CmdMsg *msg) { } curr_stream_time = event_data->frames[curr_frame_id-1].timestamp; - Debug(1, "Got SEEK command, to %f (new current frame id: %ld offset %f)", - offset, curr_frame_id, event_data->frames[curr_frame_id-1].offset); + Debug(1, "Got SEEK command, to %f s (new current frame id: %ld offset %f s)", + FPSeconds(offset).count(), + curr_frame_id, + FPSeconds(event_data->frames[curr_frame_id - 1].offset).count()); send_frame = true; break; } @@ -547,12 +566,12 @@ void EventStream::processCommand(const CmdMsg *msg) { struct { uint64_t event_id; - double duration; - double progress; + Microseconds duration; + Microseconds progress; int rate; int zoom; bool paused; - } status_data; + } status_data = {}; status_data.event_id = event_data->event_id; status_data.duration = event_data->duration; @@ -561,13 +580,12 @@ void EventStream::processCommand(const CmdMsg *msg) { status_data.zoom = zoom; status_data.paused = paused; Debug(2, "Event:%" PRIu64 ", Duration %f, Paused:%d, progress:%f Rate:%d, Zoom:%d", - status_data.event_id, - status_data.duration, - status_data.paused, - status_data.progress, - status_data.rate, - status_data.zoom - ); + status_data.event_id, + FPSeconds(status_data.duration).count(), + status_data.paused, + FPSeconds(status_data.progress).count(), + status_data.rate, + status_data.zoom); DataMsg status_msg; status_msg.msg_type = MSG_DATA_EVENT; @@ -580,11 +598,17 @@ void EventStream::processCommand(const CmdMsg *msg) { //exit(-1); } } - // quit after sending a status, if this was a quit request - if ( (MsgCommand)msg->msg_data[0] == CMD_QUIT ) - exit(0); - updateFrameRate((event_data->frame_count and event_data->duration) ? (double)event_data->frame_count/event_data->duration : 1); + // quit after sending a status, if this was a quit request + if (static_cast(msg->msg_data[0]) == CMD_QUIT) { + exit(0); + } + + double fps = 1.0; + if ((event_data->frame_count and event_data->duration != Seconds(0))) { + fps = static_cast(event_data->frame_count) / FPSeconds(event_data->duration).count(); + } + updateFrameRate(fps); } // void EventStream::processCommand(const CmdMsg *msg) bool EventStream::checkEventLoaded() { @@ -595,7 +619,7 @@ bool EventStream::checkEventLoaded() { "SELECT `Id` FROM `Events` WHERE `MonitorId` = %d AND `Id` < %" PRIu64 " ORDER BY `Id` DESC LIMIT 1", event_data->monitor_id, event_data->event_id); } else if ( (unsigned int)curr_frame_id > event_data->last_frame_id ) { - if ( !event_data->end_time ) { + if (event_data->end_time.time_since_epoch() == Seconds(0)) { // We are viewing an in-process event, so just reload it. loadEventData(event_data->event_id); if ( (unsigned int)curr_frame_id > event_data->last_frame_id ) @@ -674,7 +698,7 @@ Image * EventStream::getImage( ) { return image; } -bool EventStream::sendFrame(int delta_us) { +bool EventStream::sendFrame(Microseconds delta_us) { Debug(2, "Sending frame %ld", curr_frame_id); static char filepath[PATH_MAX]; @@ -710,7 +734,10 @@ bool EventStream::sendFrame(int delta_us) { fprintf(stdout, "Content-type: %s\r\n\r\n", vid_stream->MimeType()); vid_stream->OpenStream(); } - /* double pts = */ vid_stream->EncodeFrame(send_image->Buffer(), send_image->Size(), config.mpeg_timed_frames, delta_us*1000); + vid_stream->EncodeFrame(send_image->Buffer(), + send_image->Size(), + config.mpeg_timed_frames, + delta_us.count() * 1000); } else { bool send_raw = (type == STREAM_JPEG) && ((scale>=ZM_SCALE_BASE)&&(zoom==ZM_SCALE_BASE)) && filepath[0]; @@ -729,9 +756,8 @@ bool EventStream::sendFrame(int delta_us) { } else if ( ffmpeg_input ) { // Get the frame from the mp4 input FrameData *frame_data = &event_data->frames[curr_frame_id-1]; - AVFrame *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(), FPSeconds(frame_data->offset).count()); if ( frame ) { image = new Image(frame); //av_frame_free(&frame); @@ -806,7 +832,7 @@ bool EventStream::sendFrame(int delta_us) { fputs("\r\n", stdout); fflush(stdout); - last_frame_sent = TV_2_FLOAT(now); + last_frame_sent = now; return true; } // bool EventStream::sendFrame( int delta_us ) @@ -823,17 +849,21 @@ void EventStream::runStream() { exit(0); } - updateFrameRate((event_data->frame_count and event_data->duration) ? (double)event_data->frame_count/event_data->duration : 1); - gettimeofday(&start, nullptr); - uint64_t start_usec = start.tv_sec * 1000000 + start.tv_usec; - uint64_t last_frame_offset = 0; + double fps = 1.0; + if ((event_data->frame_count and event_data->duration != Seconds(0))) { + fps = static_cast(event_data->frame_count) / FPSeconds(event_data->duration).count(); + } + updateFrameRate(fps); - double time_to_event = 0; + start = std::chrono::system_clock::now(); + + SystemTimePoint::duration last_frame_offset = Seconds(0); + SystemTimePoint::duration time_to_event = Seconds(0); while ( !zm_terminate ) { - gettimeofday(&now, nullptr); + now = std::chrono::system_clock::now(); - int delta_us = 0; + Microseconds delta = Microseconds(0); send_frame = false; if ( connkey ) { @@ -843,7 +873,7 @@ void EventStream::runStream() { } // Update modified time of the socket .lock file so that we can tell which ones are stale. - if ( now.tv_sec - last_comm_update.tv_sec > 3600 ) { + if (now - last_comm_update > Hours(1)) { touch(sock_path_lock); last_comm_update = now; } @@ -869,8 +899,7 @@ void EventStream::runStream() { send_frame = true; } else if ( !send_frame ) { // We are paused, not stepping and doing nothing, meaning that comms didn't set send_frame to true - double time_since_last_send = TV_2_FLOAT(now) - last_frame_sent; - if ( time_since_last_send > MAX_STREAM_DELAY ) { + if (now - last_frame_sent > MAX_STREAM_DELAY) { // Send keepalive Debug(2, "Sending keepalive frame"); send_frame = true; @@ -878,39 +907,47 @@ void EventStream::runStream() { } // end if streaming stepping or doing nothing // time_to_event > 0 means that we are not in the event - if ( ( time_to_event > 0 ) and ( mode == MODE_ALL ) ) { - double time_since_last_send = TV_2_FLOAT(now) - last_frame_sent; - Debug(1, "Time since last send = %f = %f - %f", time_since_last_send, TV_2_FLOAT(now), last_frame_sent); - if ( time_since_last_send > 1 /* second */ ) { - static char frame_text[64]; + if (time_to_event > Seconds(0) and mode == MODE_ALL) { + SystemTimePoint::duration time_since_last_send = now - last_frame_sent; + Debug(1, "Time since last send = %.2f s", FPSeconds(time_since_last_send).count()); + if (time_since_last_send > Seconds(1)) { + char frame_text[64]; - snprintf(frame_text, sizeof(frame_text), "Time to %s event = %d seconds", - (replay_rate > 0 ? "next" : "previous" ), (int)time_to_event); - if ( !sendTextFrame(frame_text) ) + snprintf(frame_text, sizeof(frame_text), "Time to %s event = %f s", + (replay_rate > 0 ? "next" : "previous"), + FPSeconds(time_to_event).count()); + + if (!sendTextFrame(frame_text)) { zm_terminate = true; + } + send_frame = false; // In case keepalive was set } // 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)); + Milliseconds sleep_time = std::chrono::duration_cast( + (replay_rate > 0 ? 1 : -1) * ((1.0L * replay_rate * STREAM_PAUSE_WAIT) / ZM_RATE_BASE)); //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; + if (sleep_time == Seconds(0)) { + sleep_time += STREAM_PAUSE_WAIT; } + 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); + Debug(2, "Sleeping (%" PRIi64 " ms) because we are not at the next event yet, adding %" PRIi64 " ms", + static_cast(Milliseconds(STREAM_PAUSE_WAIT).count()), + static_cast(Milliseconds(sleep_time).count())); + std::this_thread::sleep_for(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) ) { + if (send_frame) { + if (!sendFrame(delta)) { zm_terminate = true; break; } @@ -918,23 +955,30 @@ void EventStream::runStream() { curr_stream_time = frame_data->timestamp; - if ( !paused ) { - + if (!paused) { // delta is since the last frame - delta_us = (unsigned int)(frame_data->delta * 1000000); - Debug(3, "frame delta %uus ", delta_us); + delta = std::chrono::duration_cast(frame_data->delta); + Debug(3, "frame delta %" PRIi64 "us ", + static_cast(std::chrono::duration_cast(delta).count())); + // 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); + delta = std::chrono::duration_cast((delta * base_fps) / effective_fps); + Debug(3, "delta %" PRIi64 " us = base_fps (%f) / effective_fps (%f)", + static_cast(std::chrono::duration_cast(delta).count()), + base_fps, + effective_fps); + // but must not exceed maxfps - delta_us = std::max(delta_us, int(1000000/maxfps)); - Debug(3, "delta %u = base_fps(%f)/effective fps(%f) from 30fps", delta_us, base_fps, effective_fps); + delta = std::max(delta, Microseconds(lround(Microseconds::period::den / maxfps))); + Debug(3, "delta %" PRIi64 " us = base_fps (%f) /effective_fps (%f) from 30fps", + static_cast(std::chrono::duration_cast(delta).count()), + 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 - gettimeofday(&now, nullptr); - uint64_t now_usec = (now.tv_sec * 1000000 + now.tv_usec); + now = std::chrono::system_clock::now(); // we incremented by replay_rate, so might have jumped past frame_count if ( (mode == MODE_SINGLE) && ( @@ -945,8 +989,8 @@ void EventStream::runStream() { ) { 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 - start_usec = now_usec; + // Have to reset start to now when replaying + start = now; } frame_data = &event_data->frames[curr_frame_id-1]; @@ -958,43 +1002,53 @@ void EventStream::runStream() { // 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 ) { + if (last_frame_offset != Seconds(0)) { // 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 " = %" PRIu64 " offset %f - elapsed = %dusec", - now_usec, start_usec, static_cast(now_usec - start_usec), frame_data->offset * 1000000, delta_us); + delta = std::chrono::duration_cast(frame_data->offset - (now - start)); + + Debug(2, "New delta: now - start = %" PRIu64 " us offset %" PRIi64 " us- elapsed = %" PRIu64 " us", + static_cast(std::chrono::duration_cast(now - start).count()), + static_cast(std::chrono::duration_cast(frame_data->offset).count()), + static_cast(std::chrono::duration_cast(delta).count())); } else { Debug(2, "No last frame_offset, no sleep"); - delta_us = 0; + delta = Seconds(0); } - last_frame_offset = frame_data->offset * 1000000; + last_frame_offset = frame_data->offset; - 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; + if (send_frame && type != STREAM_MPEG) { + if (delta != Seconds(0)) { + if (delta > MAX_SLEEP) { + Debug(1, "Limiting sleep to %" PRIi64 " ms because calculated sleep is too long: %" PRIi64" us", + static_cast(std::chrono::duration_cast(MAX_SLEEP).count()), + static_cast(std::chrono::duration_cast(delta).count())); + delta = MAX_SLEEP; } - usleep(delta_us); - Debug(3, "Done sleeping: %d usec", delta_us); + + std::this_thread::sleep_for(delta); + Debug(3, "Done sleeping: %" PRIi64 " us", + static_cast(std::chrono::duration_cast(delta).count())); } } } else { - delta_us = ((1000000 * ZM_RATE_BASE)/((base_fps?base_fps:1)*(replay_rate?abs(replay_rate*2):2))); + delta = std::chrono::duration_cast(FPSeconds( + ZM_RATE_BASE / ((base_fps ? base_fps : 1) * (replay_rate ? abs(replay_rate * 2) : 2)))); - Debug(2, "Sleeping %d because 1000000 * ZM_RATE_BASE(%d) / ( base_fps (%f), replay_rate(%d)", - delta_us, - ZM_RATE_BASE, - (base_fps ? base_fps : 1), - (replay_rate ? abs(replay_rate*2) : 0) - ); - 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; + Debug(2, "Sleeping %" PRIi64 " us because ZM_RATE_BASE (%d) / ( base_fps (%f) * replay_rate (%d)", + static_cast(std::chrono::duration_cast(delta).count()), + ZM_RATE_BASE, + (base_fps ? base_fps : 1), + (replay_rate ? abs(replay_rate * 2) : 0)); + + if (delta != Seconds(0)) { + if (delta > MAX_SLEEP) { + Debug(1, "Limiting sleep to %" PRIi64 " ms because calculated sleep is too long %" PRIi64, + static_cast(std::chrono::duration_cast(MAX_SLEEP).count()), + static_cast(std::chrono::duration_cast(delta).count())); + delta = MAX_SLEEP; } - usleep(delta_us); + + std::this_thread::sleep_for(delta); } // We are paused, so might be stepping //if ( step != 0 )// Adding 0 is cheaper than an if 0 @@ -1011,15 +1065,19 @@ void EventStream::runStream() { 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); + Debug(1, "replay rate (%d) time_to_event (%f s) = frame timestamp (%f s) - curr_stream_time (%f s)", + replay_rate, + FPSeconds(time_to_event).count(), + FPSeconds(event_data->frames[0].timestamp.time_since_epoch()).count(), + FPSeconds(curr_stream_time.time_since_epoch()).count()); } 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); + Debug(1, "replay rate (%d), time_to_event(%f s) = curr_stream_time (%f s) - frame timestamp (%f s)", + replay_rate, + FPSeconds(time_to_event).count(), + FPSeconds(curr_stream_time.time_since_epoch()).count(), + FPSeconds(event_data->frames[event_data->frame_count - 1].timestamp.time_since_epoch()).count()); } // end if forward or reverse } // end if checkEventLoaded } // end while ! zm_terminate @@ -1036,7 +1094,7 @@ bool EventStream::send_file(const char *filepath) { int img_buffer_size = 0; uint8_t *img_buffer = temp_img_buffer; - FILE *fdj = NULL; + FILE *fdj = nullptr; fdj = fopen(filepath, "rb"); if ( !fdj ) { Error("Can't open %s: %s", filepath, strerror(errno)); diff --git a/src/zm_eventstream.h b/src/zm_eventstream.h index 4592e97e7..34f918fe4 100644 --- a/src/zm_eventstream.h +++ b/src/zm_eventstream.h @@ -40,10 +40,10 @@ class EventStream : public StreamBase { protected: struct FrameData { //unsigned long id; - double timestamp; - double offset; - double delta; - bool in_db; + SystemTimePoint timestamp; + Microseconds offset; + Microseconds delta; + bool in_db; }; struct EventData { @@ -52,10 +52,10 @@ class EventStream : public StreamBase { unsigned long storage_id; unsigned long frame_count; // Value of Frames column in Event unsigned long last_frame_id; // Highest frame id known about. Can be < frame_count in incomplete events - time_t start_time; - time_t end_time; - double duration; - double frames_duration; + SystemTimePoint start_time; + SystemTimePoint end_time; + Microseconds duration; + Microseconds frames_duration; char path[PATH_MAX]; int n_frames; // # of frame rows returned from database FrameData *frames; @@ -66,7 +66,7 @@ class EventStream : public StreamBase { }; protected: - static const int STREAM_PAUSE_WAIT = 250000; // Microseconds + static constexpr Milliseconds STREAM_PAUSE_WAIT = Milliseconds(250); static const StreamMode DEFAULT_MODE = MODE_SINGLE; @@ -74,32 +74,32 @@ class EventStream : public StreamBase { bool forceEventChange; long curr_frame_id; - double curr_stream_time; + SystemTimePoint curr_stream_time; bool send_frame; - struct timeval start; // clock time when started the event + SystemTimePoint start; // clock time when started the event 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); + bool loadInitialEventData(int monitor_id, SystemTimePoint event_time); bool checkEventLoaded(); void processCommand(const CmdMsg *msg) override; - bool sendFrame(int delta_us); + bool sendFrame(Microseconds delta); public: EventStream() : mode(DEFAULT_MODE), forceEventChange(false), curr_frame_id(0), - curr_stream_time(0.0), send_frame(false), event_data(nullptr), storage(nullptr), ffmpeg_input(nullptr) {} + ~EventStream() { if ( event_data ) { if ( event_data->frames ) { diff --git a/src/zm_fifo_stream.cpp b/src/zm_fifo_stream.cpp index 3035ad6d0..fcb0e7186 100644 --- a/src/zm_fifo_stream.cpp +++ b/src/zm_fifo_stream.cpp @@ -92,7 +92,7 @@ bool FifoStream::sendMJEGFrames() { } fprintf(stdout, "\r\n\r\n"); fflush(stdout); - last_frame_sent = TV_2_FLOAT(now); + last_frame_sent = now; frame_count++; return true; } @@ -156,8 +156,9 @@ void FifoStream::runStream() { } while ( !zm_terminate ) { - gettimeofday(&now, nullptr); + now = std::chrono::system_clock::now(); checkCommandQueue(); + if ( stream_type == MJPEG ) { if ( !sendMJEGFrames() ) zm_terminate = true; diff --git a/src/zm_frame.cpp b/src/zm_frame.cpp index 2b28a62b1..d333d04e1 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, - Milliseconds p_delta, + Microseconds 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 87769711b..5b3792093 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, - Milliseconds p_delta, + Microseconds p_delta, int p_score, std::vector p_stats ); @@ -51,7 +51,7 @@ class Frame { int frame_id; FrameType type; struct timeval timestamp; - Milliseconds delta; + Microseconds delta; int score; std::vector zone_stats; }; diff --git a/src/zm_monitorstream.cpp b/src/zm_monitorstream.cpp index 99cc01720..b407166e7 100644 --- a/src/zm_monitorstream.cpp +++ b/src/zm_monitorstream.cpp @@ -85,7 +85,7 @@ void MonitorStream::processCommand(const CmdMsg *msg) { Debug(1, "Got PAUSE command"); paused = true; delayed = true; - last_frame_sent = TV_2_FLOAT(now); + last_frame_sent = now; break; case CMD_PLAY : Debug(1, "Got PLAY command"); @@ -280,7 +280,7 @@ void MonitorStream::processCommand(const CmdMsg *msg) { status_data.delayed = delayed; status_data.paused = paused; status_data.rate = replay_rate; - status_data.delay = TV_2_FLOAT(now) - TV_2_FLOAT(last_frame_timestamp); + status_data.delay = FPSeconds(now - last_frame_timestamp).count(); status_data.zoom = zoom; Debug(2, "fps: %.2f capture_fps: %.2f analysis_fps: %.2f Buffer Level:%d, Delayed:%d, Paused:%d, Rate:%d, delay:%.3f, Zoom:%d, Enabled:%d Forced:%d", status_data.fps, @@ -320,7 +320,7 @@ void MonitorStream::processCommand(const CmdMsg *msg) { //updateFrameRate(monitor->GetFPS()); } // end void MonitorStream::processCommand(const CmdMsg *msg) -bool MonitorStream::sendFrame(const char *filepath, const timeval ×tamp) { +bool MonitorStream::sendFrame(const char *filepath, SystemTimePoint timestamp) { bool send_raw = ((scale>=ZM_SCALE_BASE)&&(zoom==ZM_SCALE_BASE)); if ( @@ -350,8 +350,8 @@ bool MonitorStream::sendFrame(const char *filepath, const timeval ×tamp) { TimePoint send_start_time = std::chrono::steady_clock::now(); if ( - (0 > fprintf(stdout, "Content-Length: %d\r\nX-Timestamp: %d.%06d\r\n\r\n", - img_buffer_size, (int)timestamp.tv_sec, (int)timestamp.tv_usec)) + (0 > fprintf(stdout, "Content-Length: %d\r\nX-Timestamp: %.6f\r\n\r\n", + img_buffer_size, std::chrono::duration_cast(timestamp.time_since_epoch()).count())) || (fwrite(img_buffer, img_buffer_size, 1, stdout) != 1) ) { @@ -363,26 +363,27 @@ bool MonitorStream::sendFrame(const char *filepath, const timeval ×tamp) { fflush(stdout); TimePoint send_end_time = std::chrono::steady_clock::now(); - Milliseconds frame_send_time = std::chrono::duration_cast(send_end_time - send_start_time); + TimePoint::duration frame_send_time = send_end_time - send_start_time; if (frame_send_time > Milliseconds(lround(Milliseconds::period::den / maxfps))) { maxfps /= 2; - Info("Frame send time %" PRIi64 " msec too slow, throttling maxfps to %.2f", - static_cast(frame_send_time.count()), + Info("Frame send time %" PRIi64 " ms too slow, throttling maxfps to %.2f", + static_cast(std::chrono::duration_cast(frame_send_time).count()), maxfps); } - last_frame_sent = TV_2_FLOAT(now); + last_frame_sent = now; return true; } return false; } // end bool MonitorStream::sendFrame(const char *filepath, struct timeval *timestamp) -bool MonitorStream::sendFrame(Image *image, const timeval ×tamp) { +bool MonitorStream::sendFrame(Image *image, SystemTimePoint timestamp) { Image *send_image = prepareImage(image); - if (!config.timestamp_on_capture) - monitor->TimestampImage(send_image, timestamp); + if (!config.timestamp_on_capture) { + monitor->TimestampImage(send_image, zm::chrono::duration_cast(timestamp.time_since_epoch())); + } fputs("--" BOUNDARY "\r\n", stdout); if ( type == STREAM_MPEG ) { @@ -392,13 +393,11 @@ bool MonitorStream::sendFrame(Image *image, const timeval ×tamp) { vid_stream->OpenStream(); } - static struct timeval base_time; - Milliseconds delta_time = - zm::chrono::duration_cast(timestamp) - zm::chrono::duration_cast(base_time); - + static SystemTimePoint base_time; if (!frame_count) { base_time = timestamp; } + SystemTimePoint::duration delta_time = timestamp - base_time; /* double pts = */ vid_stream->EncodeFrame(send_image->Buffer(), send_image->Size(), config.mpeg_timed_frames, delta_time.count()); } else { @@ -436,8 +435,8 @@ bool MonitorStream::sendFrame(Image *image, const timeval ×tamp) { return false; } if ( - ( 0 > fprintf(stdout, "Content-Length: %d\r\nX-Timestamp: %d.%06d\r\n\r\n", - img_buffer_size, (int)timestamp.tv_sec, (int)timestamp.tv_usec) ) + (0 > fprintf(stdout, "Content-Length: %d\r\nX-Timestamp: %.6f\r\n\r\n", + img_buffer_size, std::chrono::duration_cast(timestamp.time_since_epoch()).count())) || (fwrite(img_buffer, img_buffer_size, 1, stdout) != 1) ) { @@ -451,16 +450,16 @@ bool MonitorStream::sendFrame(Image *image, const timeval ×tamp) { fflush(stdout); TimePoint send_end_time = std::chrono::steady_clock::now(); - Milliseconds frame_send_time = std::chrono::duration_cast(send_end_time - send_start_time); + TimePoint::duration frame_send_time = send_end_time - send_start_time; if (frame_send_time > Milliseconds(lround(Milliseconds::period::den / maxfps))) { maxfps /= 1.5; Warning("Frame send time %" PRIi64 " msec too slow, throttling maxfps to %.2f", - static_cast(frame_send_time.count()), + static_cast(std::chrono::duration_cast(frame_send_time).count()), maxfps); } } // Not mpeg - last_frame_sent = TV_2_FLOAT(now); + last_frame_sent = now; return true; } // end bool MonitorStream::sendFrame( Image *image, const timeval ×tamp ) @@ -503,8 +502,7 @@ void MonitorStream::runStream() { // point to end which is theoretically not a valid value because all indexes are % image_buffer_count int32_t last_read_index = monitor->image_buffer_count; - time_t stream_start_time; - time(&stream_start_time); + SystemTimePoint stream_start_time = std::chrono::system_clock::now(); frame_count = 0; @@ -518,7 +516,7 @@ void MonitorStream::runStream() { // Last image and timestamp when paused, will be resent occasionally to prevent timeout Image *paused_image = nullptr; - struct timeval paused_timestamp; + SystemTimePoint paused_timestamp; if ( connkey && ( playback_buffer > 0 ) ) { // 15 is the max length for the swap path suffix, /zmswap-whatever, assuming max 6 digits for monitor id @@ -554,7 +552,6 @@ void MonitorStream::runStream() { } else { Debug(2, "Assigning temporary buffer"); temp_image_buffer = new SwapImage[temp_image_buffer_count]; - memset(temp_image_buffer, 0, sizeof(*temp_image_buffer)*temp_image_buffer_count); Debug(2, "Assigned temporary buffer"); } } @@ -575,7 +572,7 @@ void MonitorStream::runStream() { break; } - gettimeofday(&now, nullptr); + now = std::chrono::system_clock::now(); bool was_paused = paused; if ( connkey ) { @@ -585,7 +582,7 @@ void MonitorStream::runStream() { got_command = true; } // Update modified time of the socket .lock file so that we can tell which ones are stale. - if ( now.tv_sec - last_comm_update.tv_sec > 3600 ) { + if (now - last_comm_update > Hours(1)) { touch(sock_path_lock); last_comm_update = now; } @@ -596,7 +593,7 @@ void MonitorStream::runStream() { int index = monitor->shared_data->last_write_index % monitor->image_buffer_count; Debug(1, "Saving paused image from index %d",index); paused_image = new Image(*monitor->image_buffer[index]); - paused_timestamp = monitor->shared_timestamps[index]; + paused_timestamp = SystemTimePoint(zm::chrono::duration_cast(monitor->shared_timestamps[index])); } } else if ( paused_image ) { Debug(1, "Clearing paused_image"); @@ -624,55 +621,46 @@ void MonitorStream::runStream() { delayed = true; temp_read_index = MOD_ADD(temp_read_index, (replay_rate>=0?-1:1), temp_image_buffer_count); } else { - // Debug( 3, "siT: %f, lfT: %f", TV_2_FLOAT( swap_image->timestamp ), TV_2_FLOAT( last_frame_timestamp ) ); - double expected_delta_time = ((TV_2_FLOAT(swap_image->timestamp) - TV_2_FLOAT(last_frame_timestamp)) * ZM_RATE_BASE)/replay_rate; - double actual_delta_time = TV_2_FLOAT(now) - last_frame_sent; + FPSeconds expected_delta_time = ((FPSeconds(swap_image->timestamp - last_frame_timestamp)) * ZM_RATE_BASE) / replay_rate; + SystemTimePoint::duration actual_delta_time = now - last_frame_sent; - // Debug( 3, "eDT: %.3lf, aDT: %.3f, lFS:%.3f, NOW:%.3f", expected_delta_time, actual_delta_time, last_frame_sent, TV_2_FLOAT( now ) ); // If the next frame is due - if ( actual_delta_time > expected_delta_time ) { + if (actual_delta_time > expected_delta_time) { // Debug( 2, "eDT: %.3lf, aDT: %.3f", expected_delta_time, actual_delta_time ); - if ( temp_index%frame_mod == 0 ) { + if (temp_index % frame_mod == 0) { Debug(2, "Sending delayed frame %d", temp_index); // Send the next frame if (!sendFrame(temp_image_buffer[temp_index].file_name, temp_image_buffer[temp_index].timestamp)) { zm_terminate = true; } - memcpy(&last_frame_timestamp, &(swap_image->timestamp), sizeof(last_frame_timestamp)); + last_frame_timestamp = swap_image->timestamp; // frame_sent = true; } - temp_read_index = MOD_ADD(temp_read_index, (replay_rate>0?1:-1), temp_image_buffer_count); + temp_read_index = MOD_ADD(temp_read_index, (replay_rate > 0 ? 1 : -1), temp_image_buffer_count); } } - } else if ( step != 0 ) { + } else if (step != 0) { temp_read_index = MOD_ADD(temp_read_index, (step>0?1:-1), temp_image_buffer_count); SwapImage *swap_image = &temp_image_buffer[temp_read_index]; // Send the next frame - if ( !sendFrame( - temp_image_buffer[temp_read_index].file_name, - temp_image_buffer[temp_read_index].timestamp - ) ) { + if (!sendFrame(temp_image_buffer[temp_read_index].file_name, temp_image_buffer[temp_read_index].timestamp)) { zm_terminate = true; } - memcpy( - &last_frame_timestamp, - &(swap_image->timestamp), - sizeof(last_frame_timestamp) - ); + + last_frame_timestamp = swap_image->timestamp; // frame_sent = true; step = 0; } else { //paused? int temp_index = MOD_ADD(temp_read_index, 0, temp_image_buffer_count); - double actual_delta_time = TV_2_FLOAT(now) - last_frame_sent; - if ( got_command || (actual_delta_time > 5) ) { + if (got_command || (now - last_frame_sent > Seconds(5))) { // Send keepalive Debug(2, "Sending keepalive frame %d", temp_index); // Send the next frame - if ( !sendFrame(temp_image_buffer[temp_index].file_name, temp_image_buffer[temp_index].timestamp) ) { + if (!sendFrame(temp_image_buffer[temp_index].file_name, temp_image_buffer[temp_index].timestamp)) { zm_terminate = true; } // frame_sent = true; @@ -702,20 +690,21 @@ void MonitorStream::runStream() { // Send the next frame // // Perhaps we should use NOW instead. - last_frame_timestamp = monitor->shared_timestamps[index]; + last_frame_timestamp = + SystemTimePoint(zm::chrono::duration_cast(monitor->shared_timestamps[index])); Image *image = monitor->image_buffer[index]; - if ( !sendFrame(image, last_frame_timestamp) ) { + if (!sendFrame(image, last_frame_timestamp)) { Debug(2, "sendFrame failed, quiting."); zm_terminate = true; break; } //frame_sent = true; // - if ( frame_count == 0 ) { + if (frame_count == 0) { // Chrome will not display the first frame until it receives another. // Firefox is fine. So just send the first frame twice. - if ( !sendFrame(image, last_frame_timestamp) ) { + if (!sendFrame(image, last_frame_timestamp)) { Debug(2, "sendFrame failed, quiting."); zm_terminate = true; break; @@ -735,12 +724,12 @@ void MonitorStream::runStream() { if (!sendFrame(paused_image, paused_timestamp)) zm_terminate = true; } else { - double actual_delta_time = TV_2_FLOAT(now) - last_frame_sent; - if ( actual_delta_time > 5 ) { - if ( paused_image ) { + SystemTimePoint::duration actual_delta_time = now - last_frame_sent; + if (actual_delta_time > Seconds(5)) { + if (paused_image) { // Send keepalive - Debug(2, "Sending keepalive frame because delta time %.2f > 5", - actual_delta_time); + Debug(2, "Sending keepalive frame because delta time %.2f s > 5 s", + FPSeconds(actual_delta_time).count()); // Send the next frame if (!sendFrame(paused_image, paused_timestamp)) zm_terminate = true; @@ -766,7 +755,9 @@ void MonitorStream::runStream() { temp_index); temp_image_buffer[temp_index].valid = true; } - temp_image_buffer[temp_index].timestamp = monitor->shared_timestamps[index]; + + temp_image_buffer[temp_index].timestamp = + SystemTimePoint(zm::chrono::duration_cast(monitor->shared_timestamps[index])); monitor->image_buffer[index]->WriteJpeg( temp_image_buffer[temp_index].file_name, config.jpeg_file_quality @@ -791,27 +782,29 @@ void MonitorStream::runStream() { Debug(3, "Waiting for capture last_write_index=%u", monitor->shared_data->last_write_index); } // end if ( (unsigned int)last_read_index != monitor->shared_data->last_write_index ) - unsigned long sleep_time = (unsigned long)((1000000 * ZM_RATE_BASE)/((base_fps?base_fps:1)*abs(replay_rate*2))); - if ( sleep_time > MonitorStream::MAX_SLEEP_USEC ) { + FPSeconds sleep_time = + FPSeconds(ZM_RATE_BASE / ((base_fps ? base_fps : 1) * (replay_rate ? abs(replay_rate * 2) : 2))); + + if (sleep_time > MonitorStream::MAX_SLEEP) { // Shouldn't sleep for long because we need to check command queue, etc. - sleep_time = MonitorStream::MAX_SLEEP_USEC; - Debug(3, "Sleeping for MAX_SLEEP_USEC %luus", sleep_time); + sleep_time = MonitorStream::MAX_SLEEP; + Debug(3, "Sleeping for MAX_SLEEP_USEC %" PRIi64 " us", + static_cast(std::chrono::duration_cast(sleep_time).count())); } else { - Debug(3, "Sleeping for %luus", sleep_time); + Debug(3, "Sleeping for %" PRIi64 " us", + static_cast(std::chrono::duration_cast(sleep_time).count())); } - usleep(sleep_time); - if ( ttl ) { - if ( (now.tv_sec - stream_start_time) > ttl ) { - Debug(2, "now(%" PRIi64 ") - start(%" PRIi64 " ) > ttl(%" PRIi64 ") break", - static_cast(now.tv_sec), - static_cast(stream_start_time), - static_cast(ttl)); - break; - } + std::this_thread::sleep_for(sleep_time); + + if (ttl > Seconds(0) && (now - stream_start_time) > ttl) { + Debug(2, "now - start > ttl (%" PRIi64 " us). break", + static_cast(std::chrono::duration_cast(ttl).count())); + break; } - if ( !last_frame_sent ) { + + if (last_frame_sent.time_since_epoch() == Seconds(0)) { // If we didn't capture above, because frame_mod was bad? Then last_frame_sent will not have a value. - last_frame_sent = now.tv_sec; + last_frame_sent = now; Warning("no last_frame_sent. Shouldn't happen. frame_mod was (%d) frame_count (%d)", frame_mod, frame_count); } diff --git a/src/zm_monitorstream.h b/src/zm_monitorstream.h index 5730bfc5a..0a690a1b6 100644 --- a/src/zm_monitorstream.h +++ b/src/zm_monitorstream.h @@ -25,11 +25,11 @@ class MonitorStream : public StreamBase { protected: - typedef struct SwapImage { - bool valid; - struct timeval timestamp; - char file_name[PATH_MAX]; - } SwapImage; + struct SwapImage { + bool valid = false; + SystemTimePoint timestamp; + char file_name[PATH_MAX] = ""; + }; private: SwapImage *temp_image_buffer; @@ -38,15 +38,15 @@ class MonitorStream : public StreamBase { int temp_write_index; protected: - time_t ttl; + Microseconds ttl; int playback_buffer; bool delayed; int frame_count; protected: bool checkSwapPath(const char *path, bool create_path); - bool sendFrame(const char *filepath, const timeval ×tamp); - bool sendFrame(Image *image, const timeval ×tamp); + bool sendFrame(const char *filepath, SystemTimePoint timestamp); + bool sendFrame(Image *image, SystemTimePoint timestamp); void processCommand(const CmdMsg *msg) override; void SingleImage(int scale=100); void SingleImageRaw(int scale=100); @@ -55,7 +55,7 @@ class MonitorStream : public StreamBase { #endif public: - MonitorStream() : + MonitorStream() : temp_image_buffer(nullptr), temp_image_buffer_count(0), temp_read_index(0), @@ -63,13 +63,13 @@ class MonitorStream : public StreamBase { ttl(0), playback_buffer(0), delayed(false), - frame_count(0) { - } + frame_count(0) {} + void setStreamBuffer(int p_playback_buffer) { playback_buffer = p_playback_buffer; } void setStreamTTL(time_t p_ttl) { - ttl = p_ttl; + ttl = Seconds(p_ttl); } bool setStreamStart(int monitor_id) { return loadMonitor(monitor_id); diff --git a/src/zm_stream.cpp b/src/zm_stream.cpp index c8f1166bd..48f966660 100644 --- a/src/zm_stream.cpp +++ b/src/zm_stream.cpp @@ -27,6 +27,9 @@ #include #include +constexpr Seconds StreamBase::MAX_STREAM_DELAY; +constexpr Milliseconds StreamBase::MAX_SLEEP; + StreamBase::~StreamBase() { if (vid_stream) { delete vid_stream; @@ -283,7 +286,7 @@ bool StreamBase::sendTextFrame(const char *frame_text) { fputs("\r\n\r\n", stdout); fflush(stdout); } - last_frame_sent = TV_2_FLOAT(now); + last_frame_sent = now; return true; } @@ -368,7 +371,7 @@ void StreamBase::openComms() { strncpy(rem_addr.sun_path, rem_sock_path, sizeof(rem_addr.sun_path)); rem_addr.sun_family = AF_UNIX; - gettimeofday(&last_comm_update, nullptr); + last_comm_update = std::chrono::system_clock::now(); } // end if connKey > 0 Debug(3, "comms open at %s", loc_sock_path); } // end void StreamBase::openComms() diff --git a/src/zm_stream.h b/src/zm_stream.h index 9182d6dd4..d16e973ff 100644 --- a/src/zm_stream.h +++ b/src/zm_stream.h @@ -22,13 +22,13 @@ #include "zm_logger.h" #include "zm_mpeg.h" +#include "zm_time.h" #include #include class Image; class Monitor; -#define TV_2_FLOAT( tv ) ( double((tv).tv_sec) + (double((tv).tv_usec) / 1000000.0) ) #define BOUNDARY "ZoneMinderFrame" class StreamBase { @@ -42,8 +42,8 @@ public: } StreamType; protected: - static const int MAX_STREAM_DELAY = 5; // Seconds - static const int MAX_SLEEP_USEC = 500000; // .5 Seconds + static constexpr Seconds MAX_STREAM_DELAY = Seconds(5); + static constexpr Milliseconds MAX_SLEEP = Milliseconds(500); static const StreamType DEFAULT_TYPE = STREAM_JPEG; enum { DEFAULT_RATE=ZM_RATE_BASE }; @@ -119,15 +119,15 @@ protected: bool paused; int step; - struct timeval now; - struct timeval last_comm_update; + SystemTimePoint now; + SystemTimePoint last_comm_update; double base_fps; double effective_fps; int frame_mod; - double last_frame_sent; - struct timeval last_frame_timestamp; + SystemTimePoint last_frame_sent; + SystemTimePoint last_frame_timestamp; VideoStream *vid_stream; @@ -176,9 +176,7 @@ public: effective_fps = 0.0; frame_mod = 1; - vid_stream = 0; - last_frame_sent = 0.0; - last_frame_timestamp = {}; + vid_stream = nullptr; msg = { 0, { 0 } }; } virtual ~StreamBase();