Introduction
Adaptive Bitrate Streaming
Imagine a scenario where we have a ability to control every user’s player and identify the best possible stream to feed on their connection, we would then need to have different versions of video for different users.
Having only access to the users connection attributes will not solve other problems that might arise while streaming video over internet. What if the user changes the connection type (3G to WiFi) or network type ? Then our system must be able to switch to a different video that we have stored on the server. But then a player still need to have memory of users current position and must start from there for the newly loaded version of video.
A cool thing would be if video players could detect changes in network type and available bandwidth, and then switch transparently between different streams (of the same video prepared for different speeds) until it finds the best one. Seems complex right ? This is the exact issue that adaptive bitrate streaming promises to solve.
HLS – HTTP Live Streaming
HLS which stand for HTTP Live Streaming is an adaptive bitrate streaming protocol which was introduced by Apple in 2009. HLS is default streaming protocol for all the iOS devices and also it can be used on Android and web browsers. This protocol uses a playlist file (m3u8) which will have information about the media that need to be streamed. HTTP is used for the communication between the server and client.
Usage – How to use hls.js for video streaming ?
Preparation
First of all lets create a files that are needed for the HLS protocol. We will be using ffmpeg to convert the source mp4 video file to the necessary playlist and chunks. To convert use the following code.
ffmpeg -i sample.mp4 -profile:v baseline -level 5.0 -s 1366x768 -ss 5 -start_number 0 -hls_time 1 -hls_list_size 20 -fs 0 -f hls index720p.m3u8
similar code can be used to generate different resolution based output files. For this blog we will be generating chunks for the high, mid and low end resolutions. After the necessary steps we will have the following files on the server.
Now lets prepare the manifest.m3u8 file to define media to stream on different network bandwidth.
#EXTM3U #EXT-X-STREAM-INF:BANDWIDTH=900,DEFAULT=YES,VIDEO="low" index.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=4080000,DEFAULT=NO,VIDEO="mid" index720p.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=8080000,DEFAULT=NO,VIDEO="hi" index1080p.m3u8
Implementation
create index.html file and place the following code.
- Knowledge of hls.js is required.
<!DOCTYPE HTML> <html> <head> <title>HLS Sample</title> <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script> </head> <body> </div> <div class="row"> <div class="col-md-6 align__video"> <video height="360" width="640" id="video" controls></video> </div> <div class="col-md-6 align__video"> <div id='resolution'></div> </div> </div> <script> let video = document.getElementById('video'); if (Hls.isSupported()) { var hls = new Hls(); hls.loadSource('manifest.m3u8'); hls.attachMedia(video); hls.on(Hls.Events.MANIFEST_PARSED, function () { video.play().then(() => { console.log(video.videoHeight, '<<<<HRIGHT', video.videoWidth, '<<<WIDTH'); let resolution = document.getElementById('resolution'); resolution.innerText = video.videoHeight + 'x' + video.videoWidth; }); }); } // hls.js is not supported on platforms that do not have Media Source Extensions (MSE) enabled. // When the browser has built-in HLS support (check using `canPlayType`), we can provide an HLS manifest (i.e. .m3u8 URL) directly to the video element through the `src` property. // This is using the built-in support of the plain video element, without using hls.js. // Note: it would be more normal to wait on the 'canplay' event below however on Safari (where you are most likely to find built-in HLS support) the video.src URL must be on the user-driven // white-list before a 'canplay' event will be emitted; the last video event that can be reliably listened-for when the URL is not on the white-list is 'loadedmetadata'. else if (video.canPlayType('application/vnd.apple.mpegurl')) { video.src = 'master.m3u8'; video.addEventListener('loadedmetadata', function () { video.play(); }); } </script> </body> </html>
Now lets serve our index.html and use the throttling feature available on chrome to see the advantage of the HLS protocol.
- When using no throttling the high resolution files will be loaded, refer to the screenshot below:
- But when we use the slow 3G throttle option, then we can see completely different files with different resolution which fits the users network will be loaded.