diff --git a/src/zm_monitorstream.cpp b/src/zm_monitorstream.cpp index 1509c73ed..e8f977cb3 100644 --- a/src/zm_monitorstream.cpp +++ b/src/zm_monitorstream.cpp @@ -255,7 +255,7 @@ void MonitorStream::processCommand(const CmdMsg *msg) { } status_data; status_data.id = monitor->Id(); - if ( ! monitor->ShmValid() ) { + if (!monitor->ShmValid()) { status_data.fps = 0.0; status_data.capture_fps = 0.0; status_data.analysis_fps = 0.0; @@ -265,7 +265,14 @@ void MonitorStream::processCommand(const CmdMsg *msg) { status_data.forced = false; status_data.buffer_level = 0; } else { - status_data.fps = monitor->GetFPS(); + FPSeconds elapsed = now - last_fps_update; + if (elapsed.count()) { + actual_fps = (frame_count - last_frame_count) / elapsed.count(); + last_frame_count = frame_count; + last_fps_update = now; + } + + status_data.fps = actual_fps; status_data.capture_fps = monitor->get_capture_fps(); status_data.analysis_fps = monitor->get_analysis_fps(); status_data.state = monitor->shared_data->state; @@ -519,7 +526,7 @@ void MonitorStream::runStream() { Image *paused_image = nullptr; SystemTimePoint paused_timestamp; - if ( connkey && ( playback_buffer > 0 ) ) { + if (connkey && (playback_buffer > 0)) { // 15 is the max length for the swap path suffix, /zmswap-whatever, assuming max 6 digits for monitor id const int max_swap_len_suffix = 15; @@ -528,27 +535,27 @@ void MonitorStream::runStream() { int subfolder2_length = snprintf(nullptr, 0, "/zmswap-q%06d", connkey) + 1; int total_swap_path_length = swap_path_length + subfolder1_length + subfolder2_length; - if ( total_swap_path_length + max_swap_len_suffix > PATH_MAX ) { + if (total_swap_path_length + max_swap_len_suffix > PATH_MAX) { Error("Swap Path is too long. %d > %d ", total_swap_path_length+max_swap_len_suffix, PATH_MAX); } else { swap_path = staticConfig.PATH_SWAP; Debug(3, "Checking swap path folder: %s", swap_path.c_str()); - if ( checkSwapPath(swap_path.c_str(), true) ) { + if (checkSwapPath(swap_path.c_str(), true)) { swap_path += stringtf("/zmswap-m%d", monitor->Id()); Debug(4, "Checking swap path subfolder: %s", swap_path.c_str()); - if ( checkSwapPath(swap_path.c_str(), true) ) { + if (checkSwapPath(swap_path.c_str(), true)) { swap_path += stringtf("/zmswap-q%06d", connkey); Debug(4, "Checking swap path subfolder: %s", swap_path.c_str()); - if ( checkSwapPath(swap_path.c_str(), true) ) { + if (checkSwapPath(swap_path.c_str(), true)) { buffered_playback = true; } } } - if ( !buffered_playback ) { + if (!buffered_playback) { Error("Unable to validate swap image path, disabling buffered playback"); } else { Debug(2, "Assigning temporary buffer"); @@ -558,14 +565,13 @@ void MonitorStream::runStream() { } } else { Debug(2, "Not using playback_buffer"); - } // end if connkey & playback_buffer + } // end if connkey && playback_buffer while (!zm_terminate) { - bool got_command = false; - if ( feof(stdout) ) { + if (feof(stdout)) { Debug(2, "feof stdout"); break; - } else if ( ferror(stdout) ) { + } else if (ferror(stdout)) { Debug(2, "ferror stdout"); break; } else if (!monitor->ShmValid()) { @@ -576,8 +582,9 @@ void MonitorStream::runStream() { now = std::chrono::system_clock::now(); bool was_paused = paused; - if ( connkey ) { - while ( checkCommandQueue() && !zm_terminate ) { + bool got_command = false; // commands like zoom should output a frame even if paused + if (connkey) { + while (checkCommandQueue() && !zm_terminate) { // Loop in here until all commands are processed. Debug(2, "Have checking command Queue for connkey: %d", connkey); got_command = true; @@ -589,35 +596,31 @@ void MonitorStream::runStream() { } } // end if connkey - if ( paused ) { - if ( !was_paused ) { + if (paused) { + if (!was_paused) { 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 = SystemTimePoint(zm::chrono::duration_cast(monitor->shared_timestamps[index])); } - } else if ( paused_image ) { - Debug(1, "Clearing paused_image"); + } else if (paused_image) { delete paused_image; paused_image = nullptr; } - if ( buffered_playback && delayed ) { - if ( temp_read_index == temp_write_index ) { + if (buffered_playback && delayed) { + if (temp_read_index == temp_write_index) { // Go back to live viewing Debug(1, "Exceeded temporary streaming buffer"); - // Clear paused flag paused = false; - // Clear delayed_play flag delayed = false; replay_rate = ZM_RATE_BASE; } else { - if ( !paused ) { + if (!paused) { int temp_index = MOD_ADD(temp_read_index, 0, temp_image_buffer_count); - // Debug( 3, "tri: %d, ti: %d", temp_read_index, temp_index ); SwapImage *swap_image = &temp_image_buffer[temp_index]; - if ( !swap_image->valid ) { + if (!swap_image->valid) { paused = true; delayed = true; temp_read_index = MOD_ADD(temp_read_index, (replay_rate>=0?-1:1), temp_image_buffer_count); @@ -628,7 +631,7 @@ void MonitorStream::runStream() { // If the next frame is due 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)) { @@ -646,7 +649,10 @@ void MonitorStream::runStream() { 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; } @@ -669,7 +675,7 @@ void MonitorStream::runStream() { } // end if (!paused) or step or paused } // end if have exceeded buffer or not - if ( temp_read_index == temp_write_index ) { + if (temp_read_index == temp_write_index) { // Go back to live viewing Warning("Rewound over write index, resuming live play"); // Clear paused flag @@ -680,11 +686,11 @@ void MonitorStream::runStream() { } } // end if ( buffered_playback && delayed ) - 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 - int index = monitor->shared_data->last_write_index % monitor->image_buffer_count; // % shouldn't be neccessary - if ( (frame_mod == 1) || ((frame_count%frame_mod) == 0) ) { - if ( !paused && !delayed ) { + int index = monitor->shared_data->last_write_index % monitor->image_buffer_count; + if ((frame_mod == 1) || ((frame_count%frame_mod) == 0)) { + if (!paused && !delayed) { 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)", index, frame_mod, frame_count, paused, delayed); @@ -700,8 +706,6 @@ void MonitorStream::runStream() { zm_terminate = true; break; } - //frame_sent = true; - // 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. @@ -714,11 +718,11 @@ void MonitorStream::runStream() { temp_read_index = temp_write_index; } else { - if ( delayed && !buffered_playback ) { + if (delayed && !buffered_playback) { Debug(2, "Can't delay when not buffering."); delayed = false; } - if ( last_zoom != zoom ) { + if (last_zoom != zoom) { Debug(2, "Sending 2 frames because change in zoom %d ?= %d", last_zoom, zoom); if (!sendFrame(paused_image, paused_timestamp)) zm_terminate = true; @@ -742,9 +746,9 @@ void MonitorStream::runStream() { } // end if paused or not } // end if should send frame - if ( buffered_playback && !paused ) { - if ( monitor->shared_data->valid ) { - if ( monitor->shared_timestamps[index].tv_sec ) { + if (buffered_playback && !paused) { + if (monitor->shared_data->valid) { + if (monitor->shared_timestamps[index].tv_sec) { int temp_index = temp_write_index%temp_image_buffer_count; Debug(2, "Storing frame %d", temp_index); if ( !temp_image_buffer[temp_index].valid ) { @@ -756,7 +760,7 @@ void MonitorStream::runStream() { 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); temp_write_index = MOD_ADD(temp_write_index, 1, temp_image_buffer_count); - if ( temp_write_index == temp_read_index ) { + if (temp_write_index == temp_read_index) { // Go back to live viewing Warning("Exceeded temporary buffer, resuming live play"); paused = false; @@ -801,37 +805,37 @@ void MonitorStream::runStream() { Warning("no last_frame_sent. Shouldn't happen. frame_mod was (%d) frame_count (%d)", frame_mod, frame_count); } - } // end while + } // end while ! zm_terminate - if ( buffered_playback ) { + if (buffered_playback) { Debug(1, "Cleaning swap files from %s", swap_path.c_str()); struct stat stat_buf = {}; - if ( stat(swap_path.c_str(), &stat_buf) < 0 ) { - if ( errno != ENOENT ) { + if (stat(swap_path.c_str(), &stat_buf) < 0) { + if (errno != ENOENT) { Error("Can't stat '%s': %s", swap_path.c_str(), strerror(errno)); } - } else if ( !S_ISDIR(stat_buf.st_mode) ) { + } else if (!S_ISDIR(stat_buf.st_mode)) { Error("Swap image path '%s' is not a directory", swap_path.c_str()); } else { std::string glob_pattern = stringtf("%s/*.*", swap_path.c_str()); glob_t pglob; int glob_status = glob(glob_pattern.c_str(), 0, 0, &pglob); - if ( glob_status != 0 ) { - if ( glob_status < 0 ) { + if (glob_status != 0) { + if (glob_status < 0) { Error("Can't glob '%s': %s", glob_pattern.c_str(), strerror(errno)); } else { Debug(1, "Can't glob '%s': %d", glob_pattern.c_str(), glob_status); } } else { - for ( unsigned int i = 0; i < pglob.gl_pathc; i++ ) { - if ( unlink(pglob.gl_pathv[i]) < 0 ) { + for (unsigned int i = 0; i < pglob.gl_pathc; i++) { + if (unlink(pglob.gl_pathv[i]) < 0) { Error("Can't unlink '%s': %s", pglob.gl_pathv[i], strerror(errno)); } } } globfree(&pglob); - if ( rmdir(swap_path.c_str()) < 0 ) { + if (rmdir(swap_path.c_str()) < 0) { Error("Can't rmdir '%s': %s", swap_path.c_str(), strerror(errno)); } } // end if checking for swap_path diff --git a/src/zm_monitorstream.h b/src/zm_monitorstream.h index 0dc07b067..04d2be25c 100644 --- a/src/zm_monitorstream.h +++ b/src/zm_monitorstream.h @@ -40,7 +40,6 @@ class MonitorStream : public StreamBase { Microseconds ttl; int playback_buffer; bool delayed; - int frame_count; protected: bool checkSwapPath(const char *path, bool create_path); @@ -61,8 +60,8 @@ class MonitorStream : public StreamBase { temp_write_index(0), ttl(0), playback_buffer(0), - delayed(false), - frame_count(0) {} + delayed(false) + {} void setStreamBuffer(int p_playback_buffer) { playback_buffer = p_playback_buffer; diff --git a/src/zm_stream.h b/src/zm_stream.h index d16e973ff..8650801ea 100644 --- a/src/zm_stream.h +++ b/src/zm_stream.h @@ -102,7 +102,6 @@ protected: int last_scale; int zoom; int last_zoom; - double maxfps; int bitrate; unsigned short last_x, last_y; unsigned short x, y; @@ -122,8 +121,14 @@ protected: SystemTimePoint now; SystemTimePoint last_comm_update; - double base_fps; - double effective_fps; + double maxfps; + double base_fps; // Should be capturing fps, hence a rough target + double effective_fps; // Target fps after taking max_fps into account + double actual_fps; // sliding calculated actual streaming fps achieved + SystemTimePoint last_fps_update; + int frame_count; // Count of frames sent + int last_frame_count; // Used in calculating actual_fps from frame_count - last_frame_count + int frame_mod; SystemTimePoint last_frame_sent; @@ -152,7 +157,6 @@ public: last_scale(DEFAULT_SCALE), zoom(DEFAULT_ZOOM), last_zoom(DEFAULT_ZOOM), - maxfps(DEFAULT_MAXFPS), bitrate(DEFAULT_BITRATE), last_x(0), last_y(0), @@ -164,7 +168,14 @@ public: sd(-1), lock_fd(0), paused(false), - step(0) + step(0), + maxfps(DEFAULT_MAXFPS), + base_fps(0.0), + effective_fps(0.0), + actual_fps(0.0), + frame_count(0), + last_frame_count(0), + frame_mod(1) { memset(&loc_sock_path, 0, sizeof(loc_sock_path)); memset(&loc_addr, 0, sizeof(loc_addr)); @@ -172,10 +183,6 @@ public: memset(&rem_addr, 0, sizeof(rem_addr)); memset(&sock_path_lock, 0, sizeof(sock_path_lock)); - base_fps = 0.0; - effective_fps = 0.0; - frame_mod = 1; - vid_stream = nullptr; msg = { 0, { 0 } }; }