#pragma once /* * Lightweight per-stream statistics tracker. * Header-only; include wherever stream send/receive happens. * * Usage: * Stream_Stats s; * stream_stats_init(&s, stream_id); * * // on each frame: * stream_stats_record_frame(&s, byte_count); * * // periodically (e.g. after every frame): * if (stream_stats_tick(&s)) { * printf("%.1f fps %.2f Mbps\n", s.fps, s.mbps); * } */ #include #include #include #define STREAM_STATS_INTERVAL 0.5 /* recompute rates every 0.5 s */ typedef struct { uint16_t stream_id; /* Lifetime counters — never reset. */ uint64_t total_frames; uint64_t total_bytes; /* Rolling window — reset each time rates are computed. */ uint64_t window_frames; uint64_t window_bytes; struct timespec window_start; /* Last computed rates. */ float fps; float mbps; } Stream_Stats; static inline void stream_stats_init(Stream_Stats *s, uint16_t stream_id) { memset(s, 0, sizeof(*s)); s->stream_id = stream_id; clock_gettime(CLOCK_MONOTONIC, &s->window_start); } /* Call once per received/sent frame. */ static inline void stream_stats_record_frame(Stream_Stats *s, uint32_t nbytes) { s->total_frames++; s->total_bytes += nbytes; s->window_frames++; s->window_bytes += nbytes; } /* * Recompute fps and mbps if enough time has elapsed. * Returns 1 when rates were updated, 0 otherwise. */ static inline int stream_stats_tick(Stream_Stats *s) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); double elapsed = (double)(now.tv_sec - s->window_start.tv_sec) + (double)(now.tv_nsec - s->window_start.tv_nsec) * 1e-9; if (elapsed < STREAM_STATS_INTERVAL) { return 0; } s->fps = (float)((double)s->window_frames / elapsed); s->mbps = (float)((double)s->window_bytes * 8.0 / elapsed / 1e6); s->window_frames = 0; s->window_bytes = 0; s->window_start = now; return 1; }