HLS

HTTP Live Streaming (also known as HLS) is an HTTP-based media streaming communications protocol implemented by Apple Inc. as part of its QuickTime, Safari, OS X, and iOS software. It resembles MPEG-DASH in that it works by breaking the overall stream into a sequence of small HTTP-based file downloads, each download loading one short chunk of an overall potentially unbounded transport stream. As the stream is played, the client may select from a number of different alternate streams containing the same material encoded at a variety of data rates, allowing the streaming session to adapt to the available data rate. At the start of the streaming session, HLS downloads an extended M3U playlist containing the metadata for the various sub-streams which are available.

Shaka Packager supports HLS content packaging. This tutorial covers HLS packaging of VOD content without encryption. For live content packaging, see Live; for content encryption, see DRM; for full documentation, see Packager Documentation.

Synopsis

$ packager <stream_descriptor> ... \
  --hls_master_playlist_output <master_playlist_output_path> \
  [Other HLS options] \
  [Other options, e.g. DRM options, DASH options]

See HLS specific stream descriptor fields for the available HLS specific stream descriptor fields.

See HLS options for the available HLS related options.

Note

DASH and HLS options can both be specified to output DASH and HLS manifests at the same time. Note that it works only for MP4 outputs.

Examples

The examples below uses the H264 streams created in Media Encoding.

  • TS output with elementary audio:

    $ packager \
      'in=h264_baseline_360p_600.mp4,stream=audio,segment_template=audio/$Number$.aac,playlist_name=audio/main.m3u8,hls_group_id=audio,hls_name=ENGLISH' \
      'in=input_text.vtt,stream=text,segment_template=text/$Number$.vtt,playlist_name=text/main.m3u8,hls_group_id=text,hls_name=ENGLISH' \
      'in=h264_baseline_360p_600.mp4,stream=video,segment_template=h264_360p/$Number$.ts,playlist_name=h264_360p/main.m3u8,iframe_playlist_name=h264_360p/iframe.m3u8' \
      'in=h264_main_480p_1000.mp4,stream=video,segment_template=h264_480p/$Number$.ts,playlist_name=h264_480p/main.m3u8,iframe_playlist_name=h264_480p/iframe.m3u8' \
      'in=h264_main_720p_3000.mp4,stream=video,segment_template=h264_720p/$Number$.ts,playlist_name=h264_720p/main.m3u8,iframe_playlist_name=h264_720p/iframe.m3u8' \
      'in=h264_high_1080p_6000.mp4,stream=video,segment_template=h264_1080p/$Number$.ts,playlist_name=h264_1080p/main.m3u8,iframe_playlist_name=h264_1080p/iframe.m3u8' \
      --hls_master_playlist_output h264_master.m3u8
    

The above packaging command creates five single track TS streams (4 video, 1 audio) and HLS playlists, which describe the streams.

  • MP4 output is also supported:

    $ packager \
      'in=h264_baseline_360p_600.mp4,stream=audio,init_segment=audio/init.mp4,segment_template=audio/$Number$.m4s,playlist_name=audio/main.m3u8,hls_group_id=audio,hls_name=ENGLISH' \
      'in=input_text.vtt,stream=text,segment_template=text/$Number$.vtt,playlist_name=text/main.m3u8,hls_group_id=text,hls_name=ENGLISH' \
      'in=h264_baseline_360p_600.mp4,stream=video,init_segment=h264_360p/init.mp4,segment_template=h264_360p/$Number$.m4s,playlist_name=h264_360p/main.m3u8,iframe_playlist_name=h264_360p/iframe.m3u8' \
      'in=h264_main_480p_1000.mp4,stream=video,init_segment=h264_480p/init.mp4,segment_template=h264_480p/$Number$.m4s,playlist_name=h264_480p/main.m3u8,iframe_playlist_name=h264_480p/iframe.m3u8' \
      'in=h264_main_720p_3000.mp4,stream=video,init_segment=h264_720p/init.mp4,segment_template=h264_720p/$Number$.m4s,playlist_name=h264_720p/main.m3u8,iframe_playlist_name=h264_720p/iframe.m3u8' \
      'in=h264_high_1080p_6000.mp4,stream=video,init_segment=h264_1080p/init.mp4,segment_template=h264_1080p/$Number$.m4s,playlist_name=h264_1080p/main.m3u8,iframe_playlist_name=h264_1080p/iframe.m3u8' \
      --hls_master_playlist_output h264_master.m3u8
    

The above packaging command creates five groups of streams (each with an init segment and a series of media segments) and HLS playlists, which describe the streams.

  • Single file MP4 output is also supported:

    $ packager \
      in=h264_baseline_360p_600.mp4,stream=audio,output=audio.mp4,playlist_name=audio.m3u8,hls_group_id=audio,hls_name=ENGLISH \
      in=h264_baseline_360p_600.mp4,stream=video,output=h264_360p.mp4,playlist_name=h264_360p.m3u8 \
      in=h264_main_480p_1000.mp4,stream=video,output=h264_480p.mp4,playlist_name=h264_480p.m3u8 \
      in=h264_main_720p_3000.mp4,stream=video,output=h264_720p.mp4,playlist_name=h264_720p.m3u8 \
      in=h264_high_1080p_6000.mp4,stream=video,output=h264_1080p.mp4,playlist_name=h264_1080p.m3u8 \
      --hls_master_playlist_output h264_master.m3u8
    

The above packaging command creates five single file MP4 streams and HLS playlists, which describe the streams.

  • Single file MP4 output with DASH + HLS:

    $ packager \
      in=h264_baseline_360p_600.mp4,stream=audio,output=audio.mp4,playlist_name=audio.m3u8,hls_group_id=audio,hls_name=ENGLISH \
      in=h264_baseline_360p_600.mp4,stream=video,output=h264_360p.mp4,playlist_name=h264_360p.m3u8,iframe_playlist_name=h264_360p_iframe.m3u8 \
      in=h264_main_480p_1000.mp4,stream=video,output=h264_480p.mp4,playlist_name=h264_480p.m3u8,iframe_playlist_name=h264_480p_iframe.m3u8 \
      in=h264_main_720p_3000.mp4,stream=video,output=h264_720p.mp4,playlist_name=h264_720p.m3u8,iframe_playlist_name=h264_720p_iframe.m3u8 \
      in=h264_high_1080p_6000.mp4,stream=video,output=h264_1080p.mp4,playlist_name=h264_1080p.m3u8,iframe_playlist_name=h264_1080p_iframe.m3u8 \
      --hls_master_playlist_output h264_master.m3u8 \
      --mpd_output h264.mpd
    

The above packaging command creates five single file MP4 streams, and HLS playlists as well as DASH manifests.

  • Output DASH + HLS with dash_only and hls_only options:

    $ packager \
      'in=h264_baseline_360p_600.mp4,stream=audio,init_segment=audio/init.mp4,segment_template=audio/$Number$.m4s' \
      'in=input_text.vtt,stream=text,init_segment=text/init.mp4,segment_template=text/$Number$.m4s,dash_only=1' \
      'in=input_text.vtt,stream=text,segment_template=text/$Number$.vtt,hls_only=1' \
      'in=h264_baseline_360p_600.mp4,stream=video,init_segment=h264_360p/init.mp4,segment_template=h264_360p/$Number$.m4s' \
      'in=h264_main_480p_1000.mp4,stream=video,init_segment=h264_480p/init.mp4,segment_template=h264_480p/$Number$.m4s' \
      'in=h264_main_720p_3000.mp4,stream=video,init_segment=h264_720p/init.mp4,segment_template=h264_720p/$Number$.m4s' \
      'in=h264_high_1080p_6000.mp4,stream=video,init_segment=h264_1080p/init.mp4,segment_template=h264_1080p/$Number$.m4s' \
      --generate_static_live_mpd --mpd_output h264.mpd \
      --hls_master_playlist_output h264_master.m3u8
    

The above packaging command creates HLS playlists and DASH manifest while using dash_only for creating segmented WebVTT in mp4 format and hls_only option for creating WebVTT in text format.

Configuration options

HLS specific stream descriptor fields

hls_name:

Used for HLS audio to set the NAME attribute for EXT-X-MEDIA. Defaults to the base of the playlist name.

hls_group_id:

Used for HLS audio to set the GROUP-ID attribute for EXT-X-MEDIA. Defaults to ‘audio’ if not specified.

playlist_name:

The HLS playlist file to create. Usually ends with ‘.m3u8’, and is relative to hls_master_playlist_output (see below). If unspecified, defaults to something of the form ‘stream_0.m3u8’, ‘stream_1.m3u8’, ‘stream_2.m3u8’, etc.

iframe_playlist_name:

The optional HLS I-Frames only playlist file to create. Usually ends with ‘.m3u8’, and is relative to hls_master_playlist_output (see below). Should only be set for video streams. If unspecified, no I-Frames only playlist is created.

hls_characteristics (charcs):

Optional colon or semi-colon separated list of values for the CHARACTERISTICS attribute for EXT-X-MEDIA. See CHARACTERISTICS attribute in http://bit.ly/2OOUkdB for details.

HLS options

--hls_master_playlist_output <file_path>

Output path for the master playlist for HLS. This flag must be used to output HLS.

--hls_base_url <url>

The base URL for the Media Playlists and media files listed in the playlists. This is the prefix for the files.

--hls_key_uri <uri>

The key uri for ‘identity’ and ‘com.apple.streamingkeydelivery’ (FairPlay) key formats. Ignored if the playlist is not encrypted or not using the above key formats.

--hls_playlist_type <type>

VOD, EVENT, or LIVE. This defines the EXT-X-PLAYLIST-TYPE in the HLS specification. For hls_playlist_type of LIVE, EXT-X-PLAYLIST-TYPE tag is omitted.

--time_shift_buffer_depth <seconds>

Guaranteed duration of the time shifting buffer for LIVE playlists, in seconds.

--preserved_segments_outside_live_window <num_segments>

Segments outside the live window (defined by time_shift_buffer_depth above) are automatically removed except for the most recent X segments defined by this parameter. This is needed to accommodate latencies in various stages of content serving pipeline, so that the segments stay accessible as they may still be accessed by the player.

The segments are not removed if the value is zero.

--default_language <language>

The first audio/text rendition in a group tagged with this language will have ‘DEFAULT’ attribute set to ‘YES’. This allows the player to choose the correct default language for the content.

This applies to both audio and text tracks. The default language for text tracks can be overriden by ‘default_text_language’.

--default_text_language <text_language>

Same as above, but this applies to text tracks only, and overrides the default language for text tracks.

--hls_media_sequence_number <unsigned_number>

HLS uses the EXT-X-MEDIA-SEQUENCE tag at the start of a live playlist in order to specify the first segment sequence number. This is because any live playlist have a limited number of segments, and they also keep updating with new segments while removing old ones. When a player refreshes the playlist, this information is important for keeping track of segments positions.

When the packager starts, it naturally starts this count from zero. However, there are many situations where the packager may be restarted, without this meaning starting this value from zero (but continuing a previous sequence). The most common situations are problems in the encoder feeding the packager.

With those cases in mind, this parameter allows to set the initial EXT-X-MEDIA-SEQUENCE value. This way, it’s possible to continue the sequence number from previous packager run.

For more information about the reasoning of this, please see issue #691.

The EXT-X-MEDIA-SEQUENCE documentation can be read here: https://tools.ietf.org/html/rfc8216#section-4.3.3.2.

--hls_start_time_offset <seconds>

Sets EXT-X-START on the media playlists to specify the preferred point at wich the player should start playing. A positive number indicates a time offset from the beginning of the playlist. A negative number indicates a negative time offset from the end of the last media segment in the playlist.

–hls_only=0|1

Optional. Defaults to 0 if not specified. If it is set to 1, indicates the stream is HLS only.

--force_cl_index

True forces the muxer to order streams in the order given on the command-line. False uses the previous unordered behavior.

Segment template formatting

The implementation is based on Template-based Segment URL construction described in ISO/IEC 23009-1:2014.

Supported identifiers

$<Identifier>$

Substitution parameter

Format

$$

is an escape sequence, i.e. “$$” is replaced with a single “$”.

Not applicable.

$Number$

This identifier is substitued with the number of the corresponding Segment.

The format tag may be present.

If no format tag is present, a default format tag with width=1 shall be used.

$Time$

This identifier is substituted with the value of the SegmentTimeline@t attribute for the Segment being accessed. Either $Number$ or $Time$ may be used but not both at the same time.

The format tag may be present.

If no format tag is present, a default format tag with width=1 shall be used.

Note

Identifiers $RepresentationID$ and $Bandwidth$ are not supported in this version. Please file an issue if you want it to be supported.

In each URL, the identifiers shall be replaced by the substitution parameter per the definition in the above table. Identifier matching is case-sensitive.

Each identifier may be suffixed, within the enclosing ‘$’ characters, with an additional format tag aligned with the printf format tag as defined in IEEE 1003.1-2008 following this prototype:

%0[width]d

The width parameter is an unsigned integer that provides the minimum number of characters to be printed. If the value to be printed is shorter than this number, the result shall be padded with zeros. The value is not truncated even if the result is larger.

Strings outside identifiers shall only contain characters that are permitted within URLs according to RFC 3986.