Packaging for HTTP Live Streaming (HLS)

mp4split generates all files required for HLS streaming using MP4 audio/video files as input. To enable the HLS packaging mode, the first option on the command-line must be --package-hls.

The following is a list of all options specific for HLS packaging.

Options for HLS packaging

--package_hls

Enable the HLS packaging mode.

--fragment_duration

The duration of each fragment (in milliseconds).

--output_single_file

Output the fragments as a single file, instead of a separate file for each fragment.

--base_media_file

The base name of the media file (defaults to fileSequence).

--encrypt_key_file

The file that holds the key information.

--encrypt_key_url

The license acquisition URL.

--encrypt_iv

The 128 bit AES Initialization Vector (IV). This is a random 128 bit value. The default is to use the sequence number.

--stream_encrypt

Use SAMPLE-AES for encryption instead of AES-128.

--streaming_key_delivery

Use com.apple.streamingkeydelivery as KEYFORMAT.

--start_segments_with_iframe

Align each fragment so that it starts with an IDR frame.

--iframe_index_file

The name of the iframe index file (defaults to iframe_index.m3u8).

Protocol version

The protocol version depends on the features you are requesting, so you don't have to set this explicitly. E.g. enabling output-single-file requires a minimum protocol version of 4 because EXT-X-BYTERANGE tags are used.

Newer versions of the protocol supports dynamic binding of audio, video and subtitles. Older versions require multiplexed audio/video. Let's start by creating content that is using multiplexed audio/video and gives the highest degree of compatibility with devices/players.

Using multiplexed audio/video (protocol version 3)

The following example uses two input files, two mp4's that contain both audio and video with two different bitrates for the video.

Input files for multiplexed audio/video

Filename Description
presentation-1.mp4 AVC 416x234 @ 800kbps, AAC LC @ 128kbps
presentation-2.mp4 AVC 640x360 @ 1200kbps, AAC LC @ 128 kbps

The corresponding command lines are:

#!/bin/bash

mp4split \
  --package_hls \
  -o presentation_s1/prog_index.m3u8 \
  --fragment_duration=9000 \
  --base_media_file=s1_ \
  presentation-1.mp4

and

#!/bin/bash

mp4split --package_hls -o presentation_s2/prog_index.m3u8 \
  --fragment_duration=9000 \
  --base_media_file=s2_ \
  presentation-2.mp4

The above two command lines will generate a directory each that contains the .m3u8 and .ts files created from the mp4's.

Output files for multiplexed audio/video

Filename Description
presentation_s1/prog_index.m3u8 The playlist for the 1st stream.
presentation_s1/s1_NNN.ts A number of MPEG TS segments for the 1st stream.
presentation_s2/prog_index.m3u8 The playlist for the 2nd stream.
presentation_s2/s2_NNN.ts A number of MPEG TS segments for the 2nd stream.

Creating a variant playlist is simple, just pass all the prog_index.m3u8 as inputs to the packager:

#!/bin/bash

mp4split --package_hls -o presentation.m3u8 \
  presentation_s1/prog_index.m3u8 \
  presentation_s2/prog_index.m3u8

Using multiplexed audio/video with AES-128 (protocol version 3)

Now let us add AES-128 encryption to the previous example. First we have to create a 128-bit CEK (Content Encryption Key). This is just a 16 bytes file with random bytes. You could use for example 'openssl' to create the key:

#!/bin/bash

openssl rand 16 > presentation.key

The command-lines for segmenting the mp4 files is the same as above, except that we need to add two additional options.

We have to pass the presentation.key as the --encrypt-key-file option.

Since the player needs to know where to fetch the encryption key we pass the same presentation.key also to the --encrypt-key-url option.

It's also possible to specify a full HTTP(s) URL or your own URL format.

The corresponding command lines are:

#!/bin/bash

mp4split --package_hls -o presentation_s1/prog_index.m3u8 \
  --fragment_duration=9000 \
  --base_media_file=s1_ \
  --encrypt_key_file=presentation.key \
  --encrypt_key_url=../presentation.key \
  presentation-1.mp4

and

#!/bin/bash

mp4split --package_hls -o presentation_s2/prog_index.m3u8 \
  --fragment_duration=9000 \
  --base_media_file=s2_ \
  --encrypt_key_file=presentation.key \
  --encrypt_key_url=../presentation.key \
  presentation-2.mp4

The creation of the variant playlist is the same as above:

#!/bin/bash

mp4split --package_hls -o presentation.m3u8 \
  presentation_s1/prog_index.m3u8 \
  presentation_s2/prog_index.m3u8

You will now have the following files and directories for this presentation:

Output files for multiplexed audio/video

Filename Description
presentation.m3u8 The variant/master playlist.
presentation.key The 16 bytes Content Encryption Key.
presentation_s1/prog_index.m3u8 The playlist for the 1st stream.
presentation_s1/s1_NNN.ts A number of MPEG TS segments for the 1st stream.
presentation_s2/prog_index.m3u8 The playlist for the 2nd stream.
presentation_s2/s2_NNN.ts A number of MPEG TS segments for the 2nd stream.

Download

Please download the package-hls-aes-v3.sh sample script which creates the various server manifest as discussed above. The sample content is Tears of Steel.

Using late binding of audio/video groups (protocol version 4)

If you have more than one audio track (e.g. different codecs, different languages) and/or subtitles then you want to use the grouping that the HLS protocol supports. In this case all the audio/video/subtitles have to be segmented separately.

Input files for grouped audio/video

Filename Description
presentation-1.mp4 AVC 416x234 @ 600kbps, AAC-SBR @ 64kbps
presentation-2.mp4 AVC 416x234 @ 800kbps, AAC-LC @ 128 kbps
presentation-3.mp4 AVC 640x360 @ 1200 kbps, AC3 @ 128 kbps
image.png PNG image to embed in AAC-SBR stream

The mp4split commands are:

#!/bin/bash

mp4split --package_hls -o presentation_v1/prog_index.m3u8 \
  --fragment_duration=9000 \
  --base_media_file=v1_ \
  presentation-1.mp4 \
    --track_type=video

mp4split --package_hls -o presentation_v2/prog_index.m3u8 \
  --fragment_duration=9000 \
  --base_media_file=v2_ \
  presentation-2.mp4 \
    --track_type=video

mp4split --package_hls -o presentation_v3/prog_index.m3u8 \
  --fragment_duration=9000 \
  --base_media_file=v3_ \
  presentation-3.mp4 \
    --track_type=video

mp4split --package_hls -o presentation_a1/prog_index.m3u8 \
  --fragment_duration=9000 \
  --base_media_file=a1_ \
  presentation-1.mp4 \
    --track_type=audio image.png

mp4split --package_hls -o presentation_a2/prog_index.m3u8 \
  --fragment_duration=9000 \
  --base_media_file=a2_ \
  presentation-2.mp4 \
    --track_type=audio

mp4split --package_hls -o presentation_a3/prog_index.m3u8 \
  --fragment_duration=9000 \
  --base_media_file=a3_ \
  presentation-3.mp4 \
    --track_type=audio

The following output is created:

Output files for multiplexed audio/video

Filename Description
presentation_v1/prog_index.m3u8 The playlist for the 1st video stream.
presentation_v1/iframe_index.m3u8 The IFRAME only playlist for the 1st video stream.
presentation_v1/v1_NNN.ts A number of MPEG TS segments for the 1st video stream.
presentation_v2/prog_index.m3u8 The playlist for the 2nd video stream.
presentation_v2/iframe_index.m3u8 The IFRAME only playlist for the 2nd video stream.
presentation_v2/v2_NNN.ts A number of MPEG TS segments for the 2nd video stream.
presentation_v3/prog_index.m3u8 The playlist for the 3rd video stream.
presentation_v3/iframe_index.m3u8 The IFRAME only playlist for the 3rd video stream.
presentation_v3/v3_NNN.ts A number of MPEG TS segments for the 3rd video stream.
presentation_a1/prog_index.m3u8 The playlist for the 1st audio stream.
presentation_a1/a1_NNN.aac A number of AAC segments for the 1st audio stream (including an embedded PNG image).
presentation_a2/prog_index.m3u8 The playlist for the 2nd audio stream.
presentation_a2/a2_NNN.aac A number of AAC segments for the 2nd audio stream.
presentation_a3/prog_index.m3u8 The playlist for the 3rd audio stream.
presentation_a3/a3_NNN.ac3 A number of AC3 segments for the 3rd audio stream.

Since we use a higher protocol version we can also add the iframe_index.m3u8 files to the variant playlist.

#!/bin/bash

mp4split --package_hls -o presentation.m3u8 \
  presentation_v1/prog_index.m3u8 \
  presentation_v1/iframe_index.m3u8 \
  presentation_v2/prog_index.m3u8 \
  presentation_v2/iframe_index.m3u8 \
  presentation_v3/prog_index.m3u8 \
  presentation_v3/iframe_index.m3u8 \
  presentation_a1/prog_index.m3u8 \
  presentation_a2/prog_index.m3u8 \
  presentation_a3/prog_index.m3u8

If you also want to add an audio-only variant to the variant playlist, you can simply list the audio playlist twice on the command line. For each duplicate entry an audio only variant is added.

Download

Please download the package-hls-aes-v4.sh sample script which creates the various server manifest as discussed above. The sample content is Tears of Steel.

Signaling embedded 608/708 Closed Captions (protocol version 4)

When the video track contains embedded closed captions they need to be signaled separately. The default is to signal that the video tracks do not contain any closed captions, so if they do contain captions you have to create a Closed Captions playlist and explicitly add it to the variant playlist.

The input file is the video presentation that contains the embedded Closed Captions. This time we specifically select the text track and at the same time assign it a description.

The mp4split command is:

#!/bin/bash

mp4split --package_hls -o presentation_c1/prog_index.m3u8 \
  presentation-1.mp4 \
    --track_type=text \
    --track_description="Closed Captions"

This creates a 'presentation_c1/prog_index.m3u8' file which can then be added to the variant playlist (identical to the previous example).

Note that embedded captions are not extracted, just signaled.

Using late binding of audio/video groups with SAMPLE-AES (protocol version 5)

Now let us add SAMPLE-AES encryption to the previous example. First we have to create a 128-bit CEK (Content Encryption Key). This is just a 16 bytes file with random bytes. You could use for example 'openssl' to create the key:

#!/bin/bash

openssl rand 16 > presentation.key

The command-lines for segmenting the mp4 files is the same as above, except that we need to add four additional options.

We have to pass the presentation.key as the --encrypt-key-file option.

Since the player needs to know where to fetch the encryption key we pass the same presentation.key also to the --encrypt-key-url option.

It's also possible to specify a full HTTP(s) URL or your own URL format.

We also specify --stream-encrypt to enable SAMPLE-AES encryption

The mp4split command is:

#!/bin/bash

mp4split --package_hls -o presentation_v1/prog_index.m3u8 \
  --fragment_duration=9000 \
  --encrypt_key_file=presentation.key \
  --encrypt_key_url=../presentation.key \
  --stream_encrypt \
  --base_media_file=v1_ \
  presentation-1.mp4 \
    --track_type=video

Repeat this for presentation_v2, presentation_v3, presentation_a1, presentation_a2, presentation_a3.

Creating the variant playlist is identical to the previous example.

Using late binding of audio/video groups with SAMPLE-AES for Apple FairPlay

For FairPlay we first have to create a 128-bit CEK (Content Encryption Key) and 128-bit IV (Initialization Vector). This is just a 32 bytes file with random bytes. You could use for example 'openssl' to create the key.

#!/bin/bash

openssl rand 32 > presentation.key

The command-lines for segmenting the mp4 files is the same as above and we also specify --stream-encrypt to enable SAMPLE-AES encryption and --streaming-key-delivery for FairPlay.

The mp4split command is:

#!/bin/bash

mp4split --package_hls -o presentation_v1/prog_index.m3u8 \
  --fragment_duration=9000 \
  --encrypt_key_file=presentation.key \
  --encrypt_key_url=../presentation.key \
  --stream_encrypt \
  --streaming_key_delivery \
  --base_media_file=v1_ \
  presentation-1.mp4 --track_type=video

Repeat this for presentation_v2, presentation_v3, presentation_a1, presentation_a2, presentation_a3.

Creating the variant playlist is identical to the previous example.

Please note that within FairPlay the encrypt-key-url is only for information, a client typically implements different means of locating the license server and fetch keys.

Audio only Sample AES

Using the packager it is possible to create a Sample AES protected audio only stream that includes a 'still image' (a jpg or png shown with the audio stream).

The image is embedded (with an ID3 APIC tag) in the AAC audio.

The example command is the following:

#!/bin/bash

mp4split --package_hls -o prog_index.m3u8 \
  --fragment_duration=9000 \
  --encrypt_key_file=video.key \
  --stream_encrypt \
  --encrypt_key_url=video.key \
  --output_single_file \
  oceans-64k.mp4 \
  hls.jpg

This creates a .m3u8 that looks like the following:

#EXTM3U
#EXT-X-VERSION:5
## Created with Unified Streaming Platform(version=1.6.8)
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-TARGETDURATION:10
#EXT-X-KEY:METHOD=SAMPLE-AES,URI="video.key"
#EXTINF:9.002, no desc
#EXT-X-BYTERANGE:40775@0
fileSequence.aac

...

#EXTINF:1.088, no desc
#EXT-X-BYTERANGE:15902@1095409
fileSequence.aac
#EXT-X-ENDLIST
#USP-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio-aacl-65",LANGUAGE="en",NAME="English",AUTOSELECT=YES,BANDWIDTH=117000,CODECS="mp4a.40.2"

Note

The filename 'fileSequence.aac' is the default filename, which can be change by the use of '--base-media-file'.

Safari (or Quicktime or Apple TV) has no support for the ID3 tag used, so it does play (the sound) but no image is shown.

Dolby Digital Plus, also known as Enhanced AC-3 or EC-3 audio streams are supported as well. See here for further reference HLS Sample-AES Audio Formats.

Enabling WebVTT when packaging HLS

It is also possible to package an HLS presentation and add WebVTT to it. Precondition is that the subtitles are in TTML format. To generate these from WebVTT input, see Packaging Subtitles.

The first step is to generate a .ismt file as part of the package:

#!/bin/bash

mp4split -o example_c1/video.ismt \
  example.ttml

mp4split --package_hls -o example_c1/prog_index.m3u8 \
  example_c1/video.ismt \
  --track_description="Closed Captions"

This can then be added to the .m3u8 similar to the other elements of the presentation:

#!/bin/bash

mp4split --package_hls -o example.m3u8 \
  example_c1/prog_index.m3u8 \
  example_v1/prog_index.m3u8 \
  example_v1/iframe_index.m3u8

  ... (other elements of the presentation)

Note

To enable WebVTT output for HLS you have to use at least version 4 of the HLS protocol. See --hls.client_manifest_version.

Overriding default playlist values

mp4split uses some default rules when generating the NAME and GROUP-ID fields.

If you are not happy with the defaults, you can specify the following options on the command line after each input file.

mp4split options for overriding default values

Option Description
track_groupid Specify the value used for the GROUP-ID field in the EXT-X-MEDIA tag.
track_description Specify the value used for the NAME field in the EXT-X-MEDIA tag.

Advanced recipes

Using Playready Envelope encryption for HLS

New in version 1.7.14.

You can encrypt the media segments using Playready Envelope encryption.

This encryption mode is set by specifying the option --hls.playout=playready_envelope. The PlayReady key information option (--iss.key and --iss.license_server_url) are described at PlayReady Envelope.

Example

#!/bin/bash

KID=the-key-id
CEK=the-content-key
LA_URL=the-license-server-url

# first the media and the media playlist
mp4split --package_hls \
  -o presentation_s1/prog_index.m3u8 \
  --fragment-duration=9000 \
  --output-single-file \
  --hls.playout=playready_envelope \
  --iss.license_server_url=${LA_URL} \
  --iss.key=${KID}:${CEK} \
  sample.mp4

# then the master playlist
mp4split --package_hls \
  -o presentation.m3u8 \
  --fragment_duration=9000 \
  --output_single_file \
  presentation_s1/prog_index.m3u8

Using Discretix PlayReady encryption for HLS

New in version 1.7.19.

You can encrypt the media segments using Discretix Playready encryption.

This encryption mode is set by specifying the option --hls.playout=dxdrm. The Playready key information option (--dxdrm.key and --dxdrm.license_server_url) are described at Viaccess-Orca (Discretix) PlayReady.

Example

#!/bin/bash

KID=the-key-id
CEK=the-content-key
LA_URL=the-license-server-url

# first the media and the media playlist
mp4split --package_hls \
  -o presentation_s1/prog_index.m3u8 \
  --fragment_duration=9000 \
  --output_single_file \
  --hls.playout=dxdrm \
  --dxdrm.license_server_url=${LA_URL} \
  --dxdrm.key=${KID}:${CEK} \
  sample.mp4

# then the master playlist
mp4split --package_hls \
  -o presentation.m3u8 \
  --fragment_duration=9000 \
  --output_single_file \
  presentation_s1/prog_index.m3u8

Adobe Primetime DRM

HLS can also be packaged with Adobe Primetime DRM SAMPLE-AES.

By adding --hds.drm_specific_data the Adobe Primetime DRM signalling and DRM data will be present in the media playlist .m3u8.

Example

KEYFILE=/path/to/sample-aes.key
IV=00000000000000000000000000000001
URL=url://to/key/acquisition
DRM_SPECIFIC_DATA="TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHbnNlY3Rl..."

# first the media and the media playlist
mp4split --package_hls \
  -o presentation_s1/prog_index.m3u8 \
  --fragment_duration=9000 \
  --encrypt_key_file ${KEYFILE} \
  --encrypt_key_url ${URL} \
  --stream_encrypt \
  --encrypt_iv=$(IV) \
  --hds.drm_specific_data=${DRM_SPECIFIC_DATA} \
  sample.mp4

# then the master playlist
mp4split --package_hls \
  -o presentation.m3u8 \
  --fragment-duration=9000 \
  presentation_s1/prog_index.m3u8

Irdeto Secure Key Exchange (SKE)

New in version 1.7.23.

The packager can be used to create HLS presentation protected with Irdeto SKE as well.

The following outlines the command line to be used.

Please refer to the Irdeto SKE for HLS section on how to get the key id (KID), content key (CEK) and license acquisition URL (LA_URL).

#!/bin/bash

KID=the-key-id
CEK=the-content-key
LA_URL=the-license-server-url

mp4split --package-hls \
  -o sample-1336k.m3u8 \
  --output-single-file \
  --irdeto.key=${KID}:${CEK} \
  --irdeto.license_server_url=${LA_URL} \
  --base-media-file=v1 \
  sample-1336k.ismv

mp4split --package-hls \
  -o sample-64k.m3u8 \
  --output-single-file \
  --irdeto.key=${KID}:${CEK} \
  --irdeto.license_server_url=${LA_URL} \
  --base-media-file=a1 \
  sample-64k.isma

mp4split --package-hls \
  -o oceans.m3u8 \
  --output-single-file \
  --irdeto.key=${KID}:${CEK} \
  --irdeto.license_server_url=${LA_URL} \
  sample-1336k.m3u8 \
  sample-64k.m3u8