Add stream_send_cli (V4L2 capture → TCP → VIDEO_FRAME) and stream_recv_cli (TCP → threaded frame slot → GLFW display) to exercise end-to-end streaming between two nodes on the same machine or across the network. Add include/stream_stats.h (header-only rolling-window fps/Mbps tracker) and include/v4l2_fmt.h (header-only V4L2 format enumeration shared between v4l2_view_cli and stream_send_cli). Refactor v4l2_view_cli to use the shared header. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
77 lines
1.9 KiB
C
77 lines
1.9 KiB
C
#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 <stdint.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
|
|
#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;
|
|
}
|