Transcoding multiple qualities for video, generating manifest MPEG DASH, encryption

Jumanah Al Asadi
4 min readJan 25, 2023

--

Bento4 is a helpful tool to transcoding videos and get them ready for streaming.

What’s in this article!

Before you can share your video to the general public, a standard practise is to break it up into small segments so your users can stream it gradually instead of waiting for the entire file to download. Also, you should create different video qualities, such as high and low to support different internet connection speeds that your users may have.

There are already two streaming standards available, Apple HLS and MPEG DASH. In this article we will explore MPEG DASH.

The process of transcoding is having an input single video, and outputting streaming segments with a manifest (file which describes the order to play the segments).

A great and simple tool to get this done is Bento4 which wraps over ffmpeg libraries.

To get started, prepare a video in different resolutions!

Bento4 Installation

1. Installing bento 4 on Mac osx

- Homebrew: [bento4 — Homebrew Formulae](https://formulae.brew.sh/formula/bento4)

This will give us access to the bento4 tools like mp4info, mp4fragment, mp4dash, mp4encrypt..

2. Make sure your Mac OS terminal can access your files

- [permission — Why do I get “ls: Desktop: Operation not permitted” when I own Desktop? — Ask Different](https://apple.stackexchange.com/questions/425519/why-do-i-get-ls-desktop-operation-not-permitted-when-i-own-desktop)

How to Segment and Create Dash Manifests

Source Guideline: [How to Package MPEG-DASH using Bento4’s mp4dash — OTTVerse](https://ottverse.com/bento4-mp4dash-for-mpeg-dash-packaging/)

1. Create a folder, and video files with 3 different resolutions/qualities

/capture_dash

  • CAPTURE_123ABC_1920x1080.mp4
  • CAPTURE_123ABC_1280x720.mp4
  • CAPTURE_123ABC_640x360.mp4

2. Pre-requisite: In order to segment the files with bento4, first fragment the files using mp4fragment. Choose how how many ms.. using the — fragment-duration flag.

i.e 4000ms = 4 seconds etc.

mp4fragment — fragment-duration 4000 ./CAPTURE_123ABC_1920x1080.mp4 ./CAPTURE_123ABC_1920x1080_frag.mp4

mp4fragment - fragment-duration 4000 ./CAPTURE_123ABC_1280x720.mp4 ./CAPTURE_123ABC_1280x720_frag.mp4

mp4fragment - fragment-duration 4000 ./CAPTURE_123ABC_640x360.mp4 ./CAPTURE_123ABC_640x360_frag.mp4

Optional: we can use mp4info to confirm that the video is fragmented.

mp4info CAPTURE_123ABC_640x360_frag.mp4

Output:

Movie:
duration: 32600 (media timescale units)
duration: 32600 (ms)
time scale: 1000
*fragments: yes*

3. Then run the dashify command! You can specify the name of the manifest file using — mpd-name and provide the three different qualities which were fragmented in the previous step.

mp4dash — mpd-name manifest.mpd CAPTURE_123ABC_1920x1080_frag.mp4 CAPTURE_123ABC_1280x720_frag.mp4 CAPTURE_123ABC_640x360_frag.mp4

Output:

Files will be segmented as .m4s files of (1–6 seconds). They will be placed into different folders based on their qualities, and will be sequential.

Manifest generated will be an manifest.mpd file, bento4 will automatically understand the three qualities from the video / resolutions will be displayed as different representations with different bandwidths.

<?xml version="1.0" ?>
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" profiles="urn:mpeg:dash:profile:isoff-live:2011" minBufferTime="PT1.00S" mediaPresentationDuration="PT4.004S" type="static">
<! - Created with Bento4 mp4-dash.py, VERSION=2.0.0–639 →
<Period>
<! - Video →
<AdaptationSet mimeType="video/mp4" segmentAlignment="true" startWithSAP="1" maxWidth="1920" maxHeight="1080">
<SegmentTemplate timescale="1000" duration="1001" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/seg-$Number$.m4s" startNumber="1"/>
<Representation id="video/avc1/1" codecs="avc1.640028" width="1920" height="1080" scanType="progressive" frameRate="30000/1001" bandwidth="6320503"/>
<Representation id="video/avc1/2" codecs="avc1.64001F" width="1280" height="720" scanType="progressive" frameRate="30000/1001" bandwidth="3269850"/>
<Representation id="video/avc1/3" codecs="avc1.64001F" width="640" height="360" scanType="progressive" frameRate="30000/1001" bandwidth="1843364"/>
</AdaptationSet>
</Period>
</MPD>

Encryption & DRM:

If a media provider needs to encrypt the files they are generating, so that nobody can open them unless they are allowed to or “subscribed”, you can do so using an encryption key. A more production, “real world” and secure way to protect premium media content is accomplished by leveraging a DRM (Digital Rights Management) set up. A DRM will license both an encryption key to secure the content at the time of transcoding, and a decryption key to the Media Player to play the secure files.

Bento4 works with various DRMs. The simplest way to produce encrypted MPEG DASH streams is to instruct mp4dash to perform the encryption for you automatically, by using the — encryption-key option.

1. Add encryption flags to the mp4dash command.. For example to encrypt content using a DRM, like Marlin:

mp4dash — mpd-name manifest.mpd — marlin — encryption-key=121a0fca0f1b475b8910297fa8e0a07e:a0a1a2a3a4a5a6a7a8a9aaabacadaeaf CAPTURE_123ABC_1920x1080_frag.mp4 CAPTURE_123ABC_1280x720_frag.mp4 CAPTURE_123ABC_640x360_frag.mp4

After running this command, the files will be segmented and encrypted at the same time.

If you try to open any of the files you will see the following: “Protected videos can only be played using…”

Within the manifest.mpd, there will be extra tags to inform the player of what DRM(s) can be used to obtain the decryption keys for the stream.

<?xml version="1.0" ?>
<MPD xmlns:cenc="urn:mpeg:cenc:2013" xmlns:mas="urn:marlin:mas:1–0:services:schemas:mpd" xmlns="urn:mpeg:dash:schema:mpd:2011" profiles="urn:mpeg:dash:profile:isoff-live:2011" minBufferTime="PT1.00S" mediaPresentationDuration="PT4.004S" type="static">
<! - Created with Bento4 mp4-dash.py, VERSION=2.0.0–639 →
<Period>
<! - Video →
<AdaptationSet mimeType="video/mp4" segmentAlignment="true" startWithSAP="1" maxWidth="1920" maxHeight="1080">
<! - MPEG Common Encryption →
<ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc" cenc:default_KID="121a0fca-0f1b-475b-8910–297fa8e0a07e"/>
<! - Marlin →
<ContentProtection schemeIdUri="urn:uuid:5E629AF5–38DA-4063–8977–97FFBD9902D4">
<mas:MarlinContentIds>
<mas:MarlinContentId>urn:marlin:kid:121a0fca0f1b475b8910297fa8e0a07e</mas:MarlinContentId>
</mas:MarlinContentIds>
</ContentProtection>
<SegmentTemplate timescale="1000" duration="1001" initialization="$RepresentationID$/init.mp4" media="$RepresentationID$/seg-$Number$.m4s" startNumber="1"/>
<Representation id="video/avc1/1" codecs="avc1.640028" width="1920" height="1080" scanType="progressive" frameRate="30000/1001" bandwidth="6326921"/>

</AdaptationSet>
</Period>
</MPD>

2. Another example using Google Widevine DRM, in order to dashify and encrypt at the same time use the — widevine flags.

mp4dash — mpd-name manifest.mpd — widevine-header “#CAESEJA1GVFoa14boiJDns7B8SoaDXdpZGV2aW5lX3Rlc3QiASo=” — encryption-key 90351951686b5e1ba222439ecec1f12a:0a237b0752cbf1a827e2fecfb87479a2 CAPTURE123ABC_1920x1080_frag.mp4 CAPTURE123ABC_1280x720_frag.mp4 CAPTURE123ABC_640x360_frag.mp4```

And the manifest will have the following tags inside for the player to find.

<! — MPEG Common Encryption →
<ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc" cenc:default_KID="90351951–686b-5e1b-a222–439ecec1f12a"/>
<! - Widevine →
<ContentProtection schemeIdUri="urn:uuid:edef8ba9–79d6–4ace-a3c8–27dcd51d21ed">
<cenc:pssh>AAAARnBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAACYIARIQkDUZUWhrXhuiIkOezsHxKhoNd2lkZXZpbmVfdGVzdCIBKg==</cenc:pssh>
</ContentProtection>

If you want to do encryption in a specific way, you can use *mp4encrypt* instead. For example, If you need more precise control over encryption (for example only encryption certain tracks and not others, or use special options), you can encrypt the media before using mp4dash. This is done by calling mp4encrypt directly on the input files before calling mp4dash

mp4encrypt — method MPEG-CENC — key 1:a0a1a2a3a4a5a6a7a8a9aaabacadaeaf:0123456789abcdef — property 1:KID:121a0fca0f1b475b8910297fa8e0a07e — key 2:a0a1a2a3a4a5a6a7a8a9aaabacadaeaf:aaaaaaaabbbbbbbb — property 2:KID:121a0fca0f1b475b8910297fa8e0a07e CAPTURE123ABC_1920x1080_frag.mp4 CAPTURE456DEF_1920x1080_frag.mp4

See more details:

[Encryption & DRM — Bento4](https://www.bento4.com/developers/dash/encryption_and_drm/)

--

--

Jumanah Al Asadi

I am just a web developer who loves writing, teaching and music :) My teaching style is playful and fun. At least I hope, lol :p