HLS with fragmented MP4

When streaming fMP4 over HLS, Apple specifies the 'cbcs' encryption scheme for encrypting content. This is the only encryption scheme of the 3rd edition of the Common Encryption (CENC) specification that Apple supports.

Because the 'cbcs' is part of CENC, adding it to Origin's fMP4 HLS output requires you to signal the encryption information as being compatible with CENC in addition to signaling the information for HLS.

Signaling the CENC related information is done with the parameters that start with iss, while the information necessary for HLS is signaled using the parameters starting with hls. The result is that the CEK and KIV need to be signaled twice.

Adding 'cbcs' Encryption

Below an example command-line for adding encryption according to CENC's 'cbcs' scheme. Please read HLS with fragmented MP4 for some necessary background information.

#!/bin/bash

CEK=3a2a1b68dd2bd9b2eeb25e84c4776668
KID=10000000100010001000100000000001
KIV=f9d9d5f5f3b5bc0372856df068f9f6a2

# 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-fmp4-hls-cbcs.ism \
  --hls.fmp4 \
  --iss.key=${KID}:${CEK} \
  --iss.key_iv=${KIV} \
  --hls.key=:${CEK} \
  --hls.key_iv=${KIV} \
  --hls.license_server_url=${LA_URL} \
  --hls.playout=sample_aes \
  tears-of-steel-aac-128k.cmfa \
  tears-of-steel-avc1-1500k.cmfv

Note

In case you are only concerned with adding encryption to your fMP4 HLS according to CENC's 'cbcs' scheme, the KID that you input as the first part of the value for the --iss.key parameter can be blank, because Apple does not specify the use of a KID. The same is true for the value signaled for --iss.license_server_url, which is not relevant in such cases either.

Adding FairPlay DRM

Find below an example command-line for adding FairPlay DRM with encryption according to CENC's 'cbcs' scheme. Please read HLS with fragmented MP4 for some necessary background information. The '<license-server-url>' that you pass on the command-line using --hls.license_server_url is dependent on your FairPlay implementation (i.e., you have to provide the exact information yourself).

#!/bin/bash

CEK=3a2a1b68dd2bd9b2eeb25e84c4776668
KID=10000000100010001000100000000001
KIV=f9d9d5f5f3b5bc0372856df068f9f6a2

mp4split -o tos-fmp4-hls-cbcs.ism \
  --hls.fmp4 \
  --iss.key=${KID}:${CEK} \
  --iss.key_iv=${KIV} \
  --hls.key=:${CEK} \
  --hls.key_iv=${KIV} \
  --hls.license_server_url=<license-server-url> \
  --hls.playout=sample_aes_streamingkeydelivery \
  tears-of-steel-aac-128k.cmfa \
  tears-of-steel-avc1-1500k.cmfv

Note

In case you do not require any multi-DRM functionality and are only concerned with adding FairPlay, the KID that you input as the first part of the value for the --iss.key parameter can be a dummy, because Apple does not specify the use of a KID. The same goes for the value signaled for --iss.license_server_url, which is not relevant in such cases either.

Adding PlayReady DRM

PlayReady requires the DRM related information to be signaled in a base64 encoded PlayReady Object, which you should provide yourself. This PlayReady Object will be a blob of data that you can pass on the command-line using the --iss.drm_specific_data. Unified Origin will extract the PlayReady Header (WRMHeader encoded as UTF16) from the PlayReady Object and signal it in the playlist.

#!/bin/bash

KID=10000000100010001000100000000001
CEK=5b7d5b7d5b7d5b7d5b7d5b7d5b7d5b7d
KIV=3B3A3B3A3B3A3B3A3B3A3B3A3B3A3B3A
PR_OBJECT=uAIAAAEAAQCuAjwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0AbABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzAG8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQBhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADMALgAwAC4AMAAiAD4APABEAEEAVABBAD4APABMAEEAXwBVAFIATAA+AGgAdAB0AHAAOgAvAC8AZQB4AHAAZQByAGkAbQBlAG4AdABhAGwAMQAuAGEAegB1AHIAZQB3AGUAYgBzAGkAdABlAHMALgBuAGUAdAAvAHIAaQBnAGgAdABzAG0AYQBuAGEAZwBlAHIALgBhAHMAbQB4AD8AYwBmAGcAPQAoAGMAawA6AFcAMwAxAGIAZgBWAHQAOQBXADMAMQBiAGYAVgB0ADkAVwAzADEAYgBmAFEAPQA9ACwAYwBrAHQAOgBBAEUAUwAxADIAOABCAGkAdABDAEIAQwApADwALwBMAEEAXwBVAFIATAA+ADwAUABSAE8AVABFAEMAVABJAE4ARgBPAD4APABLAEkARABTAD4APABLAEkARAAgAEEATABHAEkARAA9ACIAQQBFAFMAQwBCAEMAIgAgAFYAQQBMAFUARQA9ACIAQQBBAEEAQQBFAEEAQQBRAEEAQgBBAFEAQQBCAEEAQQBBAEEAQQBBAEEAUQA9AD0AIgA+ADwALwBLAEkARAA+ADwALwBLAEkARABTAD4APAAvAFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwALwBEAEEAVABBAD4APAAvAFcAUgBNAEgARQBBAEQARQBSAD4A

mp4split -o hls-fmp4-playready.ism \
  --hls.fmp4 \
  --iss.key=$KID:$CEK \
  --iss.key_iv=$KIV \
  --iss.drm_specific_data=$PR_OBJECT \
  --hls.playout=playready \
  --hls.minimum_fragment_length=6 \
  cmaf/tears-of-steel-aac-64k.cmfa \
  cmaf/tears-of-steel-aac-128k.cmfa \
  cmaf/tears-of-steel-avc1-400k.cmfv \
  cmaf/tears-of-steel-avc1-750k.cmfv \
  cmaf/tears-of-steel-avc1-1000k.cmfv \
  cmaf/tears-of-steel-avc1-1500k.cmfv

Note

Currently (March 2018), the playout support for PlayReady with 'cbcs' encryption is very limited. The only known client to support this combination is the Xbox upgraded to software version 1709 or higher.

Adding Widevine DRM

For Widevine, you put the DRM information in a CPIX file (for more info on this format, see Introduction to CPIX):

#!/bin/bash

mp4split -o hls-fmp4-widevine.ism \
  --hls.fmp4 \
  --hls.cpix=hls-fmp4-widevine.cpix \
  --hls.playout=widevine \
  --hls.minimum_fragment_length=6 \
  cmaf/tears-of-steel-aac-64k.cmfa \
  cmaf/tears-of-steel-aac-128k.cmfa \
  cmaf/tears-of-steel-avc1-400k.cmfv \
  cmaf/tears-of-steel-avc1-750k.cmfv \
  cmaf/tears-of-steel-avc1-1000k.cmfv \
  cmaf/tears-of-steel-avc1-1500k.cmfv

Where hls-fmp4-widevine.cpix contains the following (note that the PSSH data for Widevine contains explicit signaling for the cbcs encryption scheme):

<CPIX xmlns:pskc="urn:ietf:params:xml:ns:keyprov:pskc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:dashif:org:cpix" xsi:schemaLocation="urn:dashif:org:cpix cpix.xsd">
  <ContentKeyList>
    <ContentKey kid="d69109a4-380b-59eb-8473-1c4c73d5c2e6">
      <Data>
        <pskc:Secret>
          <pskc:PlainValue>3EoZk8ABlJ7JLzP9nryzzw==</pskc:PlainValue>
        </pskc:Secret>
      </Data>
    </ContentKey>
  </ContentKeyList>
  <DRMSystemList>
    <DRMSystem kid="d69109a4-380b-59eb-8473-1c4c73d5c2e6" systemId="edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
      <PSSH>AAAAOHBzc2gBAAAA7e+LqXnWSs6jyCfc1R0h7QAAAAAAAAAUIgx3aWRldmluZWNiY3NI88aJmwY=</PSSH>
      <HLSSignalingData playlist="media"></HLSSignalingData>
      <HLSSignalingData playlist="master"></HLSSignalingData>
    </DRMSystem>
  </DRMSystemList>
</CPIX>