You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
perf: avoid materializing full camera channel in Episode.frames() when only timestamps are needed #687
Episode.frames() appears to materialize the full camera channel even though it only needs the channel timestamps to associate extracted frames with their source log times.
The video generation path already processes camera data in batches, which keeps memory usage bounded. However, after frame extraction, frames() calls the equivalent of:
self.channel(topic).timestamps.tolist()
self.channel(topic) constructs a complete ChannelData object and accumulates the channel payload across batches. For camera channels, this can mean retaining a large amount of encoded video data in memory solely to retrieve timestamps.
frames_at_indices() appears to use the same full-channel path.
Why this matters
For long camera episodes, the encoded video payload can be much larger than the timestamp array itself.
For example, a 3-hour 30 FPS stream contains about 324,000 timestamps. At 8 bytes per timestamp, the timestamp data is only around 2.6 MB, while the corresponding encoded camera payload may be hundreds of megabytes.
This means frame extraction may use significantly more peak memory than necessary even though the underlying video path is otherwise streamed.
Expected behavior
Frame-related APIs that only need camera timestamps should read only the timestamp/log-time column instead of materializing the complete channel payload.
Possible approach
Add an internal timestamp-only helper that iterates over channel batches and collects only log_times, for example:
Then use this path in frames() / frames_at_indices() instead of calling self.channel(topic).
It may also be worth allowing the timestamp-mapping code to operate directly on a NumPy array or other sequence to avoid an additional .tolist() allocation.
Benchmark
Before and after the change, benchmark a reasonably long camera episode using:
episode.frames(fps=1)
and:
episode.frames_at_indices(...)
Measure:
peak RSS / memory usage
wall-clock execution time
returned frame count
returned log_time_ns values
The optimized implementation should produce identical timestamps and frames while reducing peak memory usage.
Scope
This should be a performance-only change with no change to the public behavior of Episode.frames() or Episode.frames_at_indices().
Confirmed. frames() (src/hflow/episode.py:772) and frames_at_indices() (:813) call self.channel(topic) only for timestamps. That buffers every encoded payload, and channel() caches the result, so it stays in memory until the episode closes. A timestamp-only helper like the one you sketched is the right fix. Reuse a cached ChannelData when one already exists. A test that the frame log times are unchanged and that frames() leaves nothing in the channel cache is enough; no benchmark needed.
Activity
kstonekuan commentedon Oct 4, 2026
Confirmed.
frames()(src/hflow/episode.py:772) andframes_at_indices()(:813) callself.channel(topic)only for timestamps. That buffers every encoded payload, andchannel()caches the result, so it stays in memory until the episode closes. A timestamp-only helper like the one you sketched is the right fix. Reuse a cachedChannelDatawhen one already exists. A test that the frame log times are unchanged and thatframes()leaves nothing in the channel cache is enough; no benchmark needed.perf: avoid caching camera payloads during frame extraction (Hebbian-…