Skip to content

v1.42.0

Choose a tag to compare

@Vanilagy Vanilagy released this 28 Apr 15:28
· 12 commits to main since this release
2207c7d

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 HlsInputFormat and the HLS singleton. 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 Inputs via PathedSource; sources that can return other sources for a given file path. UrlSource and FilePathSource are pathed out of the gate; custom multi-file sources can be constructed using CustomPathedSource. Required for reading HLS as it is multi-file.
  • Added multi-file Outputs via PathedTarget, 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 via InputTrack.getLiveRefreshInterval(), which you can use to poll the live edge for updates.
  • Added Input.getDurationFromMetadata() and InputTrack.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, null is 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 by Input.getTracks(), Input.getVideoTracks(), Input.getAudioTracks(), Input.getPrimaryVideoTrack(), and Input.getPrimaryAudioTrack(). Added asc, desc and prefer helpers 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 on InputTrack: .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, OutputAudioTrack and OutputSubtitleTrack, returned by the Output.add*Track methods
  • Added an output track grouping system, used to define track pairings for HLS outputs. Create OutputTrackGroups, then assign tracks to them via BaseTrackMetadata.group.
  • Added TrackDisposition.primary to indicate that a track is the primary, main track. Corresponds to HLS's DEFAULT attribute.
  • 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 via BaseTrackMetadata.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 to true iff Mediabunny can read the file.
  • Input.getFirstTimestamp() now takes an optional InputTrack[] as first argument; if provided, the first timestamp is only computed for the given tracks.
  • Input.computeDuration() now takes two optional arguments: InputTrack[] and PacketRetrievalOptions. 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 using skipLiveWait.
  • 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(), returning true for tracks that only contain key packets, such as audio tracks or #EXT-X-I-FRAME-STREAM-INF HLS tracks.
  • Added InputTrack.getBitrate() and InputTrack.getAverageBitrate() for retrieving a track's peak and average bitrate respectively, as specified in file metadata.
  • InputTrack.computeDuration() now accepts an optional PacketRetrievalOptions argument that can be used to configure behavior for live streams using skipLiveWait.
  • 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.
  • BufferTarget now takes an optional first argument BufferTargetOptions, which can be used to set the onFinalize callback which allows you to do work as soon as the buffer has been finalized.
  • Added ConversionOptions.tracks which can be 'all' or 'primary'; used to control the tracks that are considered for conversion.
  • More media sinks now accept PacketRetrievalOptions in their methods: AudioBufferSink, AudioSampleSink, CanvasSink, VideoSampleSink. Required for accessing skipLiveWait.
  • Added global decodability checker helper functions: canDecode, canDecodeAudio, canDecodeVideo, getDecodableCodecs, getDecodableAudioCodecs, getDecodableVideoCodecs,
  • Added Source/Target ranging; a new .slice() method returns a RangedSource/RangedTarget which maps to a subset of the original source/target.
  • Added a new reference counting system for sources via SourceRef. A ref can be acquired via source.ref(), and only when the last ref has been .free()d will the source be disposed.
  • Added AppendOnlyStreamTarget, which is like StreamTarget except it accepts WritableStream<Uint8Array>, meaning it models purely sequential writes.
  • Added EventEmitter, a new base class for listening to events via an .on method. Subclassed by Input, Output, Source and Target.
  • Added a source event for Input, emitted every time a new source is acquired
  • Added a target event for Output, emitted every time a new target is acquired
  • Added a finalized event to Target, 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 initInput is necessary.
  • UrlSource now supports responses with unknown length (no Content-Length or Content-Range headers present)
  • Conversion.onProgress now receives a second processedTime argument
  • Added timestampBase option for MediaStreamVideoTrackSource and MediaStreamAudioTrackSource, 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 file
  • VideoEncodingConfig.keyFrameInterval now defaults to 2 seconds (was 5 previously)
  • ConversionOptions.trim.start now defaults to the start timestamp of all non-user-discarded tracks, instead of all tracks.

Deprecations

  • InputTrack.codec. Prefer await inputTrack.getCodec() instead.
  • InputTrack.internalCodecId. Prefer await inputTrack.getInternalCodecId() instead.
  • InputTrack.languageCode. Prefer await inputTrack.getLanguageCode() instead.
  • InputTrack.name. Prefer await inputTrack.getName() instead.
  • InputTrack.timeResolution. Prefer await inputTrack.getTimeResolution() instead.
  • InputTrack.disposition. Prefer await inputTrack.getDisposition() instead.
  • InputVideoTrack.codedWidth. Prefer await inputVideoTrack.getCodedWidth() instead.
  • InputVideoTrack.codedHeight. Prefer await inputVideoTrack.getCodedHeight() instead.
  • InputVideoTrack.displayWidth. Prefer await inputVideoTrack.getDisplayWidth() instead.
  • InputVideoTrack.displayHeight. Prefer await inputVideoTrack.getDisplayHeight() instead.
  • InputVideoTrack.squarePixelWidth. Prefer await inputVideoTrack.getSquarePixelWidth() instead.
  • InputVideoTrack.squarePixelHeight. Prefer await inputVideoTrack.getSquarePixelHeight() instead.
  • InputVideoTrack.pixelAspectRatio. Prefer await inputVideoTrack.getPixelAspectRatio() instead.
  • InputVideoTrack.rotation. Prefer await inputVideoTrack.getRotation() instead.
  • InputAudioTrack.numberOfChannels. Prefer await inputAudioTrack.getNumberOfChannels() instead.
  • InputAudioTrack.sampleRate. Prefer await 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
  • UrlSource no longer always requests byte 0 to determine the file size, it can do that from any starting offset now
  • ReadableStreamSource's reader is now properly canceled on dispose
  • UrlSource.parallelism actually 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

New fields