Commit 8fae89d
feat: stop the picamera2 capture loop when no consumers
Building on the previous LazyEncoder commit, this commit ref-counts the
Picamera2 instance itself: the camera only runs while at least one
encoder is active. When the last encoder is released, picam2.stop() is
called; on the next consumer, picam2.start() runs again.
Adds a small CameraSession wrapper next to LazyEncoder; each LazyEncoder
takes an optional session and acquires/releases it together with the
underlying encoder, so the camera is the union of the encoders' refs.
Measured CPU impact, applied on top of the previous commit (Raspberry
Pi 4B, Camera Module 3, hardware encoders, sampled with `top`):
Default config (640x480 @ 15 FPS):
Idle (no clients): ~5% -> ~0%
Live MJPEG / WebRTC client: unchanged
Heavier config (1920x1080 @ 30 FPS):
Idle (no clients): ~15% -> ~0%
Live WebRTC client: ~60% (unchanged)
Cumulative effect of both commits at 1080p30:
Idle: ~95-100% -> ~0%
Live WebRTC: ~120-135% -> ~60%
Cold-start latency on first connect (camera off -> on -> first JPEG):
~150-500 ms for /snapshot at 1080p30, dominated by libcamera sensor
init and AE/AWB warm-up. The first cold start after process boot is
typically slowest (~500 ms); subsequent cold starts are faster
(~150-200 ms) since some libcamera state appears to be retained.
There is no warm path while no consumers are active: every snapshot
released triggers a full camera stop.
Implementation notes:
- CameraSession.acquire/release are protected by a threading.Lock and
roll back the refcount if picam2.start() raises, mirroring the
LazyEncoder pattern.
- LazyEncoder.acquire takes the session ref before calling start_encoder
so the camera is always running when the encoder starts. release does
the inverse: stop_encoder first, then drop the session ref. If
start_encoder fails, the session ref is rolled back too.
- Lock acquisition order is consistent (encoder lock then session lock),
so two encoders sharing one session cannot deadlock.
- CSI.stop() now defensively calls picam2.stop_encoder() and
picam2.stop() under try/except, since at systemd shutdown the camera
may already be stopped (no consumers) and stop_encoder/stop would
otherwise raise.
- USB camera path is unaffected; only csi.py wires the session in.
All 129 existing unit tests pass.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>1 parent b297ece commit 8fae89d
2 files changed
Lines changed: 62 additions & 9 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
8 | | - | |
| 8 | + | |
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
| |||
42 | 42 | | |
43 | 43 | | |
44 | 44 | | |
| 45 | + | |
45 | 46 | | |
46 | | - | |
| 47 | + | |
47 | 48 | | |
48 | 49 | | |
49 | 50 | | |
50 | 51 | | |
51 | 52 | | |
52 | | - | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
53 | 57 | | |
54 | 58 | | |
55 | 59 | | |
56 | | - | |
57 | 60 | | |
58 | 61 | | |
59 | 62 | | |
| |||
67 | 70 | | |
68 | 71 | | |
69 | 72 | | |
70 | | - | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
2 | 2 | | |
3 | | - | |
4 | | - | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
5 | 11 | | |
6 | 12 | | |
7 | 13 | | |
8 | 14 | | |
9 | 15 | | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
10 | 41 | | |
11 | | - | |
| 42 | + | |
12 | 43 | | |
13 | 44 | | |
14 | 45 | | |
15 | 46 | | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
16 | 50 | | |
17 | 51 | | |
18 | 52 | | |
19 | 53 | | |
| 54 | + | |
20 | 55 | | |
21 | 56 | | |
22 | 57 | | |
| |||
25 | 60 | | |
26 | 61 | | |
27 | 62 | | |
| 63 | + | |
| 64 | + | |
28 | 65 | | |
29 | 66 | | |
30 | 67 | | |
31 | 68 | | |
32 | 69 | | |
33 | 70 | | |
34 | 71 | | |
| 72 | + | |
| 73 | + | |
35 | 74 | | |
36 | 75 | | |
37 | 76 | | |
| |||
42 | 81 | | |
43 | 82 | | |
44 | 83 | | |
| 84 | + | |
| 85 | + | |
45 | 86 | | |
46 | 87 | | |
47 | 88 | | |
| |||
0 commit comments