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.
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
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();
});
}
}
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
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>
And see the result :
That's it!
Top comments (7)
Hi, i am a kind of noobie for spring boot. When i try to add Request param in this livestream() method it throws the error. I couldn't find out what i did wrong.
here I upload the image of my changes. Someone help me to solve this issue, Thank you..
dev-to-uploads.s3.amazonaws.com/up...
dev-to-uploads.s3.amazonaws.com/up...
Hi @mathivanan1803 have you tried to play your RTSP stream with VLC?
In your error log, I see that the RTSP stream is not recognized by FFMpeg.
Hello, GiBoOw. I found the solution, the error was some unwanted strings are added in the RTSP URL.
I have another question, when i try to run this code in my client machine it throws 401 unauthorized. Even i give the user name and password in the RTSP link it didn't work.
i cant find out what i did wrong, could you help me with this.
Thank you..
On my NVR (Hikvision), I have to change the security configuration...
The RTSP auth option must be set to "digest", "basic/digest" is not working
Thanks for the reply @giboow , actually I can't check the configuration of camera , it on client side.. anyway I will try this solution.
Once again thanks for the solution.
Hey GiBoOw Can I use this example to capture rtsp stream? I want to take a photo from rtsp stream.
You can probably change ffmpeg params and use "-vframes 1"