Bin responsible for receiving audio/video/text tracks, packaging them into CMAF/TS/AAC, and writing playlists/segments via the provided storage.
Timing contract
- Upstream must provide monotonic, accurate PTS/DTS per track.
- Tracks that produce segments at a given sync point must be aligned in time (minor AAC/H264 cut differences are tolerated within packager tolerance).
- By default, the sink does not shift or trim timestamps.
- Optional startup alignment trimming can be enabled with
:trim_align?. This alignment is performed once at startup (not continuously). When H264 is present, alignment is anchored to H264 keyframes and advances to the next keyframe until all non-H264 tracks started at or before the selected cut point.
Operational modes
:vodsyncs whenever the next segment group is ready and is strict about timing.{:event, safety_delay}syncs on a target-duration cadence.{:sliding, max_segments, safety_delay}syncs on cadence and keeps a rolling window.
Policy and error handling
- All outputs are RFC-compliant.
:vodis strict: any packager error fails fast.:event/:slidingare tolerant to recoverable timing issues by inserting discontinuities, but fail fast on missing mandatory track segments to avoid silent stalls.
Bin options
Passed via struct Membrane.HLS.SinkBin.t/0
storageHLS.Storage.t()Required
Storage implementation used to write segments and playlists.manifest_uriURI.t()Required
URI of the master playlist written by the packager.target_segment_durationMembrane.Time.t()Required
Target duration for each HLS segment.playlist_mode:vod | {:event, Membrane.Time.t()} | {:sliding, pos_integer(), Membrane.Time.t()}Default value:
:vod:vod- Segments are synced as soon as the next segment group is ready.{:event, safety_delay}- Live event playlist, synced each target segment duration.{:sliding, max_segments, safety_delay}- Live playlist with rolling window.
resume?boolean()Default value:
false
When true, attempt to resume from an existing master and media playlists in storage.resume_on_error:start_new | :raiseDefault value:
:start_new
Policy for broken or missing initial playlists when resuming.resume_as_liveboolean()Default value:
false
When true, all media playlists loaded during resume have theirfinishedflag reset tofalseand theirtypecleared before being handed to the packager. This allows resuming against a previously-finalized VOD playlist as if it were still a live event, preventing the packager from staying in VOD mode and silently dropping new segments.Only meaningful when
resume?is also true.flush_on_endboolean()Default value:
true
Automatically flush the packager when all streams ended. Set tofalseif flushing manually (via:flushnotification).trim_align?boolean()Default value:
false
When enabled, trims leading content once on startup before segmentation.If at least one H264 track is present, the cut point is selected on H264 keyframes. The aligner picks the earliest keyframe for which all non-H264 tracks have already started (
first_ts <= cut_point). If needed, it waits for later keyframes.Without H264 tracks, the cut point is the latest first cuttable timestamp across inputs.
For H264 tracks this requires parsed AU-aligned input with keyframe metadata (typically from
Membrane.H264.Parser).trim_align_max_leading_trimMembrane.Time.t()Default value:
3000000000
Maximum amount of leading media that can be removed from a single track while aligning.trim_align_max_queued_bufferspos_integer()Default value:
2000
Maximum number of buffers queued per track while waiting for startup alignment. This guard is especially relevant when late non-H264 tracks force waiting for a later H264 keyframe cut point.
Pads
:input
Accepted formats:
Membrane.H264Membrane.AACMembrane.TextMembrane.RemoteStream| Direction: | :input |
| Availability: | :on_request |
Pad options:
container:CMAF | :TS | :PACKED_AACDefault value:
:CMAF
How A/V tracks are packaged.encoding:AAC | :H264 | :TEXTRequired
Encoding type determining which parser will be used for the given stream.omit_subtitle_repetitionboolean()Default value:
false
When writing subtitle playlists, subtitles that span over multiple segments are repeated in both segments. When this flag is turned on, subtitles appear only in the segment in which they start.subtitle_min_durationMembrane.Time.t()Default value:
1500000000
Forces subtitles to last at list the specified amount of time. If omitted, subtitles will last the duration of their content.relative_mpeg_ts_timestampsboolean()Default value:
false
If true, each subtitle segment will have a X-TIMESTAMP-MAP header and its contents will be relative to that timing.build_stream(track() -> HLS.VariantStream.t() | HLS.AlternativeRendition.t())Required
Build either aHLS.VariantStreamor aHLS.AlternativeRendition.VariantStream.bandwidthandVariantStream.codecsare deprecated and are now computed automatically when possible.segment_durationMembrane.Time.t()Required
Duration for a HLS segment.
Summary
Types
@type input_pad_opts() :: [ container: :CMAF | :TS | :PACKED_AAC, encoding: :AAC | :H264 | :TEXT, omit_subtitle_repetition: boolean(), subtitle_min_duration: Membrane.Time.t(), relative_mpeg_ts_timestamps: boolean(), build_stream: (track() -> HLS.VariantStream.t() | HLS.AlternativeRendition.t()), segment_duration: Membrane.Time.t() ]
Options for pad :input
@type t() :: %Membrane.HLS.SinkBin{ flush_on_end: boolean(), manifest_uri: URI.t(), playlist_mode: :vod | {:event, Membrane.Time.t()} | {:sliding, pos_integer(), Membrane.Time.t()}, resume?: boolean(), resume_as_live: boolean(), resume_on_error: :start_new | :raise, storage: HLS.Storage.t(), target_segment_duration: Membrane.Time.t(), trim_align?: boolean(), trim_align_max_leading_trim: Membrane.Time.t(), trim_align_max_queued_buffers: pos_integer() }
Struct containing options for Membrane.HLS.SinkBin
@type track() :: Membrane.CMAF.Track.t() | map()
Functions
@spec options() :: keyword()
Returns description of options available for this module