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
Add demux codec_mutex contention guidance to autoresearch prompt (#1503)
Add a "Demux contention: FFmpeg's `codec_mutex`" subsection to the
optimization strategies prompt, explaining the root cause of demux
scaling issues: FFmpeg's process-wide `codec_mutex` serializes
`codec->init()` for decoders flagged `FF_CODEC_CAP_NOT_INIT_THREADSAFE`
(external libraries with unknown thread-safety). Recommends splitting
demux and decode into separate pipeline stages with at most 3
concurrency for demux, applicable to both CPU and NVDEC decode paths.
Also updates the NvDec section with an MTP example showing the split
pattern.
This effect is most pronounced for operations that are inherently fast (data copying, demuxing, disaggregation), where the operation itself is cheap but contention from concurrent scheduling inflates the observed per-item latency. For slow operations (network I/O, heavy CPU compute), higher concurrency is still beneficial because the parallelism gains outweigh the contention cost.
199
199
200
+
### Demux contention: FFmpeg's `codec_mutex`
201
+
202
+
Demuxing contention is not just generic thread scheduling overhead — there is a specific root cause inside FFmpeg. Every `Demuxer` construction calls `avformat_find_stream_info`, which probes each stream by opening a decoder via `avcodec_open2`. For codecs backed by external libraries (e.g. libvpx, libaom, libopus) whose thread-safety guarantees are unknown to FFmpeg, this initialization is guarded by a process-wide `codec_mutex` (`FF_CODEC_CAP_NOT_INIT_THREADSAFE` flag). At even modest concurrency (4+ threads), demux threads serialize on this lock and per-item latency rises sharply without improving throughput.
203
+
204
+
**Recommendation:** always split demuxing and decoding into separate pipeline stages with independent concurrency, and assign **at most 3 concurrency** to the demux stage. This allows the decode stage to use higher concurrency independently (or leverage NVDEC hardware decoders) without being bottlenecked by the demux lock:
205
+
206
+
```python
207
+
# Split demux and decode with independent concurrency
208
+
pipeline = (
209
+
PipelineBuilder()
210
+
.add_source(source)
211
+
.pipe(fetch, concurrency=16)
212
+
.pipe(demux, concurrency=3) # at most 3 — codec_mutex contention
213
+
.pipe(decode, concurrency=8) # decode can scale independently
214
+
.aggregate(batch_size)
215
+
.pipe(collate)
216
+
.add_sink(buffer_size=3)
217
+
)
218
+
```
219
+
200
220
### Search strategy
201
221
202
222
When tuning a stage's concurrency — especially for fast operations:
Higher concurrency values (e.g., c=16) still work — excess tasks wait for an engine — but waste thread resources on waiting. Setting concurrency to match the hardware count (c=7) is marginally more efficient.
256
276
277
+
**Always split demux and decode into separate stages** (see "Demux contention" above). Demuxing should be limited to 2-3 concurrency due to FFmpeg's `codec_mutex`, while decode — whether CPU or NvDec — can scale independently. Combining them in a single stage forces decode concurrency to match the demux bottleneck. With NvDec, the MTP pattern works particularly well because demuxed packets are picklable and can cross the subprocess boundary:
When the pipeline decodes video with `spdl.io.load_video` / `spdl.io.decode_packets`, the underlying FFmpeg decoder uses **a single thread by default**. This is a deliberate SPDL design choice — concurrency is expected to come from running many decoders in parallel at the pipeline level — but for some workloads (high-resolution video, low pipeline concurrency, or CPU headroom available) raising the per-decoder thread count is faster overall.
0 commit comments