diff --git a/src/zm_monitorstream.cpp b/src/zm_monitorstream.cpp index 0df93f963..43e8e9976 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; @@ -520,7 +527,7 @@ void MonitorStream::runStream() { Image *paused_image = nullptr; struct timeval 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; @@ -529,27 +536,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"); @@ -560,14 +567,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()) { @@ -578,8 +584,9 @@ void MonitorStream::runStream() { gettimeofday(&now, nullptr); 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; @@ -591,35 +598,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 = 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); @@ -632,7 +635,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)) { @@ -650,10 +653,10 @@ void MonitorStream::runStream() { SwapImage *swap_image = &temp_image_buffer[temp_read_index]; // Send the next frame - if ( !sendFrame( + if (!sendFrame( temp_image_buffer[temp_read_index].file_name, - temp_image_buffer[temp_read_index].timestamp - ) ) { + temp_image_buffer[temp_read_index].timestamp) + ) { zm_terminate = true; } memcpy( @@ -680,7 +683,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 @@ -691,11 +694,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); @@ -710,9 +713,7 @@ void MonitorStream::runStream() { 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) ) { @@ -724,11 +725,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; @@ -752,9 +753,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 ) { @@ -772,7 +773,7 @@ void MonitorStream::runStream() { 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; @@ -815,16 +816,16 @@ 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 ) { + struct stat stat_buf = {}; + 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 { char glob_pattern[PATH_MAX] = ""; @@ -832,21 +833,21 @@ void MonitorStream::runStream() { snprintf(glob_pattern, sizeof(glob_pattern), "%s/*.*", swap_path.c_str()); glob_t pglob; int glob_status = glob(glob_pattern, 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, strerror(errno)); } else { Debug(1, "Can't glob '%s': %d", glob_pattern, 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 5730bfc5a..3f50ec7f6 100644 --- a/src/zm_monitorstream.h +++ b/src/zm_monitorstream.h @@ -41,7 +41,6 @@ class MonitorStream : public StreamBase { time_t ttl; int playback_buffer; bool delayed; - int frame_count; protected: bool checkSwapPath(const char *path, bool create_path); @@ -62,9 +61,9 @@ 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 6d752689d..e1652a886 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: struct timeval now; struct timeval 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; double last_frame_sent; @@ -154,7 +159,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), @@ -166,7 +170,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)); @@ -174,12 +185,8 @@ 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; - #if HAVE_LIBAVCODEC - vid_stream = 0; + vid_stream = nullptr; #endif // HAVE_LIBAVCODEC last_frame_sent = 0.0; last_frame_timestamp = {};