From de19ad6ea1fb53a0f281ac8d39587f419db520ca Mon Sep 17 00:00:00 2001 From: flipflip Date: Mon, 27 Jul 2026 18:09:12 +0200 Subject: [PATCH] Add more stats to examples/camera_streaming --- .../camera_streaming/camera_streaming.cpp | 102 ++++++++++++------ 1 file changed, 70 insertions(+), 32 deletions(-) diff --git a/examples/camera_streaming/camera_streaming.cpp b/examples/camera_streaming/camera_streaming.cpp index 4aefdae..438de87 100644 --- a/examples/camera_streaming/camera_streaming.cpp +++ b/examples/camera_streaming/camera_streaming.cpp @@ -22,6 +22,7 @@ */ /* LIBC/STL */ +#include #include #include #include @@ -32,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -60,6 +60,28 @@ using namespace fpsdk::common::video; // --------------------------------------------------------------------------------------------------------------------- +// Statistics +struct Stats +{ + // clang-format off + static constexpr std::array PROB = {{ 0.5, 0.68, 0.95, 0.997 }}; + using Accumulator = boost::accumulators::accumulator_set>; + Accumulator lat { boost::accumulators::extended_p_square_probabilities = PROB }; // Latency receiving the data + Accumulator size { boost::accumulators::extended_p_square_probabilities = PROB }; // Size of the data + Accumulator exp { boost::accumulators::extended_p_square_probabilities = PROB }; // Exposure duration + Accumulator dec { boost::accumulators::extended_p_square_probabilities = PROB }; // Time decoding video + // clang-format on +}; + +// --------------------------------------------------------------------------------------------------------------------- + int main(int argc, char** argv) { #ifndef NDEBUG @@ -82,7 +104,8 @@ int main(int argc, char** argv) "1 for encoded video)\n" "Examples:\n" " camera_streaming 10.0.2.1 CAM1 HIRES_VID 1\n" - " camera_streaming 10.0.2.1 CAM1 HIRES_IMG 10"); + " camera_streaming 10.0.2.1 CAM1 HIRES_IMG 10\n" + " timeout -s SIGINT 60 camera_streaming ..."); return EXIT_FAILURE; } @@ -115,13 +138,7 @@ int main(int argc, char** argv) VideoFrameDecoderPtr decoder; // Statistics - using Accumulator = boost::accumulators::accumulator_set>; - Accumulator acc_lat; // Latency receiving the data - Accumulator acc_size; // Size of the data - Accumulator acc_dec; // Latency decoding video + Stats stats; // Stream data until we get SIGINT (CTRL-c) SigIntHelper sigint; @@ -129,14 +146,16 @@ int main(int argc, char** argv) std::size_t n_frames = 0; char info[1000]; bool ok = true; - TicToc tt_str; + const auto t_start = Time::FromClockRealtime(); while (ok && !sigint.ShouldAbort() && stream->NextFrame(data)) { // We'll calculate the latency from the time we received the data (now) and the data reference time. Note that // this requires the computer that runs this program being timesynced with the sensor (and the sensor being // timesynced, too, ideally with GNSS). Any error in timesync of the sensor or the computer affects the measured - // latency (could be to the better or to the worse). + // latency (could be to the better or to the worse). Also, we'll use the end of exposure as the reference time + // instead of the middle of exposure. const auto t_recv = Time::FromClockRealtime(); - const auto t_data = Time::FromPosixNs(data.ts_); + const auto t_expo = Duration::FromNSec(data.dt_); + const auto t_data = Time::FromPosixNs(data.ts_) + (t_expo * 0.5); n_frames++; // Generic info @@ -145,13 +164,16 @@ int main(int argc, char** argv) n_frames, data.valid_ ? "valid" : "invalid", CamIdToStr(data.cam_id_), CamDataTypeToStr(data.type_), CamDataFmtToStr(data.fmt_), CamDataFrmToStr(data.frm_), data.data_.size(), t_data.StrIsoTime(3).c_str(), Duration::FromNSec(data.dt_).GetSec() * 1e3); - acc_size((double)data.data_.size() / 1024.0); // [KiB] + + // Update statistics + stats.size((double)data.data_.size() / 1024.0); // [KiB] + stats.exp((double)t_expo.GetSec() * 1e3); // [ms] // Latency if (data.valid_) { const double lat = (t_recv - t_data).GetSec() * 1e3; // [ms] len += std::snprintf(&info[len], sizeof(info) - len, " -- latency: %+5.1f", lat); - acc_lat(lat); + stats.lat(lat); } // Decode video @@ -174,36 +196,52 @@ int main(int argc, char** argv) // Decoding adds latency const auto lat = tt.Toc().GetSec() * 1e3; // [ms] - len += std::snprintf(&info[len], sizeof(info) - len, " -- decode: %+4.1f", lat); - acc_dec(lat); + len += std::snprintf(&info[len], sizeof(info) - len, " -- decode: %+5.1f", lat); + stats.dec(lat); } } INFO("%s", info); } - const double t_str = tt_str.Toc().GetSec(); + const auto t_end = Time::FromClockRealtime(); + const auto t_str = (t_end - t_start).GetSec(); stream->Disconnect(); // Print stats NOTICE("Streamed %s %s %s %d for %.0fs (%" PRIuMAX " frames)", sensor.c_str(), CamIdToStr(cam_id), - CamDataTypeToStr(type), rate, t_str, boost::accumulators::count(acc_size)); - if (boost::accumulators::count(acc_lat) > 10) { - INFO("Latency receiving data [ms]: mean %4.1f (std %4.1f) min/median/max %4.1f %4.1f %4.1f", - boost::accumulators::mean(acc_lat), std::sqrt(boost::accumulators::variance(acc_lat)), - boost::accumulators::min(acc_lat), boost::accumulators::median(acc_lat), boost::accumulators::max(acc_lat)); + CamDataTypeToStr(type), rate, t_str, boost::accumulators::count(stats.size)); + if (boost::accumulators::count(stats.lat) > 10) { // clang-format off + INFO("Latency receiving data [ms]: mean %4.1f (std %4.1f) min/0.5/0.68/0.95/0.997/max %4.1f %4.1f %4.1f %4.1f %4.1f %4.1f", // clang-format on + boost::accumulators::mean(stats.lat), std::sqrt(boost::accumulators::variance(stats.lat)), + boost::accumulators::min(stats.lat), boost::accumulators::extended_p_square(stats.lat)[0], + boost::accumulators::extended_p_square(stats.lat)[1], boost::accumulators::extended_p_square(stats.lat)[2], + boost::accumulators::extended_p_square(stats.lat)[3], boost::accumulators::max(stats.lat)); + } + if (boost::accumulators::count(stats.dec) > 10) { // clang-format off + INFO("Latency decoding video [ms]: mean %4.1f (std %4.1f) min/0.5/0.68/0.95/0.997/max %4.1f %4.1f %4.1f %4.1f %4.1f %4.1f", // clang-format on + boost::accumulators::mean(stats.dec), std::sqrt(boost::accumulators::variance(stats.dec)), + boost::accumulators::min(stats.dec), boost::accumulators::extended_p_square(stats.dec)[0], + boost::accumulators::extended_p_square(stats.dec)[1], boost::accumulators::extended_p_square(stats.dec)[2], + boost::accumulators::extended_p_square(stats.dec)[3], boost::accumulators::max(stats.dec)); } - if (boost::accumulators::count(acc_dec) > 10) { - INFO("Latency decoding video [ms]: mean %4.1f (std %4.1f) min/median/max %4.1f %4.1f %4.1f", - boost::accumulators::mean(acc_dec), std::sqrt(boost::accumulators::variance(acc_dec)), - boost::accumulators::min(acc_dec), boost::accumulators::median(acc_dec), boost::accumulators::max(acc_dec)); + if (boost::accumulators::count(stats.exp) > 10) { // clang-format off + INFO("Exposure duration [ms]: mean %4.1f (std %4.1f) min/0.5/0.68/0.95/0.997/max %4.1f %4.1f %4.1f %4.1f %4.1f %4.1f", // clang-format on + boost::accumulators::mean(stats.exp), std::sqrt(boost::accumulators::variance(stats.exp)), + boost::accumulators::min(stats.exp), boost::accumulators::extended_p_square(stats.exp)[0], + boost::accumulators::extended_p_square(stats.exp)[1], boost::accumulators::extended_p_square(stats.exp)[2], + boost::accumulators::extended_p_square(stats.exp)[3], boost::accumulators::max(stats.exp)); } - if ((boost::accumulators::count(acc_size) > 10) && (t_str > 1.0)) { - INFO("Data size per frame [KiB]: mean %4.0f (std %4.0f) min/median/max %4.0f %4.0f %4.0f", - boost::accumulators::mean(acc_size), std::sqrt(boost::accumulators::variance(acc_size)), - boost::accumulators::min(acc_size), boost::accumulators::median(acc_size), - boost::accumulators::max(acc_size)); - INFO("Average data rate [KiB/s]: %.0f", boost::accumulators::sum(acc_size) / t_str); + if ((boost::accumulators::count(stats.size) > 10) && (t_str > 1.0)) { // clang-format off + INFO("Data size per frame [KiB]: mean %4.0f (std %4.0f) min/0.5/0.68/0.95/0.997/max %4.0f %4.0f %4.0f %4.0f %4.0f %4.0f", // clang-format on + boost::accumulators::mean(stats.size), std::sqrt(boost::accumulators::variance(stats.size)), + boost::accumulators::min(stats.size), boost::accumulators::extended_p_square(stats.size)[0], + boost::accumulators::extended_p_square(stats.size)[1], + boost::accumulators::extended_p_square(stats.size)[2], + boost::accumulators::extended_p_square(stats.size)[3], boost::accumulators::max(stats.size)); + const double avg = boost::accumulators::sum(stats.size) / t_str; + // Assuming GibE link TCP socket ~115MB/s = ~120500 KiB/s + INFO("Average data rate [KiB/s]: %.0f (~%.1f%%GigE)", avg, avg / 120500.0 * 1e2); } return ok ? EXIT_SUCCESS : EXIT_FAILURE;