Add csv output for latency benchmarks to local_video example - #1320
Add csv output for latency benchmarks to local_video example#1320chenosaurus wants to merge 5 commits into
Conversation
chenosaurus
commented
Aug 6, 2026
- add logging output of the video pipeline timing metrics to csv
- add python script to generate report from logged csv
| if updated_sample.is_complete() { | ||
| self.latest_complete_sample = Some(updated_sample); | ||
| if let Some(frame_log) = self.frame_log.as_mut() { | ||
| if let Err(error) = frame_log.record(updated_sample) { | ||
| warn!("Publisher CSV logging disabled after write failure: {error}"); | ||
| self.frame_log = None; | ||
| } | ||
| } |
There was a problem hiding this comment.
🟡 Publisher metrics file records the same video frame several times when multiple quality layers are published
Each extra timing notification for a frame that already has all of its stages filled in writes another row for that frame (frame_log.record(updated_sample) at examples/local_video/src/publisher.rs:739) instead of only writing the frame once, so the metrics file contains repeated entries for the same frame.
Impact: With simulcast publishing, the generated CSV and PDF report show several times more frames than were really sent, with near-zero frame intervals and blank frame-gap values, making the latency/loss numbers misleading.
Why extra timing events arrive per frame and how they duplicate rows
PublisherTimingState::record_sdk_event (examples/local_video/src/publisher.rs:715-747) keys samples by capture timestamp and calls PublisherCsvLogger::record on every event whose sample is_complete(). is_complete() becomes true as soon as encoder-upload, encoder-output and packetize timestamps are all present, and it stays true for all later events with the same capture timestamp.
In webrtc-sys/src/packet_trailer.cpp:228-266, TransformSend emits EncoderOutput and WebrtcPacketize per transformed frame per SSRC. With --simulcast there are multiple SSRCs/layers per captured frame, all carrying the same user_timestamp and frame_id, so the same sample is re-completed several times and record() writes an additional CSV row each time.
Duplicate rows increment sample_count, set packetize_interval_ms to the tiny inter-layer delta, and produce empty frame_id_gap (because frame_id.checked_sub(previous) is 0 and checked_sub(1) yields None). The Python report then counts these rows as distinct frames (examples/local_video/scripts/generate_frame_report.py:436) and uses the intervals for freeze inference (examples/local_video/scripts/generate_frame_report.py:135-147).
Prompt for agents
In examples/local_video/src/publisher.rs, PublisherTimingState::record_sdk_event calls PublisherCsvLogger::record for every SDK timing event whose sample is already complete. Because libwebrtc emits EncoderOutput/WebrtcPacketize per encoded layer (see webrtc-sys/src/packet_trailer.cpp TransformSend, which runs once per SSRC), a simulcast publish re-completes the same capture-timestamp sample multiple times and writes duplicate CSV rows for one captured frame. Fix by only logging on the transition from incomplete to complete: capture whether the sample was complete before applying the event and record only when it just became complete. Alternatively, make PublisherCsvLogger ignore samples whose frame_id/capture timestamp equals the last logged one.
Was this helpful? React with 👍 or 👎 to provide feedback.