REST chunked video streaming with Jersey2


In this tutorial we demonstrate simple chunked MP4 video streaming using a RESTful web service with Jersey2, Tomcat and Maven. We use the Range (with bytes=X..Y) parameter to send or buffer the video in chunks. Therefore, less bandwidth is required if the client requests smaller part of the video. Stepping forward or backward throughout the video is supported. The required Maven project is available on Github.

1. Prerequisites

  1. Install Apache Tomcat (we use version 8.5). If not already installed, please have a look at these 2 tutorials:
  2. Install Apache Maven to build the project
  3. You can just run a “clean install” on the Maven project and deploy the created WAR file to Tomcat directly. Although we recommend to work with an IDE like EclipseEE or IntelliJ to adapt or debug the project
  4. If you import the Maven project to EclipseEE, activate and adapt the Project Facets to use the Dynamic Web Project 3.1, Java 1.8 and JAX-RS 2.0

2. Code step-by-step

This tutorial is based on the Git Repository of Arul Dhesiaseelan, demonstrating video streaming with Jersey. We created a project around it, made some adaptations and provide a client JQuery UI with a media player.

2.1 Dependencies in pom.xml

We use the following dependencies in the pom.xml. Versions are 2.25 for Jersey and 2.5 for the Apache Commons IO.

2.2. Adaptations in web.xml

The servlet entry pattern is /rest/*. We provide an index.html file with a media player at root level to stream the video later on. Furthermore, we use a WriterInteceptor to avoid ClientAbortExceptions. These occur whenever the client closes the connection before the server is able to send all the requested data in the response (which happens quite a lot).

2.3 The REST web service

The web service provides two entry points at “/stream”. The first one is a HEAD request, which some media players use to determine whether ranged/chunked streaming is supported. The response consists of the PARTIAL_CONTENT (206) HTTP status code, the actual content length of the video as well as the accepted format “Accept-Ranges”. A typical client range requests looks like this: “bytes=0-1048576” for the first MB or “bytes=1048577-2097152” for the second MB. Furthermore meta data is requested from the start and the end of the video.

The second entry points provides the streaming functionality and is a GET request. The logic is contained the buildStream method with the video file and the GET range parameter. If there is no range specified (range == null), the full video content is send at once.

Many video players work with the range parameter but request basically the full content length. Since we want to focus on chunked streaming, we only process the “from” range (and ignore the “to” range).

Finally we create our response range (“Content-Range”) which looks like this: “bytes 0-2097152/31551484” to inform the client which part of the data is transmitted. The number behind the slash indicates the full video length in bytes. In the example code we use 2 MB chunks which should be increased in production to avoid endless requests.

2.4 MediaStreamer class

We use a helper class from Arul Dhesiaseelan (in the Git repository above) to write to an output stream.

2.5 JQuery client

The JQuery mkh player is utilized to display the video. The index.html only contains a logo and the media player.

3. Run the streaming example

In order to build the example code, execute “mvn clean install” to build the war file. Then you can deploy it directly in the Tomcat Webapps folder or use EclipseEE. The resources folder contains an example video.

With the default settings in Tomcat (Port 8080) you can reach the project root (and the index.html) at: http://localhost:8080/jersey2-resume-video-streaming/

The REST streaming web service is located at: http://localhost:8080/jersey2-resume-video-streaming/rest/stream

Running Eclipse, the internal browser will open and should display something like this:

Streaming in eclipse

Calling the address in a browser like Chrome we see the following output:


Now you can play or step through the video. You can have a look at the Tomcat output or the Eclipse console to check out what requests are received and which responses are returned:

The media player requests some meta information from the beginning and end. Furthermore it always requests the full content length of the video. Because we ignore the second range parameter (“to”) we continue to send only 2 MB chunks back to the client.

4. Conclusion

The video streaming is straight forward. You do not need much code to make it work. We recommend for production to use bigger chunks (10-50MB) or even switch to a real media server. Doing these kinds of things with REST is not the optimal solution. Since REST is stateless, we do not have a session. Consequently, in the example we open and close the media file on every request, which does not scale at all. There are workarounds with timers and e.g. JWTs to mimic a session and keep the file opened, but we still suggest to stream data like this via a media server.

Thanks goes out to Arul Dhesiaseelan and his provided Git Repository, on which this tutorial is heavily based on.

We tried using the network stream of the VLC media player. This works for exactly one chunk. You can step through the video, but only one chunk (2 MB in the demo case) is displayed and then started from zero again. We have to do some research to get to the bottom of that.

If you have problems or errors, feel free to comment and ask.


Leave a Reply