* 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 BufferTarget.onFinalize option for awaitable async action on finalize
The `finalized` event fires synchronously and its return value is ignored,
making it unsuitable for use cases where the muxer should wait (e.g.
uploading the buffer to S3, R2, or other object stores that require a
known Content-Length and therefore can't stream via StreamTarget).
Adds a new `BufferTargetOptions` type with an `onFinalize` callback that
the muxer awaits before resolving. Matches the existing callback pattern
used by `HlsOutputFormatOptions.onSegment`, `onMaster`, etc.
When used with PathedTarget, this provides proper backpressure: the next
segment won't start being produced until the previous one has finished
uploading, keeping memory bounded regardless of video length.
- Adds `BufferTargetOptions` type, exported from the package root
- `BufferTarget` constructor now accepts optional options (backward compatible)
- `_finalize()` awaits `onFinalize` before emitting the `finalized` event
- Adds runtime validation for non-function callbacks
- Updates "Upload to a server" docs in writing-hls.md with S3 pattern
- Documents `onFinalize` in writing-media-files.md BufferTarget section
- Adds tests for callback invocation, async awaiting, backward compat, and validation
* Add ConcurrentRunner, add OutputOptions.onFinalize, adjust docs accordingly, clean up tests
* give me more control baby
* forgot to tell about it
* polish guide and js docs
* vanilagy says remove this, docs will reveal it
---------
Co-authored-by: Vanilagy <[email protected]>
* implement in FlacOutputFormatOptions
* implement in flac-muxer.ts
* Fix demuxer: Handle minimumFrameSize = 0, maxiumFrameSize = 0
* add a test
* Update flac-demuxer.ts
* Update flac.test.ts
* clean up comments for minima and maxima
* Add FlacOutputFormatOptions.appendOnly to docs
---------
Co-authored-by: Vanilagy <[email protected]>
* Fix CTS=0 in fragmented fMP4 with multiple tracks
When muxing fragmented MP4 with both video and audio tracks,
compositionTimeOffset (CTS) was zero for all video samples, causing
B-frame content to display in decode order instead of presentation
order (visible judder).
Root cause: During finalize(), interleaveSamples(true) triggers
finalizeFragment() via the cross-track keyframe check in
addSampleToTrack. This writes the trun box before processTimestamps
has computed correct decodeTimestamp values, so CTS = PTS - DTS = 0.
Fix: Call processTimestamps() for all tracks at the start of
finalizeFragment(). This is safe because processTimestamps is a no-op
when the timestampProcessingQueue is empty.
Video-only fragmented muxing was unaffected because the single-track
case never triggers the cross-track keyframe check during
interleaveSamples.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
* Fix the problem at the actual root
* Oopsie doopsie
---------
Co-authored-by: Claude Opus 4.6 <[email protected]>
Co-authored-by: Vanilagy <[email protected]>