I made a simple, cheap NVR with BASH and FFMPEG
Introduction
I started studying IP cameras and surveillance as a survival skill a few years ago. My family has some nice homes that we want to protect. The houses are far apart from each other. I also wanted to see the different environments and climates so that I could get that feeling of being there. Why not take a look at the beach while you are stuck in the gloomy capital city? To tie all this together I decided to design my own NVR.
NVR stands for Network Video Recorder. It is a system that has one basic function. Of course, It records video from network-enabled cameras which it has access to. Next, it should also receive motion events from those cameras that have motion detection capability. As I wrote previously in my post on my open source work, the ONVIF standard ensures an easy way to access such services on the camera.
FFMPEG and Linux Bash
At the time I had already started exploring the Raspberry PI single-board-computer. It is a perfect platform for such a system. My own Rapsberry Pi 4Bs run Ubuntu Server. Obviously, I need a library to do the actual recording and transformation of the video. FFMPEG is the most used and celebrated video recording library in existence. The bash scripting language would be the glue that ties all of this together. Finally, in order to guarantee durability and proper scheduling, I used systemd.
The elegance of FFMPEG is that it provides enconding and connection capabilities. In fact, the broad range of features guarantees that it can cover all your video needs. If you do not wish to use the command-line, there are multiple frontends and interfaces written for it.
A watchdog to help me record
The diagram above shows the calling order. Crontab scheduling was used to reset the service once per day to help with stability. The service was responsible for keeping the connection with the camera open and restarting in case of server reboot. FFMPEG has a nasty bug. It does not return a proper exit code if a connection with a camera hangs. As a result, I was forced to implement a watchdog service. The watchdog concept in systemd is a tool for monitoring processes that do not report their own failure reliably. In this case, a watchdog script would check if the video files was growing as expected and restart accordingly.
There was quite a bit of fidling to get the watchdog script right. The trick is in identifing the proper process id which spawns the video file. There are some nested processes in a running systemd service with each their own PID. After some trial and error I was able to guess the order. You can find an example in the repository listed in the final paragraph below. I cannot guarantee it will work for you. It depends on the choices you make in writing your scripts.
Some problems to watch out for
There are several issues that I noticed during conceptualization and later in production. One is preserving timestamps and frame synchronization in case of restarts (ex. connection failure). There are two ways for handling this. One is to use an appendable video format like TS. It is not compact and will impact your storage. Another is to record in very small chunks. For example, make a new video file every minute or 30 seconds. Both of these choices require post-processing to produce a smooth single file video and preserve storage capacity. In the first case, I need to remux the file to a format with better compression. In the second case, I need to concatenate the small chunks into one usable video.
I have tried both implementations on various locations. The first was easier to implement. It meant that at the end of the day, the server load was increased as the remux operations ran. The second case included a lot more scripting. However, it proved a good solution for remote locations with limited storage. I could upload the small chunks to a remote backup location and do post-processing there. Concatenation as such is not a resource intensive operation.
To conclude, my system is still in operation and has helped ensure the safety of my home(s) on multiple occurrences. I have presented a previous version of the system during a tech talk last year. You can find the link to the presentation here. There is also a GitHub repository with sample scripts to help you get started. I hope this was an interesting read for you. Until next time, stay safe!
Related Posts:
Filed under: home-automation,open-source,raspberry-pi - @ 2023-01-05 16:00
Tags: bash, ffmpeg, linux, raspberry-pi, systemd, ubuntu, watchdog