Decode video frames at the publish rate, not the stream rate - #106
Merged
leandropineda merged 1 commit intoJul 29, 2026
Merged
Conversation
The grab loop held capture_mutex across every grab(), so get_frame_jpg() had to wait for the lock on each publish -- with a blocking network grab in between, that starved publishing for seconds at a time. And retrieve() ran once per publish on a capture whose every frame had already been decoded, paying the YUV->BGR conversion and copy again (4.5ms vs 7.1ms per frame at 1080p: 13.5% vs 21.3% of a core at 30fps). Only the capture thread touches self.capture now, so the grab loop takes no lock: it drains the stream with grab() and converts a frame into a buffer at twice the publish rate. get_frame_jpg() encodes whatever is in the buffer and never touches the capture. Frame size comes from the frame itself instead of two CAP_PROP queries per publish. Tests: 1 new case in test_video.py (grabs >> retrieves, publishing does not touch the capture).
leandropineda
force-pushed
the
perf/video-decode-throttle
branch
from
July 29, 2026 11:23
392975c to
42898e5
Compare
leandropineda
force-pushed
the
fix/video-capture-recovery
branch
from
July 29, 2026 11:23
3f09480 to
3d3d6be
Compare
This was referenced Jul 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #105.
Two costs in the capture loop:
capture_mutexacross everygrab(), soget_frame_jpg()waited on the lock at each publish — with a blocking network grab in between, publishing starved for seconds;retrieve()ran per publish on framesgrab()had already decoded, paying the YUV→BGR conversion and copy twice (4.5ms vs 7.1ms per frame at 1080p — 13.5% vs 21.3% of a core at 30fps).Now only the capture thread touches
self.capture, so the loop takes no lock: it drains withgrab()and converts into a buffer at twice the publish rate.get_frame_jpg()encodes the buffer and never touches the capture. Frame size comes from the frame instead of twoCAP_PROPqueries per publish.Tests: 1 new case (grabs >> retrieves; publishing doesn't touch the capture). Suite: 149 passed, flake8/black clean.