Historical recipe — not current setup guidance. Measurements and implementation links below belong to their original workload and revision. Deployment labels and defaults may be obsolete. Use the reviewed performance recipes; browse historical evidence.
AVPlumber · Mixer optimization cookbook
Real 1080p inputs, no shortcuts
Implementation links are pinned to develop at c20464a5 (2026-10-09); read against develop at 8fa15c92 on 2026-10-13 and still current. Measurements retain their original workload and scope. Watch the current 192-input L4 demo.
Current scope. Capacity tests still require independent real-resolution inputs processed at native cadence. The eight small mixed-rate barcoded inputs are a correctness fixture, explicitly not a capacity qualification.
The capacity demo proves what real inputs cost: every scene source is its own input of at least 1080p25, with its own media, processed on every frame. The four downstream keys are separate browser inputs at their graphics dimensions; they are included in the 192-input total.
Status: Implemented- 1920×1080every scene clip, raw file and browser page; keys use their graphics dimensions
- 0files shared between generated sources
- ≈ 155 MBdisk and page cache per raw NV12 source (2 s clip at 25 fps)
- 0 framesadded to program or command-to-screen latency
Shared test media vs. real inputs
One source, one frame: where each rule applies
At a glance
- What
- Each generated source gets its own media: an NVDEC clip, a raw NV12/P010 file or a browser page. No two sources share a file.
- Its source ID is burned into every frame, on a plate at a spot and orbit phase seeded by that ID. Patterns rotate through a pool by source index.
- Browser scene pages render at 1920×1080 and show their ID in the page header. Key windows are 1016×172 (lower third), 1920×80 (ticker), 152×152 and 304×152 (corner bugs).
- The setup page is 1080p only; the 720p option is gone.
- Why
Capacity numbers must describe a real show. Shared files, smaller pictures or replayed GPU frames make every stage look cheaper than it is. A frozen source is visible too: its plate stops moving.
- Latency
None. The rule adds no node, queue or wait, so program and command-to-screen latency do not change.
- Side effects
- First preparation takes longer: every source renders its own clip.
- Portrait canvases show the 1920×1080 sources contained, with bars.
- Headline capacity is lower than a demo with shortcuts would show. That is the point.
- Cost
- 0 new nodes, 0 new queues, 0 new threads.
- Disk and page cache grow with the source count: a raw 1080p NV12 clip at 25 fps is ≈ 155 MB per 2 s, one per raw source.
- VRAM: nothing held for looped clips.
- Host memory, with
raw_upload: "resident"(on a branch; the demo show runs it): each raw file is held in page-locked memory after its first pass, 8.8 GB for 47 two-second clips. Every picture is still transferred to the GPU for every showing, as from a capture card that writes into page-locked memory (Input, decode and wake-ups). - GPU and CPU: full 1080p decode, upload or import on every frame, for every source. This is the honest load.
- Risk
If the raw files do not all fit in the page cache, they are read from disk at the combined rate every frame. Old media directories are not pruned; delete them by hand.
- Switch it off
No switch for the setup page. It is the capacity demo's ground rule. Custom recipes can still set other generation sizes, or use file and download inputs that several sources read.
Where in the code
- prepare_demo.py:
id_overlayburns the source ID into every frame; the plate position is seeded by the ID - prepare_demo.py: pattern picked per source index
- prepare_demo.py: one file per source, named by its ID
- prepare_demo.py and browser_alpha.html L24–26: each browser page carries its own ID
- setup_runtime.py: 1080p only, one fixed source size
- setup_runtime.py: 1920×1080 generation and browser windows; demo.example.json has no shared download inputs
- setup.html L251: the setup page's fixed source size, no resolution menu
- pyplumber/mixer/inputs.py: the decoder node, no resize parameter
- pyplumber/mixer/graph.py: the GPU clip cache holds wipe graphics, never sources; configured media wipes are preloaded. The current cut-only recording does not exercise them
- recipe.md · Generated media: per-source media and storage per format
Source links are pinned to the reviewed revision.
See also Ideas we measured and dropped: shared media, 720p, decode-side resize and GPU-held loops.