Load Testing HLS Stream Using JMeter
What is Video Streaming?
Although highly unlikely, but if you are wondering the meaning of video streaming, it simply means that to play the online video, you won’t need to download the video completely. It offers you other advantages like you can jump directly to a section of the video and start playing it from there. As you don’t need to download the file, it saves you bandwidth if you don’t intend to watch the complete video by maintaining only a small buffer of the video.
What is HLS Stream?
There are different protocols to serve videos online. The most common one is RTMP (Real Time Messaging Protocol), which is a flash based protocol. The problem with RTMP is that it uses its ports for flash media. By other ports, I mean that your web server uses port 80. But RTMP video will require a port other than 80. So if your firewall allows only port 80 traffic, then the RTMP video will not pass through your firewall. One workaround is that we can use HTTP tunneling and use RTMPT protocol, but it will be a huge performance tradeoff for the server.
Another drawback of RTMP is that since it is a flash based protocol, it will require a flash player embedded in your browser and will not be supported in HTML5.
Okay, it seems like we are convinced that we will not be using RTMP for our videos. So what alternatives do we have? You already guessed that it would be HLS protocol. (Since the post and this section is about HLS only.)
HTTP Live Streaming (HLS), as the name suggests, is an HTTP-based media streaming protocol, by Apple Inc. As it is proprietary of Apple Inc., along with HTML5, it is fully supported by all IOS devices as well (RTMP was not supported by IOS devices). This protocol is adaptive, which means that it will automatically adjust the video quality according to the browser bandwidth. This was not possible (without using a streaming engine) with RTMP.
What is JMeter?
JMeter is an open source tool for performance and load testing. It can be used for application testing as well as video testing. You can set up JMeter as master-slave as well. JMeter will be used to test the HLS stream in this blog post. I assume basic understanding and familiarity with JMeter.
JMeter and HLS Stream
Before proceeding with the steps of load testing HLS stream with Jmeter, Let’s have a brief look at how HLS stream works.
The HLS Stream splits the video into smaller chunks and creates a playlist for these small chunks. The playlist is downloaded as an m3u8 file, which contains the list of all the chunks in that video. In order to proceed, you need this playlist file. From this file, video chunks will be extracted. The actual video chunks are small ts files.
Load Testing
Step 1: Get the m3u8 file URL
The m3u8 file, the playlist file for our load testing, will be the starting point for the JMeter script. How do you get URL for this file? You can use developer tools in your browser and look under Network tab. In the filter provided, as shown in the below image, you can search for m3u8:
Now, let’s see the contents of this file. We will get this file (curl) from the URL we got above:
[sourcecode language=”js”]$ curl "http://xxx.yyy.com/p/1982551/sp/198255100/0_cejlz2mj/format/applehttp/protocol/http/f/a.m3u8"[/sourcecode]
This command will produce the following output:
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=98304,RESOLUTION=128x72 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=333824,RESOLUTION=640x360 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=479232,RESOLUTION=640x360 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=680960,RESOLUTION=640x360
This file gives us four new playlists. These playlists will be downloaded next, and one of these will be chosen according to the browser bandwidth. You might want to go with the highest resolution and bandwidth since you are going to load test the video.
Now this will be your final playlist URL which you will be using in your JMeter script. Before getting our hands dirty on JMeter, let’s have a look at our chosen playlist file:
[sourcecode language=”js”]$ curl “http://xxx.yyy.com/enc/1982551/sp/198255100/0_cejlz2mj/flavorId/0_hjddwmny/name/a.mp4/index.m3u8”[/sourcecode]
The output of this curl command will look like this:
#EXTM3U #EXT-X-TARGETDURATION:10 #EXT-X-ALLOW-CACHE:YES #EXT-X-PLAYLIST-TYPE:VOD #EXT-X-KEY:METHOD=AES-128,URI="encryption.key" #EXT-X-VERSION:3 #EXT-X-MEDIA-SEQUENCE:1 #EXTINF:2.000, seg-1-v1-a1.ts #EXTINF:2.000, seg-2-v1-a1.ts ... ... seg-11-v1-a1.ts #EXTINF:6.703, seg-12-v1-a1.ts #EXT-X-ENDLIST
Step 2: Create HTTP Sampler in JMeter for the playlist URL
Now, we start our script by adding a thread group and an HTTP request sampler to our test plan in JMeter:
Let’s call this HTTP Request as “Playlist”. In this playlist, enter the server name and path as shown:
Step 3: Extract Segment list using Regular Expression Extractor
Now, we add a Regular Expression Extractor as the child of Playlist (Add -> Post Processor -> Regular Expression Extractor) and name it “StreamList”. This Regular Expression Extractor will extract the provided pattern and store it in an array variable which will be named under “Reference name” as shown below. We will name it “streams”:
Step 4: Loop over the extracted array
In Step 3, we extracted the playlist in the array named “streams”, next we need to add a ForEach Controller, which will loop through “streams” variable. Let’s name the controller as streamLoop.
The Input variable name will be your variable name in Step 3 (“streams” in our case). The values will be fetched one by one in the output variable. Let’s call the output variable as “chunks”:
Step 5: Add another HTTP Request Sampler for TS chunks
Add another HTTP Request sampler as the child of ForEach Controller created in Step 4 so that we can loop through all the video chunks extracted from the playlist.
Enter the server name same as in previous HTTP sampler. In the Path, replace “index.m3u8” (present at the end of the URL) by the variable value ${chunks} as shown in the below image:
And that’s it. You can add the “View Results Tree” listener to verify the requests being sent by JMeter. You will be able to see output like this in the result tree if everything is setup correctly:
References:
https://en.wikipedia.org/wiki/Streaming_media
https://www.blazemeter.com/blog/how-load-test-http-live-media-streaming-hls-jmeter
https://support.jwplayer.com/customer/portal/articles/1430349-about-rtmp-streaming
When we hit the child m3u8 request then it will fetch the initial generated ts files only. But in case of live streaming we will get more ts files as user see the video or audio. How we can wait for them as response of single request of child m3u8 URL?
Hi How did you converted the url- curl “http://xxx.yyy.com/p/1982551/sp/198255100/0_cejlz2mj/format/applehttp/protocol/http/f/a.m3u8
to
“http://xxx.yyy.com/enc/1982551/sp/198255100/0_cejlz2mj/flavorId/0_hjddwmny/name/a.mp4/index.m3u8
tried a lot of ways but cannot use the ts in there
Thanks for pointing this out Arjun.
Actually the first curl command provides output like this:
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=98304,RESOLUTION=128×72
http://xxx.yyy.com/enc/1982551/sp/198255100/0_cejlz2mj/flavorId/0_jk3oc9go/name/a.mp4/index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=333824,RESOLUTION=640×360
http://xxx.yyy.com/enc/1982551/sp/198255100/0_cejlz2mj/flavorId/0_n4gq71zx/name/a.mp4/index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=479232,RESOLUTION=640×360
http://xxx.yyy.com/enc/1982551/sp/198255100/0_cejlz2mj/flavorId/0_c2g5i5vf/name/a.mp4/index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=680960,RESOLUTION=640×360
http://xxx.yyy.com/enc/1982551/sp/198255100/0_cejlz2mj/flavorId/0_hjddwmny/name/a.mp4/index.m3u8
Hence the new URL.
Looks like I missed the output. I will make changes in the post accordingly.
Hi Thanks for your quick reply. and thanks for adding the output. I understood the scenario in your test.
But, in my case there is no sub files of video with different resolution
Its live streaming with a single m3u8 file. So I did only one for each loop.
its like
Thread group
Playlist
streams(Regx)
stream_loop(for each loop)
stream(http req)
But In my results tree, I am not getting the result of stream(http req).
In result tree, only playlist(http req) results are displayed. Can you please help
Did you manage to get this working? My output does not give me a result with another URL, i just get the result e.g.:
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=98304,RESOLUTION=128×72
Not sure why it’s like that, but you need to analyze the output from network tab under developers tools in your browser and see what all the requests your browser is sending.