Files
mediabunny/changes-and-fixes.txt
T
2026-04-16 18:27:51 +02:00

199 lines
9.2 KiB
Plaintext

================================================================================
MEDIABUNNY HLS BRANCH - BUG FIXES AND BEHAVIOR CHANGES TO EXISTING CODE
For use in release notes. Only covers changes to pre-existing code.
New HLS/CMAF features are not listed here.
================================================================================
============================================================
BUG FIXES
============================================================
1. SourceRef race conditions (commit aa810fc)
- Source cache entry was added BEFORE the reference was fully created,
allowing premature garbage collection of cached sources
- Cache eviction variable pointed to wrong ref (local instead of entry)
- `count > MAX_SOURCE_CACHE_SIZE` off-by-one -> `count >= MAX_SOURCE_CACHE_SIZE`
- Input.source and Input.target getters could return unused/stale instances
when using async callbacks; now properly tracked via _getRootSourceRef()
2. Track closing race conditions in all muxers (commit 94678dd)
- ISOBMFF, Matroska, MPEG-TS, and OGG muxers used `trackData.track.source._closed`
to check if tracks were closed. This was racy because the closed state could
change between check and use. Added explicit `closed: boolean` field to all
muxer track data structures, set synchronously in onTrackClose().
3. Target.slice() validation bug (commit 7b70756)
- Validation used `!Number.isInteger(offset) && offset < 0` (AND), meaning
negative non-integer offsets slipped through. Fixed to use OR (`||`).
4. MPEG-TS demuxer: off-by-one errors in reorder buffer logic
- Rewind loop changed from `reorderSize` to `reorderSize + 1` iterations,
fixing packet duration calculation near seek points
- End-of-stream rewind loop changed from `reorderSize - 1` to `reorderSize`
- Flush condition changed from `>= reorderSize` to `> reorderSize`, keeping
one extra packet in the buffer before flushing for correct presentation
order computation
5. MPEG-TS demuxer: first chunk assertion crash (line 1031-1035)
- Old code asserted that a key frame is always found in the first chunk,
crashing on files where that assumption doesn't hold (e.g., HLS segments
starting mid-GOP). Changed to gracefully return null.
6. MPEG-TS demuxer: video parameters only searched in first packet
- Some muxers place SPS/PPS in later packets. The demuxer now loops through
multiple packets to find AVC/HEVC decoder configuration records instead of
only checking the first one.
7. ISOBMFF: duration calculation didn't account for sample duration
- `lastPresentedSample()` found the sample with the highest timestamp but
didn't add its duration. Replaced with `presentationSpan()` that correctly
computes `maxEndTimestamp - minTimestamp`.
8. ISOBMFF demuxer: assertion crash on unavailable data
- Demuxer asserted that read slices are non-null. Changed to gracefully
return null when data is outside available range (important for streaming/
progressive scenarios).
9. ISOBMFF demuxer: multiple trun boxes per fragment rejected
- Old code logged a warning and skipped the second trun box. Now correctly
accumulates samples across multiple trun boxes per track per fragment,
maintaining cumulative offset and timestamp state.
10. Conversion API: track count validation before fan-out consideration
(commit 2f576aa)
- Tracks were validated against the max count before considering that some
track options had `discard: true`. Now validates inside the fan-out loop.
11. MP3 muxer: frame positions recorded at wrong offset
- Frame byte positions were recorded AFTER writing packet data. Now recorded
BEFORE writing, which is correct for Xing TOC frame offset calculations.
12. FLAC demuxer: missing STREAMINFO validation
- Added explicit error when STREAMINFO metadata block is missing,
producing a clear "Corrupted FLAC file" message instead of undefined
behavior downstream.
============================================================
BEHAVIOR CHANGES
============================================================
1. Default keyFrameInterval changed from 5 seconds to 2 seconds
(commit c6e505a)
Aligns with default HLS segment duration. Affects all video encoding
that doesn't explicitly set keyFrameInterval.
2. Conversion API copies input pairability graph by default (commit 6410ea9)
When track group is not explicitly specified, conversion now auto-creates
OutputTrackGroups that mirror the input track pairing relationships. This
means converted outputs preserve which tracks are meant to play together.
3. Matroska demuxer: removed implicit track sorting by default disposition
Tracks are no longer sorted so that default=true tracks come first.
Now all tracks have `primary: false` by default. Callers should use the
getPrimaryVideoTrack()/getPrimaryAudioTrack() methods for selection.
4. Removed superfluous end-position seeks in muxer finalize methods
(commit 7b70756)
MP3, FLAC, and Matroska muxers no longer seek to the end of file after
writing final metadata. The seek was unnecessary since the writer is
done at that point.
5. clampCropRectangle now returns a new object instead of mutating input
(src/sample.ts:1123)
6. Date.now() -> performance.now() in FinalizationRegistry callback
(src/sample.ts:48)
Uses monotonic time for timing measurements.
7. Codec string parsing: mp4a.40.34 now correctly identified as MP3
(src/codec.ts:677-686)
Previously would have matched the aac prefix check. MP3 check now
runs first and includes this codec string.
8. UrlSource: servers without Content-Length now supported
Previously, if the server returned 200 without a Content-Length header,
UrlSource threw an error. Now it gracefully handles this by downloading
the entire resource with an unbounded worker (targetPos = Infinity,
strictTarget = false), determining file size once the stream ends.
9. UrlSource: file size probing request removed
The old UrlSource always made a dedicated initial `Range: bytes=0-`
request solely to probe file size and range request support. File size
is now determined lazily from the response headers of the first actual
read, removing the extra round-trip.
10. UrlSource: non-range-request server warnings deduplicated per origin
The "server did not respond with 206 Partial Content" warning is now
emitted at most once per origin instead of on every request.
11. ReadableStreamSource: reader now canceled on dispose
ReadableStreamSource._dispose() now calls `this._reader?.cancel()`,
properly releasing the underlying stream resource.
12. ReadOrchestrator: worker queue system
When the maximum worker count is reached, reads are now queued and
dispatched when a worker becomes free, instead of evicting running
workers which could abort in-flight fetches.
============================================================
DEPRECATIONS
============================================================
1. InputTrack sync property getters (commit 051578c)
All sync getters on InputTrack/InputVideoTrack/InputAudioTrack are now
deprecated in favor of async methods:
.codec -> await .getCodec()
.languageCode -> await .getLanguageCode()
.name -> await .getName()
.timeResolution -> await .getTimeResolution()
.disposition -> await .getDisposition()
.displayWidth -> await .getDisplayWidth()
.displayHeight -> await .getDisplayHeight()
.rotation -> await .getRotation()
(etc.)
The sync getters still work for non-HLS inputs but throw when the
backing requires async resolution (e.g., HLS tracks before hydration).
2. Source.onread callback -> source.on('read', handler)
The onread setter still works but is marked @deprecated.
3. Target.onwrite callback -> target.on('write', handler)
Same as above.
============================================================
REMOVALS
============================================================
1. Target.onfinalized callback (commit 6410ea9)
Removed entirely. Use the 'finalized' event: target.on('finalized', ...).
2. InputTrackDescriptor concept (commit 051578c)
The entire InputTrackDescriptor API was removed. Its functionality
(pairable tracks, primary track selection) is now directly on InputTrack.
3. InputTrack[] option for ConversionOptions.tracks (commit 606ee87)
ConversionOptions.tracks now only accepts 'all' | 'primary', no longer
accepts an array of InputTrack instances.
4. Unnecessary sync getter wrappers (commit 8241820)
Removed deprecated sync getters for: hasOnlyKeyPackets, bitrate,
averageBitrate, isRelativeToUnixEpoch on InputTrack.
============================================================
API ADDITIONS (for context, not release-note-worthy on their own)
============================================================
- PacketRetrievalOptions.skipLiveWait (fixes #342)
- DiscardedTrack.trackOptions field
- TargetRequest.mimeType
- TrackDisposition.primary
- Source/Target/Output extend EventEmitter
- CanvasSink methods now async generators (getCanvas, canvases, canvasesAtTimestamps)
- EncodedPacketSink.getFirstPacket/getPacket/getNextPacket now async
- Muxer writers deferred to start() instead of constructor