v1.42.0
The biggest update yet: this one adds HLS read/write support to Mediabunny, a long-requested feature. HLS playlists consist of many files, each describing a small segment of media data. Mediabunny's HLS API completely abstracts this away: you can read HLS playlists as if they were single media files, meaning they plug into your existing logic without much issue. Same goes for writing!
Still, HLS brought a lot of new challenges to Mediabunny and required a lot of additions across the entire API surface to adequately solve. That's why even beyond HLS, the API is now much more flexible and powerful.
New features
- Added support for reading HLS playlists, facilitated by
HlsInputFormatand theHLSsingleton. Support for an arbitrary amount video and audio tracks, I-frame only tracks, VOD playlists, live playlists, encrypted playlists, DATE-TIME-tagged segments, BYTERANGE-addressed segments, and more. All segment file formats are supported (MPEG-TS, fMP4, CMAF, ADTS, MP3, ...). For a detailed guide, see the Reading HLS guide. - Added support for writing HLS playlists via
HlsOutputFormat. Supports arbitrary video/audio track configurations, master playlist configuration, both VOD and live writing, with fully configurable output file structure. All segment file formats are supported (MPEG-TS, fMP4, CMAF, ADTS, MP3, ...). For a detailed guide, see the Writing HLS guide. - Added
CmafOutputFormat, a way of writing Segmented MP4 files which are split into a segment file and a separate init file. - Added multi-file
InputsviaPathedSource; sources that can return other sources for a given file path.UrlSourceandFilePathSourceare pathed out of the gate; custom multi-file sources can be constructed usingCustomPathedSource. Required for reading HLS as it is multi-file. - Added multi-file
OutputsviaPathedTarget, which return a new target for a given file path. Fully customizable. Required for writing HLS as it is multi-file. - Added async getters for most data on
InputTrack, such as.getCodec(),.getDisplayWidth(), etc. Required due to lazy loading requirements added by HLS. - Added live tracks: tracks that are currently still generating media data. You can probe liveness with
InputTrack.isLive()and obtain a refresh interval viaInputTrack.getLiveRefreshInterval(), which you can use to poll the live edge for updates. - Added
Input.getDurationFromMetadata()andInputTrack.getDurationFromMetadata(), a new way to get a file's duration efficiently without needing to find the last packet. Instead, it extracts the duration from metadata in the file. If there is no such metadata,nullis returned. - Added an input track query system via
InputTrackQuery, allowing for expressing filtering and sorting of tracks. Useful for finding tracks in many-track inputs. Track queries are accepted byInput.getTracks(),Input.getVideoTracks(),Input.getAudioTracks(),Input.getPrimaryVideoTrack(), andInput.getPrimaryAudioTrack(). Addedasc,descandpreferhelpers to help write sorters. - Added input track pairability: a metric that describes if two tracks can be presented together. Can be checked via
a.canBePairedWith(b). Additional helper methods exist onInputTrack:.getPairableTracks(),.getPairableVideoTracks(),.getPairableAudioTracks(),.getPrimaryPairableVideoTrack(),.getPrimaryPairableAudioTrack(),.hasPairableTrack(),.hasPairableVideoTrack(),.hasPairableAudioTrack(). - Added a video pre-processing system via
VideoEncodingConfig.transform, which allows you to transform (resize/rotate/etc.) frames right before they get passed to the encoder. Useful for generating multiple HLS variants. - Added an audio pre-processing system via
AudioEncodingConfig.transform, which allows you to transform (resample/remix) audio data right before they get passed to the encoder. Useful for generating multiple HLS variants. - Added output track fan-out to the Conversion API: you can now create multiple output tracks from a single input track. Great for creating multiple renditions of a video track, for example.
- Added
OutputTrack,OutputVideoTrack,OutputAudioTrackandOutputSubtitleTrack, returned by theOutput.add*Trackmethods - Added an output track grouping system, used to define track pairings for HLS outputs. Create
OutputTrackGroups, then assign tracks to them viaBaseTrackMetadata.group. - Added
TrackDisposition.primaryto indicate that a track is the primary, main track. Corresponds to HLS'sDEFAULTattribute. - Added Unix epoch-relative tracks where timestamps are relative to Jan 1 1970. Useful for syncing data to a real-time clock. Exposed via
InputTrack.isRelativeToUnixEpoch(). Such tracks can also be written viaBaseTrackMetadata.isRelativeToUnixEpoch. - Added
InputOptions.formatOptions, a way to provide input format-specific configuration. For now, this can be used to provide decryption keys for DRM-protected content. - Added
Input.canRead(), resolving totrueiff Mediabunny can read the file. Input.getFirstTimestamp()now takes an optionalInputTrack[]as first argument; if provided, the first timestamp is only computed for the given tracks.Input.computeDuration()now takes two optional arguments:InputTrack[]andPacketRetrievalOptions. When tracks are provided, the duration is only computed for the given tracks. The packet retrieval options allow you to configure behavior for live streams usingskipLiveWait.- Added
InputOptions.initInput, a way to specify a separate init file that carries track initialization data. Can be used with segmented MP4 and MPEG-TS. - Added
OutputOptions.initTarget, which is used to write a separate init file for the formats that require it, such as CMAF. - Added
InputTrack.hasOnlyKeyPackets(), returningtruefor tracks that only contain key packets, such as audio tracks or #EXT-X-I-FRAME-STREAM-INF HLS tracks. - Added
InputTrack.getBitrate()andInputTrack.getAverageBitrate()for retrieving a track's peak and average bitrate respectively, as specified in file metadata. InputTrack.computeDuration()now accepts an optionalPacketRetrievalOptionsargument that can be used to configure behavior for live streams usingskipLiveWait.- Added
PacketRetrievalOptions.skipLiveWait, can be used to disable waiting for the live stream to catch up when requesting media data beyond the live edge. - Added
OutputOptions.onFinalize, a callback which is called right before Output finalization completes. BufferTargetnow takes an optional first argumentBufferTargetOptions, which can be used to set theonFinalizecallback which allows you to do work as soon as the buffer has been finalized.- Added
ConversionOptions.trackswhich can be'all'or'primary'; used to control the tracks that are considered for conversion. - More media sinks now accept
PacketRetrievalOptionsin their methods:AudioBufferSink,AudioSampleSink,CanvasSink,VideoSampleSink. Required for accessingskipLiveWait. - Added global decodability checker helper functions:
canDecode,canDecodeAudio,canDecodeVideo,getDecodableCodecs,getDecodableAudioCodecs,getDecodableVideoCodecs, - Added
Source/Targetranging; a new.slice()method returns aRangedSource/RangedTargetwhich maps to a subset of the original source/target. - Added a new reference counting system for sources via
SourceRef. A ref can be acquired viasource.ref(), and only when the last ref has been.free()d will the source be disposed. - Added
AppendOnlyStreamTarget, which is likeStreamTargetexcept it acceptsWritableStream<Uint8Array>, meaning it models purely sequential writes. - Added
EventEmitter, a new base class for listening to events via an.onmethod. Subclassed byInput,Output,SourceandTarget. - Added a
sourceevent forInput, emitted every time a new source is acquired - Added a
targetevent forOutput, emitted every time a new target is acquired - Added a
finalizedevent toTarget, emitted after the target has been finalized - Added
ConcurrentRunner, a helper class for orchestrating parallel async tasks; useful for coordinating parallel HTTP uploads. - MPEG-TS files no longer need to begin with a key frame, as long as the codec parameters are found somewhere in the remaining packets. Zero key frames can also be present, but then an
initInputis necessary. UrlSourcenow supports responses with unknown length (noContent-LengthorContent-Rangeheaders present)Conversion.onProgressnow receives a secondprocessedTimeargument- Added
timestampBaseoption forMediaStreamVideoTrackSourceandMediaStreamAudioTrackSource, allowing you to define the zero point for the media sample timestamps
Changes
getTracks()now always returns tracks in the order in which they appear in the input fileVideoEncodingConfig.keyFrameIntervalnow defaults to 2 seconds (was 5 previously)ConversionOptions.trim.startnow defaults to the start timestamp of all non-user-discarded tracks, instead of all tracks.
Deprecations
InputTrack.codec. Preferawait inputTrack.getCodec()instead.InputTrack.internalCodecId. Preferawait inputTrack.getInternalCodecId()instead.InputTrack.languageCode. Preferawait inputTrack.getLanguageCode()instead.InputTrack.name. Preferawait inputTrack.getName()instead.InputTrack.timeResolution. Preferawait inputTrack.getTimeResolution()instead.InputTrack.disposition. Preferawait inputTrack.getDisposition()instead.InputVideoTrack.codedWidth. Preferawait inputVideoTrack.getCodedWidth()instead.InputVideoTrack.codedHeight. Preferawait inputVideoTrack.getCodedHeight()instead.InputVideoTrack.displayWidth. Preferawait inputVideoTrack.getDisplayWidth()instead.InputVideoTrack.displayHeight. Preferawait inputVideoTrack.getDisplayHeight()instead.InputVideoTrack.squarePixelWidth. Preferawait inputVideoTrack.getSquarePixelWidth()instead.InputVideoTrack.squarePixelHeight. Preferawait inputVideoTrack.getSquarePixelHeight()instead.InputVideoTrack.pixelAspectRatio. Preferawait inputVideoTrack.getPixelAspectRatio()instead.InputVideoTrack.rotation. Preferawait inputVideoTrack.getRotation()instead.InputAudioTrack.numberOfChannels. Preferawait inputAudioTrack.getNumberOfChannels()instead.InputAudioTrack.sampleRate. Preferawait inputAudioTrack.getSampleRate()instead.Source.onread. Prefer.on('read', ...)instead.Target.onwrite. Prefer.on('write', ...)instead.
Fixes
- Fixed rare track closing race conditions in multiple muxers
- Fixed off-by-one reorder buffer error in MPEG-TS demuxer
- Fixed ISOBMFF muxer duration calculation
- Fixed multiple ISOBMFF trun boxes not being supported
- Fixed incorrect MP3 Xing TOC frame locations
- Codec string
'mp4a.40.34'is now correctly identified as MP3 UrlSourceno longer always requests byte 0 to determine the file size, it can do that from any starting offset nowReadableStreamSource's reader is now properly canceled on disposeUrlSource.parallelismactually now controlls the amount of parallel requests, guaranteed- Fixed missing null terminator at the end of TXXX ID3v2 frame
- Fixed being unable to access the file system in server-side environments when using the CommonJS build
- Fixed encoder/decoder extension packages struggling with huge timestamps beyond the int32 limit
Full list of API additions
New types/classes/functions
HLSHLS_FORMATSHlsInputFormatHlsOutputFormatHlsOutputFormatOptionsHlsOutputPlaylistInfoHlsOutputSegmentInfoCmafOutputFormatCmafOutputFormatOptionsFilePathPathedSourceCustomPathedSourcePathedTargetSourceRequestTargetRequestRangedSourceRangedTargetAppendOnlyStreamTargetSourceRefEventEmitterEventListenerOptionsSourceEventsTargetEventsInputEventsOutputEventsOutputTrackOutputVideoTrackOutputAudioTrackOutputSubtitleTrackOutputTrackGroupInputTrackQueryascdescprefercanDecodecanDecodeAudiocanDecodeVideogetDecodableCodecsgetDecodableAudioCodecsgetDecodableVideoCodecsAudioTransformOptionsVideoTransformOptionsUnsupportedInputFormatErrorConcurrentRunnerDurationMetadataRequestOptionsSetOptionalIsobmffInputFormatOptionsInputFormatOptionsBufferTargetOptionsPsshBoxMediaStreamAudioTrackSourceOptions
New fields
InputTrack.getCodecInputTrack.getInternalCodecIdInputTrack.getLanguageCodeInputTrack.getNameInputTrack.getTimeResolutionInputTrack.getDispositionInputTrack.hasOnlyKeyPacketsInputTrack.isRelativeToUnixEpochInputTrack.isLiveInputTrack.getLiveRefreshIntervalInputTrack.getBitrateInputTrack.getAverageBitrateInputTrack.getDurationFromMetadataInputTrack.canBePairedWithInputTrack.getPairableTracksInputTrack.getPairableVideoTracksInputTrack.getPairableAudioTracksInputTrack.getPrimaryPairableVideoTrackInputTrack.getPrimaryPairableAudioTrackInputTrack.hasPairableTrackInputTrack.hasPairableVideoTrackInputTrack.hasPairableAudioTrackInputVideoTrack.getCodedWidthInputVideoTrack.getCodedHeightInputVideoTrack.getRotationInputVideoTrack.getSquarePixelWidthInputVideoTrack.getSquarePixelHeightInputVideoTrack.getPixelAspectRatioInputVideoTrack.getDisplayWidthInputVideoTrack.getDisplayHeightInputAudioTrack.getNumberOfChannelsInputAudioTrack.getSampleRateInput.canReadInput.getDurationFromMetadataSource.sliceSource.refTarget.sliceInputOptions.initInputInputOptions.formatOptionsOutputOptions.initTargetOutputOptions.onFinalizeOutput.defaultTrackGroupBaseTrackMetadata.isRelativeToUnixEpochBaseTrackMetadata.groupVideoTrackMetadata.hasOnlyKeyPacketsAudioEncodingConfig.transformVideoEncodingConfig.transformPacketRetrievalOptions.skipLiveWaitTrackDisposition.primaryConversionOptions.tracksConversionVideoOptions.groupConversionAudioOptions.groupDiscardedTrack.trackOptionsMediaStreamVideoTrackSourceOptions.timestampBase