Load Testing HLS Stream Using JMeter

31 / Aug / 2016 by Raghu Sharma 6 comments

 001banner

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:01.DeveloperTools

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:

02.JMeter_TestPlan

Let’s call this HTTP Request as “Playlist”. In this playlist, enter the server name and path as shown:

03.playlist_HTTPSampler

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”:

04.RegExtractor

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”:

05.ForEachController

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:

06.chunks_sampler

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:

07.result

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

FOUND THIS USEFUL? SHARE IT

comments (6)

  1. Sanjay Kumar

    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?

    Reply
  2. Arjun Dev

    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

    Reply
    1. Raghu Sharma

      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.

      Reply
      1. Arjun

        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

        Reply
        1. Kamil

          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

          Reply
          1. Raghu Sharma

            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.

Leave a Reply

Your email address will not be published. Required fields are marked *