Packaging HTTP Live Streaming with fragmented MP4 (fMP4 HLS)

Note

This part of our documentation is specifically intended for packaging to deliver fMP4 over HLS, or, in short: fMP4 HLS. This is a new feature and other parts of our documentation that refer to HLS without explicitly mentioning compatibility with fMP4 HLS may not necessarily apply to it, as these parts were written when Transport Streams (TS) were the only output format supported for delivery of HLS.

New in version 1.8.3.

Packaging for delivery of fMP4 HLS does not differ much from packaging HLS using Transport Streams. The most significant differences are the following:

  • You package your content into a CMAF compatible container, instead of Transport Streams. See: How to package CMAF

  • You never use the --package_hls option (not for creating the Media Playlists, I-frame Playlists or Master Playlist)

  • A Media Playlist for fMP4 HLS uses byte ranges to index the CMAF packaged content. Therefore, no individual segments are generated

  • You add a different kind of encryption to your content and use different options to do so

Superficially, the resulting playlists look very similar. Do note though that regarding encryption, the exact meaning of SAMPLE-AES is different for fMP4 HLS than it is for HLS with Transport Streams.

The benefits of streaming fMP4 HLS

The first major benefit of fMP4 HLS is that it uses the same file container format as MPEG-DASH. You can read more about this convergence in our blog post about The promises of CMAF and its compatibility with the Unified Streaming Platform.

In addition, Apple added support for HEVC and HDR (Dolby Vision and HDR10) to the HLS specification, but restricted these features to fMP4 HLS only. Using Unified Packager, no additional configuration is needed when packaging HEVC and/or HDR for fMP4 HLS.

Overview of steps involved in packaging fMP4 HLS

Below you can find the necessary steps for packaging audio and video content. Overall, they are the following:

  • Make sure your content is packaged in a CMAF compatible container with the desired fragment duration (e.g., 8 seconds).

  • Create Media Playlists based on your CMAF packaged content

  • Create I-frame Playlists for your video content

  • Create a Master Playlist based on all the individual playlists that you created

Adding encryption is done at the first step (when packaging your content as CMAF) and adding the necessary signaling for the encryption is done at the second step (when creating the Media Playlists).

Creating HLS playlists with CMAF packaged content

As mentioned above, the notable difference when creating the necessary playlists for streaming HLS from statically packaged content is that the --package_hls should not be used.

Use tos-fmp4-hls-static.sh to package the Tears of Steel demo contents as CMAF and subsequently generate the necessary HLS playlists to set up a statically packaged fMP4 HLS stream.

Create Media Playlists

#!/bin/bash

mp4split -o tos-64k-fmp4.m3u8 \
  tos-8s-aac-64k.cmfa
mp4split -o tos-128k-fmp4.m3u8 \
  tos-8s-aac-128k.cmfa
mp4split -o tos-400k-fmp4.m3u8 \
  tos-8s-avc1-400k.cmfv
mp4split -o tos-750k-fmp4.m3u8 \
  tos-8s-avc1-750k.cmfv
mp4split -o tos-1000k-fmp4.m3u8 \
  tos-8s-avc1-1000k.cmfv

Note

It's also possible to create a HLS Media Playlist for subtitles that are stored in a fMP4 container (i.e., a .cmft-file). However, iOS and MacOS devices only support the TTML based variant of ISO-14496-30 (IMSC1 Text) in fMP4, not WebVTT. For WebVTT, only WebVTT Segments are supported. To generate those WebVTT Segments and the necessary Media Playlist, follow the instructions for Adding WebVTT subtitles when packaging HLS TS.

Create I-frame Playlists

In addition to creating standard Media Playlists for each track, create I-frame Playlists for every track to enable trick play and allow viewers to fast forward and rewind playback of your stream. To do so, you can:

  • Create I-frame Playlists based on sync-samples only MP4s, as explained in Adding trick play to a DASH or HLS stream

  • Or you can create I-frame Playlists based on the regular video files, by using the --create_iframe_playlist option

The latter is explained below:

--create_iframe_playlist

#!/bin/bash

mp4split -o iframe-tos-400k-fmp4.m3u8 \
  --create_iframe_playlist \
  tos-8s-avc1-400k.cmfv
mp4split -o iframe-tos-750k-fmp4.m3u8 \
  --create_iframe_playlist \
  tos-8s-avc1-750k.cmfv
mp4split -o iframe-tos-1000k-fmp4.m3u8 \
  --create_iframe_playlist \
  tos-8s-avc1-1000k.cmfv

Note

Also, the --create_iframe_playlist option used for fMP4 HLS should not be used for HLS with Transport Streams, as the necessary I-frame Playlists are generated automatically when packaging the latter.

Create Master Playlist

Packaging the media playlists into a Master Playlist is done the usual way.

#!/bin/bash

mp4split -o master_fmp4_clear.m3u8 \
  tos-64k-fmp4.m3u8 \
  tos-128k-fmp4.m3u8 \
  tos-400k-fmp4.m3u8 \
  tos-750k-fmp4.m3u8 \
  tos-1000k-fmp4.m3u8 \
  iframe-tos-400k-fmp4.m3u8 \
  iframe-tos-750k-fmp4.m3u8 \
  iframe-tos-1000k-fmp4.m3u8

Protecting a statically packaged fMP4 HLS stream

When streaming fMP4 HLS, Apple specifies that the CENC 'cbcs' encryption scheme must be used if you want to protect your content.

To do so, requires the following:

  • Add 'cbcs' encryption when packaging your content as CMAF

  • Add the required signaling of the keys when generating the Media Playlists

Note

When generating a Media Playlist, you can specify a value for the advisory HLS tag 'HDCP-LEVEL' using the option --hdcp_level, for which none, type-0 and type-1 are valid values (e.g., --hdcp_level=type-1). If this tag is not specified, it will not be added.

Adding CENC 'cbcs' encryption

To encrypt your content according to the CENC 'cbcs' encryption scheme you add the following parameters to your command-line when packaging your content to CMAF (with your own keys, of course).

--cenc.key=10000000100010001000100000000001:3a2a1b68dd2bd9b2eeb25e84c4776668 \
--cenc.key_iv=f9d9d5f5f3b5bc0372856df068f9f6a2 \
--scheme_type=cbcs

Like so:

#!/bin/bash

CEK=3a2a1b68dd2bd9b2eeb25e84c4776668
KID=10000000100010001000100000000001
KIV=f9d9d5f5f3b5bc0372856df068f9f6a2

mp4split -o tos-8s-128k-cbcs.cmfa \
  --fragment_duration=384000/48000 \
  --cenc.key=${KID}:${CEK} \
  --cenc.key_iv=${KIV} \
  --scheme_type=cbcs \
  tears-of-steel-aac-128k.mp4

mp4split -o tos-8s-2200k-cbcs.cmfv \
  --fragment_duration=192/24 \
  --cenc.key=${KID}:${CEK} \
  --cenc.key_iv=${KIV} \
  --scheme_type=cbcs \
  tears-of-steel-avc1-2200k.mp4

To add the necessary signaling of the key to your Media Playlists, make use of the --encrypt_key_url option when creating these playlists.

For example:

#!/bin/bash

CEK=3a2a1b68dd2bd9b2eeb25e84c4776668

# Store binary representation of CEK in cek.key file
echo ${CEK} | xxd -p -r > cek.key

# URL that resolves to the cek.key file
LA_URL=https://license-server/cek.key

mp4split -o tos-128k-fmp4-cbcs.m3u8 \
  --encrypt_key_url=${LA_URL} \
  tos-8s-128k-cbcs.cmfa

mp4split -o tos-2200k-fmp4-cbcs.m3u8 \
  --encrypt_key_url=${LA_URL} \
  tos-8s-2200k-cbcs.cmfv

Then, with all the Media Playlists in place, you generate the I-frame Playlists and Master Playlist as you normally would.

Use tos-fmp4-hls-cbcs-static.sh to package the Tears of Steel demo contents as CMAF with 'cbcs' encryption and subsequently generate the necessary HLS playlists to set up a statically packaged and encrypted fMP4 HLS stream.

Adding FairPlay DRM

When you want to use FairPlay DRM, you have to set the --encrypt_key_url to signal the URL of your FairPlay licensing server. Additionally, you have to add the option --key_format="com.apple.streamingkeydelivery" when generating your Media Playlists.

#!/bin/bash

KID=10000000100010001000100000000001
FP_URL=skd://${KID}

mp4split -o tos-128k-fmp4-fp.m3u8 \
  --encrypt_key_url=${FP_URL} \
  --key_format="com.apple.streamingkeydelivery" \
  tos-8s-128k-cbcs.cmfa

mp4split -o tos-2200k-fmp4-fp.m3u8 \
  --encrypt_key_url=${FP_URL} \
  --key_format="com.apple.streamingkeydelivery" \
  tos-8s-2200k-cbcs.cmfv

Then, with all the Media Playlists in place, you generate the I-frame Playlists and Master Playlist as you normally would.

Adding PlayReady DRM

To support PlayReady 4 for HLS, add the necessary signaling when generating the Media Playlists with Unified Packager, by using the --iss.drm_specific_data command-line option to specify the base64 encoded PlayReady Object containing the PlayReady Header (or, even better, the complete PSSH box):

#!/bin/bash

PR_OBJECT=uAIAAAEAAQCuAjwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0AbABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzAG8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQBhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADMALgAwAC4AMAAiAD4APABEAEEAVABBAD4APABMAEEAXwBVAFIATAA+AGgAdAB0AHAAOgAvAC8AZQB4AHAAZQByAGkAbQBlAG4AdABhAGwAMQAuAGEAegB1AHIAZQB3AGUAYgBzAGkAdABlAHMALgBuAGUAdAAvAHIAaQBnAGgAdABzAG0AYQBuAGEAZwBlAHIALgBhAHMAbQB4AD8AYwBmAGcAPQAoAGMAawA6AFcAMwAxAGIAZgBWAHQAOQBXADMAMQBiAGYAVgB0ADkAVwAzADEAYgBmAFEAPQA9ACwAYwBrAHQAOgBBAEUAUwAxADIAOABCAGkAdABDAEIAQwApADwALwBMAEEAXwBVAFIATAA+ADwAUABSAE8AVABFAEMAVABJAE4ARgBPAD4APABLAEkARABTAD4APABLAEkARAAgAEEATABHAEkARAA9ACIAQQBFAFMAQwBCAEMAIgAgAFYAQQBMAFUARQA9ACIAQQBBAEEAQQBFAEEAQQBRAEEAQgBBAFEAQQBCAEEAQQBBAEEAQQBBAEEAUQA9AD0AIgA+ADwALwBLAEkARAA+ADwALwBLAEkARABTAD4APAAvAFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwALwBEAEEAVABBAD4APAAvAFcAUgBNAEgARQBBAEQARQBSAD4A

mp4split -o tos-128k-fmp4-pr.m3u8 \
  --iss.drm_specific_data=${PR_OBJECT} \
  tos-8s-128k-cbcs.cmfa

mp4split -o tos-2200k-fmp4-pr.m3u8 \
  --iss.drm_specific_data=${PR_OBJECT} \
  tos-8s-2200k-cbcs.cmfv

mp4split -o tos-master-pr.m3u8 \
  tos-128k-fmp4-pr.m3u8 \
  tos-2200k-fmp4-pr.m3u8

Adding Widevine DRM

To support Widevine DRM for HLS V2, add the necessary signaling when generating the Media Playlists with Unified Packager, by using the --widevine.drm_specific_data command-line option to specify the base64 encoded Widevine data (or, even better, the complete PSSH box).

#!/bin/bash

WV_DATA=IhBma2ozbGphU2RmYWxrcjNqSOPclZsG

mp4split -o tos-128k-fmp4-wv.m3u8 \
  --widevine.drm_specific_data=${WV_DATA} \
  tos-8s-128k-cbcs.cmfa

mp4split -o tos-2200k-fmp4-wv.m3u8 \
  --widevine.drm_specific_data=${WV_DATA} \
  tos-8s-2200k-cbcs.cmfv

mp4split -o tos-master-wv.m3u8 \
  tos-128k-fmp4-wv.m3u8 \
  tos-2200k-fmp4-wv.m3u8