Guide to encoding videos for streaming with Transloadit

Tyler McAllister
Like us at Transloadit, you are probably a fan of streaming services 🎥 But have you ever considered
starting your own? Our /video/adaptive Robot has
you covered in case you did have a wild idea like that! You can use this Robot to encode
mp4 or webm video to either HLS (HTTP Live Streaming) or MPEG-DASH.
In this blog post, we'll walk you through the process of creating a basic proof-of-concept adaptive player in React that supports streaming HLS, MPEG-DASH, or MP4 video, depending on the compatibility of the browser, in a similar vein to one of our JavaScript demos.

What are HLS and MPEG-DASH?
Before we get started, let's clarify what HLS and MPEG-Dash are exactly. Both are streaming protocols that split up video data into small chunks that can be downloaded to a device over HTTP. But which format should you choose? HLS may seem like the go-to option since it's the most widely supported, especially on Apple devices (since they are its creators). The downside to HLS is that it only supports its own DRM, so providing heavy-duty protection can be a bit more complicated.
MPEG-DASH, on the other hand, is an open-source standard. It can also benefit users who want to use their data efficiently, as it allows video quality to be switched on the fly. The downside to MPEG-DASH is that relatively few browsers — and none of the iOS devices — support it.
For this walkthrough, we'll encode to both formats, and use them to work with an adaptive video player.
Storing our files via Assembly
We can jump straight into the Assembly below for an overview of how to use the Robot.
{
"steps": {
":original": {
"robot": "/upload/handle"
},
"hls-encode": {
"use": ":original",
"robot": "/video/encode",
"ffmpeg_stack": "{{stacks.ffmpeg.recommended_version}}",
"preset": "hls-720p"
},
"dash-encode": {
"use": ":original",
"robot": "/video/encode",
"ffmpeg_stack": "{{stacks.ffmpeg.recommended_version}}",
"preset": "dash-720p-video"
},
"thumbnailed": {
"use": "hls-encode",
"robot": "/video/thumbs",
"result": true,
"ffmpeg_stack": "{{stacks.ffmpeg.recommended_version}}"
},
"hls-adaptive": {
"use": {
"steps": ["hls-encode"],
"bundle_steps": true
},
"robot": "/video/adaptive",
"ffmpeg_stack": "{{stacks.ffmpeg.recommended_version}}",
"playlist_name": "my_playlist.m3u8",
"segment_duration": 6,
"closed_captions": false,
"technique": "hls"
},
"dash-adaptive": {
"use": {
"steps": ["dash-encode"],
"bundle_steps": true
},
"robot": "/video/adaptive",
"ffmpeg_stack": "{{stacks.ffmpeg.recommended_version}}",
"playlist_name": "my_playlist.mpd",
"segment_duration": 6,
"technique": "dash"
},
"export-plain": {
"use": ["thumbnailed", "dash-encode"],
"robot": "/google/store",
"credentials": "stream-test",
"acl": "public-read",
"path": "stream-videos/${file.name}"
},
"export-hls": {
"use": "hls-adaptive",
"robot": "/google/store",
"credentials": "stream-test",
"acl": "public-read",
"path": "stream-videos/hls-video/${file.name}"
},
"export-dash": {
"use": "dash-adaptive",
"robot": "/google/store",
"credentials": "stream-test",
"acl": "public-read",
"path": "stream-videos/dash-video/${file.name}"
}
}
}
Don't let the size of these Assembly Instructions worry you. Let's break it down.
In the first Step, the /upload/handle Robot's usage is clear. We utilize it to get a video from an end-user.
Secondly, the /video/encode Robot encodes the
uploaded video into HLS and MPEG-DASH at the hls-encode and dash-encode Steps,
respectively. These are necessary Steps for the
/video/adaptive Robot.
Thirdly, since we're going to be working with a video player, it would be useful if we could easily
extract a thumbail from our video. Luckily, that's exactly what the
/video/thumbs Robot is doing at the thumbnailed
Step ✨
Now we reach the star of the show - the /video/adaptive
Robot. In the Assembly, we have split its tasks up into two separate
Steps: hls-adaptive and dash-adaptive. Let's take a look at the parameters this
Robot is given. They take their respective encoded videos and generate a .m3u8 and
.mpd playlist. MPEG-DASH and HLS protocol files are composed of a playlist (.m3u8 or .mpd)
and a sequence of segments. The playlist file simply looks for the associated segments necessary
for streaming the video and plays through them sequentially.
Using segment_duration, we can define the maximum amount of time each segment of the streaming
video will have. This can be an important thing to consider when thinking about your user's data and
download capacity. Another quirk of these protocols is that we need to make sure their segments are
always in the same directory as their playlist, otherwise the playlists will be looking for segments
they can't find. Thankfully, at the last overall Step, the
/google/store Robot sets the path for the MPEG-DASH
and HLS files to a defined path like - stream-videos/dash-video/${file.name}. This means that
everything should be bunched together nicely. Just be sure to set up store.object.create
permissions in your Bucket. We also store the
.mp4 video and thumbnail using the same Robot.
A proof of concept via React
Griffith is a video player for React that is very easy to get
started with. It takes props containing the properties of the player and an object sources
consisting of the URL of the video along with its format.
var sources = {
hd: {
bitrate: 905,
size: 10105235,
duration: 0,
width: 1280,
height: 720,
play_url: 'https://storage.googleapis.com/yourbucket/streamvideos/hls-video/my_playlist.m3u8',
},
}
We can detect the browser's compatibility with MPEG-DASH and HLS by using the following code:
function checkCompatibility() {
var compatibility = document.createElement('video')
if (compatibility.canPlayType('application/x-mpegURL')) {
return build_sources('m3u8', 'my_playlist')
}
if (compatibility.canPlayType('application/dash+xml')) {
return build_sources('mpd', 'my_playlist')
}
if (compatibility.canPlayType('video/mp4')) {
return build_sources('mp4', 'my_playlist')
} else {
console.log('No compatible video found')
}
}
You can find my basic implementation here. The /video/adaptive Robot really does streamline the generation of streaming media. As people consume more videos over the internet, we're confident that this Robot could prove to be a useful utility for those looking for a simple and sleek solution.
For further reading, our demo: Make video compatible for all devices may interest you as it illustrates how to mix and match this with other formats, depending on what the playback device supports, and provides sample code for a non-React player: Plyr.