How to build a video transcoder with SpringBoot and FFMPEG!

giboow

GiBoOw

Posted on October 13, 2021

How to build a video transcoder with SpringBoot and FFMPEG!

I recently started working on a surveillance camera system and I want to be able to display the collected videos on web pages.
At first glance, it seemed very easy, but I quickly realized that I would have to rack my brains!

How it should work?

The camera is connected to an NVR (Numeric Video recorder) which has an API that allows to retrieve the configuration information and the video stream. By searching a little on the Web (Yes the documentation is difficult to access..), I discover that the communication protocol used by the NVR is RTSP (Real-Time Streaming Protocol). This is where I encounter the main problem! How to use this protocol in an HTML page that does not support it? My solution is to use a server that allows to transcode the video in a more known format (MP4) and an ultra standard protocol (Http). This will also allow me to hide the access identifiers to the camera by using my server as a proxy.

Graph it should work

So how do we do it?

A great tool that is well known for doing video conversion is FFMPeg, so I'm starting to look into how I can use it to convert RSTP. I quickly find a command line that works:



ffmpeg -y -loglevel level+info -n -re -acodec pcm_s16le -rtsp_transport tcp -i rtsp://user:passwd@192.168.1.200:554/ISAPI/Streaming/channels/101/live -vcodec copy -af asetrate=22050 -acodec aac -b:a 96k -nostdin myvideo.mp4


Enter fullscreen mode Exit fullscreen mode

Then how to make a proxy with SpringBoot? It's very simple actually, you just have to use the StreamingResponseBody object. This allows to return an asynchronous request processing, where the application can write directly to the response output stream without blocking the rest of my API.

Finally, I just have to use FFMPEG in my controller to send the stream via my API. I could have used " Runtime.getRuntime().exec(" ffmpeg...) " but I couldn't figure out how to get my stream. Fortunately I found a magic library Jaffree : "Jaffree stands for JAva FFmpeg and FFprobe FREE command line wrapper. Jaffree supports programmatic video production and consumption (with transparency)"

The solution

Here is the final solution and how to relay a video stream from a HikVision camera so that the format is usable by an HTML page.



import com.github.kokorin.jaffree.StreamType;
import com.github.kokorin.jaffree.ffmpeg.FFmpeg;
import com.github.kokorin.jaffree.ffmpeg.PipeOutput;

@RestController
@RequestMapping("/video")
@Log4j2
public class VideoController {
    @GetMapping(value = "/live.mp4")
    @ResponseBody
    public ResponseEntity<StreamingResponseBody> livestream(@PathVariable("id") Long tipperId) throws Exception {

        String rtspUrl = "rtsp://user:passwd@192.168.1.200:554/ISAPI/Streaming/channels/101/live";

        return ResponseEntity.ok()
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                .body(os -> {
                    FFmpeg.atPath()
                            .addArgument("-re")
                            .addArguments("-acodec", "pcm_s16le")
                            .addArguments("-rtsp_transport", "tcp")
                            .addArguments("-i", rtspUrl)
                            .addArguments("-vcodec", "copy")
                            .addArguments("-af", "asetrate=22050")
                            .addArguments("-acodec", "aac")
                            .addArguments("-b:a", "96k" )
                            .addOutput(PipeOutput.pumpTo(os)
                                    .disableStream(StreamType.AUDIO)
                                    .disableStream(StreamType.SUBTITLE)
                                    .disableStream(StreamType.DATA)
                                    .setFrameCount(StreamType.VIDEO, 100L)
                                     //1 frame every 10 seconds
                                    .setFrameRate(0.1)
                                    .setDuration(1, TimeUnit.HOURS)
                                    .setFormat("ismv"))
                            .addArgument("-nostdin")
                            .execute();
                });

    }
}


Enter fullscreen mode Exit fullscreen mode

You will also have to modify the configuration of your SpringBoot application (application.properties file) to increase the timeout for asynchronous requests.



spring.mvc.async.request-timeout = 3600000


Enter fullscreen mode Exit fullscreen mode

You just have to call your API on the web page:



<div class="video">
  <video width="100%" height="auto" controls autoplay muted loop *ngIf="event?.video">
    <source src="http://localhost:8080/video/live.mp4"
            type="video/mp4">
    Sorry, your browser doesn't support embedded videos.
  </video>
</div>


Enter fullscreen mode Exit fullscreen mode

And see the result :

Final result

That's it!

Find the article in French on my personal website

💖 💪 🙅 🚩
giboow
GiBoOw

Posted on October 13, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related