* Fix orphaned queued reads when a freed worker slot is stolen concurrently
ReadOrchestrator.runWorker's finally callback dequeues the oldest queued
read and asserts that createWorker succeeds ("we just freed up a worker").
That assumption races: the callback runs on a later microtask than the
worker's stop, and concurrent read() calls in that gap can LRU-evict the
freed worker and saturate every slot. The assert then throws as an
unhandled rejection after the read was removed from the queue but before
it was attached to any worker - its pending slices' promises never settle
and the awaiting reads hang forever.
Observed in production-like load (a 4-source composition player): 25
back-to-back occurrences saturating both workers, leaving clips
permanently undecodable.
Fix: create the worker first; only dequeue the read once a slot was
actually obtained. If every slot is busy, leave the read queued - each
running worker drains the queue from this same block when it stops, so
the read is picked up by whichever worker stops next.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
* Update logic
---------
Co-authored-by: Claude Opus 4.8 <[email protected]>
Co-authored-by: Vanilagy <[email protected]>
* fix: release targets from Output._targets on finalize
Long-running HLS transcodes leak memory. Every finalized BufferTarget
stays in _targets until the outer Output closes, pinning its buffer.
Writer.finalize() already does this cleanup for writer-based flows;
extend it to buffer-finalize paths via the public 'finalized' event.
* fix: ReadOrchestrator LRU eviction picks only drained workers
assert(pendingSlices.length === 0) fires under heavy concurrent reads
(e.g. multi-rendition HLS decode from BlobSource). LRU filter only
checked !running; workers with queued slices could be evicted.
Add pendingSlices.length === 0 to the filter.
* fix: export AppendOnlyStreamTarget from index
Missing from the re-export; public docs import it by name.
* fix: join HLS init segment path with root + playlist path
Init path went through _getTarget bare; segments got joined with rootPath + playlist.path. Playlist-relative URI then can't resolve when the playlist lives in a subdirectory.
* Fix targets not being cleaned up, fix paused workers with remaining pending slices, modify doc block, fixed isRoot not being changed on proxied requests
---------
Co-authored-by: Vanilagy <[email protected]>
- Add support for fMP4 segments
- Add initInput (supported by ISOBMFF and MPEG-TS)
- Input.isSupported()
- Refactored file size retrieval logic, the file size can now be retrieved alongside the first read.
- Add support for unsized UrlSources
- Add support for multiple trun boxes in a row for the same track (as the spec literally says lol)
- Add support for more M3U8 features
- Fix faulty line reader
- MPEG-TS improvements: support video parameters not in first packet, support better key frame detection, support extension PES packets without PTS
- Fix reorder buffer being 1 element too small