Move from SystemTimePoint to SteadyTimePoint where possible. Implement MAXFPS command. Change the logic of calculating sleep time to make more sense. Get rid of frame_mod use in favour of calculating when then next frame should get sent and just waiting till then.

This commit is contained in:
Isaac Connor 2021-12-16 16:35:20 -05:00
parent 7b7ac8fc7e
commit 60d2186ff4
5 changed files with 80 additions and 42 deletions

View File

@ -663,7 +663,7 @@ bool EventStream::checkEventLoaded() {
else else
curr_frame_id = 1; curr_frame_id = 1;
Debug(2, "New frame id = %ld", curr_frame_id); Debug(2, "New frame id = %ld", curr_frame_id);
start = std::chrono::system_clock::now(); start = std::chrono::steady_clock::now();
return true; return true;
} else { } else {
Debug(2, "No next event loaded using %s. Pausing", sql.c_str()); Debug(2, "No next event loaded using %s. Pausing", sql.c_str());
@ -851,13 +851,13 @@ void EventStream::runStream() {
} }
updateFrameRate(fps); updateFrameRate(fps);
start = std::chrono::system_clock::now(); start = std::chrono::steady_clock::now();
SystemTimePoint::duration last_frame_offset = Seconds(0); SystemTimePoint::duration last_frame_offset = Seconds(0);
SystemTimePoint::duration time_to_event = Seconds(0); SystemTimePoint::duration time_to_event = Seconds(0);
while ( !zm_terminate ) { while ( !zm_terminate ) {
now = std::chrono::system_clock::now(); now = std::chrono::steady_clock::now();
Microseconds delta = Microseconds(0); Microseconds delta = Microseconds(0);
send_frame = false; send_frame = false;
@ -904,7 +904,7 @@ void EventStream::runStream() {
// time_to_event > 0 means that we are not in the event // time_to_event > 0 means that we are not in the event
if (time_to_event > Seconds(0) and mode == MODE_ALL) { if (time_to_event > Seconds(0) and mode == MODE_ALL) {
SystemTimePoint::duration time_since_last_send = now - last_frame_sent; TimePoint::duration time_since_last_send = now - last_frame_sent;
Debug(1, "Time since last send = %.2f s", FPSeconds(time_since_last_send).count()); Debug(1, "Time since last send = %.2f s", FPSeconds(time_since_last_send).count());
if (time_since_last_send > Seconds(1)) { if (time_since_last_send > Seconds(1)) {
char frame_text[64]; char frame_text[64];
@ -976,7 +976,7 @@ void EventStream::runStream() {
// +/- 1? What if we are skipping frames? // +/- 1? What if we are skipping frames?
curr_frame_id += (replay_rate>0) ? frame_mod : -1*frame_mod; curr_frame_id += (replay_rate>0) ? frame_mod : -1*frame_mod;
// sending the frame may have taken some time, so reload now // sending the frame may have taken some time, so reload now
now = std::chrono::system_clock::now(); now = std::chrono::steady_clock::now();
// we incremented by replay_rate, so might have jumped past frame_count // we incremented by replay_rate, so might have jumped past frame_count
if ( (mode == MODE_SINGLE) && ( if ( (mode == MODE_SINGLE) && (

View File

@ -76,7 +76,7 @@ class EventStream : public StreamBase {
long curr_frame_id; long curr_frame_id;
SystemTimePoint curr_stream_time; SystemTimePoint curr_stream_time;
bool send_frame; bool send_frame;
SystemTimePoint start; // clock time when started the event TimePoint start; // clock time when started the event
EventData *event_data; EventData *event_data;

View File

@ -134,6 +134,18 @@ void MonitorStream::processCommand(const CmdMsg *msg) {
break; break;
} }
break; break;
case CMD_MAXFPS :
{
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];
maxfps = (int_part + dec_part / 1000000.0);
Debug(1, "Got MAXFPS %f", maxfps);
break;
}
case CMD_SLOWFWD : case CMD_SLOWFWD :
Debug(1, "Got SLOW FWD command"); Debug(1, "Got SLOW FWD command");
paused = true; paused = true;
@ -268,7 +280,7 @@ void MonitorStream::processCommand(const CmdMsg *msg) {
} else { } else {
FPSeconds elapsed = now - last_fps_update; FPSeconds elapsed = now - last_fps_update;
if (elapsed.count()) { if (elapsed.count()) {
actual_fps = (frame_count - last_frame_count) / elapsed.count(); actual_fps = (actual_fps + (frame_count - last_frame_count) / elapsed.count())/2;
last_frame_count = frame_count; last_frame_count = frame_count;
last_fps_update = now; last_fps_update = now;
} }
@ -288,7 +300,7 @@ void MonitorStream::processCommand(const CmdMsg *msg) {
status_data.delayed = delayed; status_data.delayed = delayed;
status_data.paused = paused; status_data.paused = paused;
status_data.rate = replay_rate; status_data.rate = replay_rate;
status_data.delay = FPSeconds(now - last_frame_timestamp).count(); status_data.delay = FPSeconds(now - last_frame_sent).count();
status_data.zoom = zoom; status_data.zoom = zoom;
Debug(2, "viewing 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", Debug(2, "viewing 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, status_data.fps,
@ -382,6 +394,9 @@ bool MonitorStream::sendFrame(Image *image, SystemTimePoint timestamp) {
Image *send_image = prepareImage(image); Image *send_image = prepareImage(image);
fputs("--" BOUNDARY "\r\n", stdout); fputs("--" BOUNDARY "\r\n", stdout);
// Calculate how long it takes to actually send the frame
TimePoint send_start_time = std::chrono::steady_clock::now();
if ( type == STREAM_MPEG ) { if ( type == STREAM_MPEG ) {
if ( !vid_stream ) { 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());
@ -402,8 +417,6 @@ bool MonitorStream::sendFrame(Image *image, SystemTimePoint timestamp) {
int img_buffer_size = 0; int img_buffer_size = 0;
unsigned char *img_buffer = temp_img_buffer; unsigned char *img_buffer = temp_img_buffer;
// Calculate how long it takes to actually send the frame
TimePoint send_start_time = std::chrono::steady_clock::now();
switch ( type ) { switch ( type ) {
case STREAM_JPEG : case STREAM_JPEG :
@ -445,21 +458,22 @@ bool MonitorStream::sendFrame(Image *image, SystemTimePoint timestamp) {
fputs("\r\n", stdout); fputs("\r\n", stdout);
fflush(stdout); fflush(stdout);
TimePoint send_end_time = std::chrono::steady_clock::now();
TimePoint::duration frame_send_time = send_end_time - send_start_time;
TimePoint::duration maxfps_milliseconds = Milliseconds(lround(Milliseconds::period::den / maxfps));
if (frame_send_time > maxfps_milliseconds) {
//maxfps /= 1.5;
Warning("Frame send time %" PRIi64 " msec too slow (> %" PRIi64 ", throttling maxfps to %.3f",
static_cast<int64>(std::chrono::duration_cast<Milliseconds>(frame_send_time).count()),
static_cast<int64>(std::chrono::duration_cast<Milliseconds>(maxfps_milliseconds).count()),
maxfps);
}
} // Not mpeg } // Not mpeg
last_frame_sent = now;
TimePoint send_end_time = std::chrono::steady_clock::now();
TimePoint::duration frame_send_time = send_end_time - send_start_time;
TimePoint::duration maxfps_milliseconds = Milliseconds(lround(Milliseconds::period::den / maxfps));
if (frame_send_time > maxfps_milliseconds) {
//maxfps /= 1.5;
Warning("Frame send time %" PRIi64 " msec too slow (> %" PRIi64 ", throttling maxfps to %.3f",
static_cast<int64>(std::chrono::duration_cast<Milliseconds>(frame_send_time).count()),
static_cast<int64>(std::chrono::duration_cast<Milliseconds>(maxfps_milliseconds).count()),
maxfps);
}
last_frame_sent = send_end_time;
return true; return true;
} } // end bool MonitorStream::sendFrame(Image *image, SystemTimePoint timestamp)
void MonitorStream::runStream() { void MonitorStream::runStream() {
if (type == STREAM_SINGLE) { if (type == STREAM_SINGLE) {
@ -502,7 +516,8 @@ void MonitorStream::runStream() {
// point to end which is theoretically not a valid value because all indexes are % image_buffer_count // 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; int32_t last_read_index = monitor->image_buffer_count;
SystemTimePoint stream_start_time = std::chrono::system_clock::now(); TimePoint stream_start_time = std::chrono::steady_clock::now();
when_to_send_next_frame = stream_start_time; // initialize it to now so that we spit out a frame immediately
frame_count = 0; frame_count = 0;
@ -571,7 +586,7 @@ void MonitorStream::runStream() {
break; break;
} }
now = std::chrono::system_clock::now(); now = std::chrono::steady_clock::now();
bool was_paused = paused; bool was_paused = paused;
bool got_command = false; // commands like zoom should output a frame even if paused bool got_command = false; // commands like zoom should output a frame even if paused
@ -618,7 +633,7 @@ void MonitorStream::runStream() {
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 { } else {
FPSeconds expected_delta_time = ((FPSeconds(swap_image->timestamp - last_frame_timestamp)) * ZM_RATE_BASE) / replay_rate; 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; TimePoint::duration actual_delta_time = now - last_frame_sent;
// If the next frame is due // If the next frame is due
if (actual_delta_time > expected_delta_time) { if (actual_delta_time > expected_delta_time) {
@ -684,7 +699,8 @@ void MonitorStream::runStream() {
if (last_read_index != monitor->shared_data->last_write_index) { if (last_read_index != monitor->shared_data->last_write_index) {
// have a new image to send // have a new image to send
int index = monitor->shared_data->last_write_index % monitor->image_buffer_count; int index = monitor->shared_data->last_write_index % monitor->image_buffer_count;
if ((frame_mod == 1) || ((frame_count%frame_mod) == 0)) { //if ((frame_mod == 1) || ((frame_count%frame_mod) == 0)) {
if ( now >= when_to_send_next_frame ) {
if (!paused && !delayed) { if (!paused && !delayed) {
last_read_index = monitor->shared_data->last_write_index; last_read_index = monitor->shared_data->last_write_index;
Debug(2, "Sending frame index: %d: frame_mod: %d frame count: %d paused(%d) delayed(%d)", Debug(2, "Sending frame index: %d: frame_mod: %d frame count: %d paused(%d) delayed(%d)",
@ -743,9 +759,9 @@ void MonitorStream::runStream() {
} // end if actual_delta_time > 5 } // end if actual_delta_time > 5
} // end if change in zoom } // end if change in zoom
} // end if paused or not } // end if paused or not
} else { //} else {
frame_count++; //frame_count++;
} // end if should send frame } // end if should send frame now > when_to_send_next_frame
if (buffered_playback && !paused) { if (buffered_playback && !paused) {
if (monitor->shared_data->valid) { if (monitor->shared_data->valid) {
@ -776,15 +792,35 @@ void MonitorStream::runStream() {
} }
} // end if buffered playback } // end if buffered playback
} else { } else {
Debug(3, "Waiting for capture last_write_index=%u", monitor->shared_data->last_write_index); Debug(3, "Waiting for capture last_write_index=%u == last_read_index=%u",
monitor->shared_data->last_write_index,
last_read_index);
} // end if ( (unsigned int)last_read_index != monitor->shared_data->last_write_index ) } // end if ( (unsigned int)last_read_index != monitor->shared_data->last_write_index )
FPSeconds sleep_time = FPSeconds sleep_time;
FPSeconds(1 / ((base_fps ? base_fps : 1) * (replay_rate ? abs(replay_rate) : 1))); if (now >= when_to_send_next_frame) {
if (last_frame_sent.time_since_epoch() != Seconds(0)) { // sent a frame, so update
sleep_time -= (now - last_frame_sent);
if (sleep_time < Seconds(0)) double capture_fps = monitor->GetFPS();
sleep_time = Seconds(0); double fps = (maxfps && (capture_fps > maxfps)) ? maxfps : capture_fps;
double sleep_time_seconds = (1 / ((fps ? fps : 1))) // 1 second / fps
* (replay_rate ? abs(replay_rate)/ZM_RATE_BASE : 1); // replay_rate is 100 for 1x
Debug(3, "Using %f for maxfps. capture_fps: %f maxfps %f * replay_rate: %d = %f", fps, capture_fps, maxfps, replay_rate, sleep_time_seconds);
sleep_time = FPSeconds(sleep_time_seconds);
if (when_to_send_next_frame > now)
sleep_time -= when_to_send_next_frame - now;
when_to_send_next_frame = now + std::chrono::duration_cast<Microseconds>(sleep_time);
if (last_frame_sent > now) {
FPSeconds elapsed = last_frame_sent - now;
if (sleep_time > elapsed) {
sleep_time -= elapsed;
}
}
} else {
sleep_time = when_to_send_next_frame - now;
} }
if (sleep_time > MonitorStream::MAX_SLEEP) { if (sleep_time > MonitorStream::MAX_SLEEP) {

View File

@ -386,7 +386,7 @@ void StreamBase::openComms() {
strncpy(rem_addr.sun_path, rem_sock_path, sizeof(rem_addr.sun_path)); strncpy(rem_addr.sun_path, rem_sock_path, sizeof(rem_addr.sun_path));
rem_addr.sun_family = AF_UNIX; rem_addr.sun_family = AF_UNIX;
last_comm_update = std::chrono::system_clock::now(); last_comm_update = std::chrono::steady_clock::now();
Debug(3, "comms open at %s", loc_sock_path); Debug(3, "comms open at %s", loc_sock_path);
} // end if connKey > 0 } // end if connKey > 0
} // end void StreamBase::openComms() } // end void StreamBase::openComms()

View File

@ -88,6 +88,7 @@ protected:
CMD_VARPLAY, CMD_VARPLAY,
CMD_GET_IMAGE, CMD_GET_IMAGE,
CMD_QUIT, CMD_QUIT,
CMD_MAXFPS,
CMD_QUERY=99 CMD_QUERY=99
} MsgCommand; } MsgCommand;
@ -118,21 +119,22 @@ protected:
bool paused; bool paused;
int step; int step;
SystemTimePoint now; TimePoint now;
SystemTimePoint last_comm_update; TimePoint last_comm_update;
double maxfps; double maxfps;
double base_fps; // Should be capturing fps, hence a rough target double base_fps; // Should be capturing fps, hence a rough target
double effective_fps; // Target fps after taking max_fps into account double effective_fps; // Target fps after taking max_fps into account
double actual_fps; // sliding calculated actual streaming fps achieved double actual_fps; // sliding calculated actual streaming fps achieved
SystemTimePoint last_fps_update; TimePoint last_fps_update;
int frame_count; // Count of frames sent int frame_count; // Count of frames sent
int last_frame_count; // Used in calculating actual_fps from frame_count - last_frame_count int last_frame_count; // Used in calculating actual_fps from frame_count - last_frame_count
int frame_mod; int frame_mod;
SystemTimePoint last_frame_sent; TimePoint last_frame_sent;
SystemTimePoint last_frame_timestamp; SystemTimePoint last_frame_timestamp;
TimePoint when_to_send_next_frame; // When to send next frame so if now < send_next_frame, skip
VideoStream *vid_stream; VideoStream *vid_stream;