* 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]>
* 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]>
* add a test
* recognize as input format
* scaffold flac demuxer
* implement getting metadata
* Implement mime type
* read all metadata + deduplicate stubs
* Read first packet
* copyright headers
* read the first packet
* Get entire first packet, work on advancing
* iterate over all samples
* testable with bun
* stub out metadata support
* parse descriptive metadata
* All in 1 file
seems more appropriate to the philosophy
* some parameters are not needed anymore all within 1 class
* skip over bytes we are sure are not the syncword
* run prettier
* timestamp is determined based on passed blocks, not maximumBlockSize
* no binary search needed!
* simplifications
* Finish demuxer reading sequentially
* more tests + add a file with a seektable
* don't throw if (this.audioInfo.minimumBlockSize !== this.audioInfo.maximumBlockSize
* Add docs
* Update format compatibility table
* Simplification
* confirm conversion is working
* Finish
* Resolve TODO comment
* Support images (read-only)
* Returning description as Uint8Array
* Cleanup of demuxer
* Misc renames
* Object on same line
* Resolve first batch of comments
* Throw errors on corrupt blocks, correctly use requestSlice()
* Fix description field
* Explain why last frame is a bit shorter
* Add FLAC to README
* Put track backings below demuxer
* convert to methods
* Reorder container checking
* getBlockSize() -> readBlockSize()
* bitStream -> bitstream
* better naming for bytes
* use .skip()
* Don't return blockSize twice in readFlacFrameHeader
* Use enum + switch to distinguish Flac block types
* Use else-if
* Use else-if
* Compressed switch statement
* readCodedNumber
* Update flac-misc.ts
* We don't need the bits variable at all
* reorder functions in flac-demuxer
* Handle gracefully not being able to load another sample
* Update flac-demuxer.ts
* blockingbit null
* use async instead of promise.resolve
* use binary search
* Replace recursion with while loop
* Add mutex to getPacket()
* Load more data not in getPacketAtIndex, but outside
* Apply suggestion from @Vanilagy
Co-authored-by: David P. <[email protected]>
* computeDuration() reads last packet
* Update flac-demuxer.ts
* share vorbis comment reading logic
* reuse vorbis comment writing logic, set vendor always to "Mediabunny"
* flush after writign
* Use FileSlice.tempFromBytes
* assert !== null
* fixing nitpicks
* apply suggestions
* fix ogg
* We are now muxing images
* apply suggestion
* Update src/flac/flac-muxer.ts
Co-authored-by: David P. <[email protected]>
* apply suggestion
* readSampleRate()
* seek outside writeHeader()
* mention vorbis metadata + add to metadatatags comment
* should be able to -> can
* Add test in metadata tags
* Add test for packets being byte identical after remuxing
* compare to null
* no casting to uint8array
* make test pass
* Update flac-muxer.ts
* Call validateAudioChunkMetadata() and validateAndNormalizeTimestamp()
* `onFrame` option
* emit frames using onFrame
* Run prettier over files
* Fix FLAC PICTURE block logic, small other changes
* Update docs
* Remove .only modifier
* fix remuxing and add test
* Don't throw error if parsing fails in header, since hitting a syncword might just be coincidential
* Fix remaining type errors
---------
Co-authored-by: David P. <[email protected]>