PSla Blog

Blog Piotra Ślatały | Peter Slatala's Blog

Simple NVR setup for Amcrest & Reolink cameras

A while ago I purchased amcrest (this and this branded Dahua) and reolink (RLC-410) cameras. I run my own ‘server’ at home, with enough storage to actually have recording stored there.

I did not want another box (NVR) to store the recording, the server I have is more than enough.

Continuous (loop) recording

Set up loop recording with ffmpeg

First, I am going to create a dedicated user (without a password, but you can add a password to)

# useradd -m cameras
# su - cameras

Then I am going to create a directory

mkdir -p /mnt/oldnas/cameras/loop
chown -R cameras:cameras /mnt/oldnas/cameras/

Then I am going to create a script to start the recording, e.g. “/root/scripts/record-cameras.sh”:

#!/bin/bash
cd /mnt/oldnas/cameras/loop/
sudo -u motion /mnt/oldnas/cameras/record-cul-de-sac.sh &
sudo -u motion /mnt/oldnas/cameras/record-backyard.sh &
.... (repeat for each camera)

These scripts are really all the same (and could be one script with a parameter, really).

For Reolink:

#!/bin/bash
while [ true ]
do
        # future releases will rename to avconv
        ffmpeg -loglevel error -i "rtsp://user:password@10.0.11.10:554//h264Preview_01_main" -vcodec copy -acodec copy -fflags +genpts -f segment -segment_time 300 -segment_format mp4 "backyard-`date +'%Y-%m-%d_%H_%M'`-%03d.mp4" > /dev/null
        date | mail [email protected] -s "[CAMERA] Backyard"
        echo "CAMERA ERROR"
        sleep 10
done

For Amcrest change "rtsp://user:password@10.0.11.10:554//h264Preview_01_main" to rtsp://user:[email protected]/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif.

Use the appropriate username, password and IP address.

This script will

  • Continuously loop-record with each file corresponding to 5 minutes of video
  • Restart recording when the camera gets offline (after 10 second wait)
  • Send you an email (every 10 seconds) when the camera is unavailable/offline.

The 10 second retry may be excessive, so you might want to adjust it to e.g. 30 seconds. (in the sleep section)

Can I get loop recording with motion detection?

You can… You can install a fully-fledged solution like zoneminder or shinobi. Neither of those worked well for me — e.g. zoneminder always decodes a full-resolution video (even when low-resolution video is used for motion detection). I try to use H.265 (HEVC) which uses less storage, but takes more time to decode.

For this reason, I opted in for motionproject. It’s decent, but in the end it was generating too many false positives for me. (e.g. sun reflecting in the vehicle window, noise from IR as the flies are flying in front of the camera at night).

So this was my setup, but I abandoned it for the setup above + zigbee motion sensors.

For Reolink cameras, I had to use RTMP (as RTSP was causing issues). Also, recording from motion project was choppy, see details on their github. Because of that, I decided to use my own script to capture the recording when motion was detected. That is not ideal, because the recording starts exactly when motion is detected, and would not have any buffer before.

Example for Reolink:

# /usr/etc/motion/camera1.conf
#
# This config file was generated by motion 4.3.1

###########################################################
# Configuration options specific to camera 1
############################################################
# User defined name for the camera.
camera_name BackyardCamera

# Numeric identifier for the camera.
camera_id 101

# The full URL of the network camera stream.
netcam_url rtmp://10.0.11.10/bcs/channel0_sub.bcs?channel=0&stream=0&user=user&password=password

# Image width in pixels.
width 640

# Image height in pixels.
height 480

netcam_highres rtmp://10.0.11.10/bcs/channel0_main.bcs?channel=0&stream=0&user=user&password=password
movie_passthrough on

# Text to be overlayed in the lower left corner of images
#text_left CAMERA 1

# File name(without extension) for movies relative to target directory
movie_filename BACKYARD_%t-%v-%Y%m%d%H%M%S

on_event_start /mnt/oldnas/cameras/on-event-start.sh 101 "rtmp://10.0.11.10/bcs/channel0_main.bcs?channel=0&stream=0&user=motion&password=TaniaKamera"
on_event_end /mnt/oldnas/cameras/on-event-end.sh 101

A few observations:

  • Low resolution stream is used for motion detection. That stream must be enabled on the camera.
  • High resolution stream is saved on disk (netcam_highres)

on-event-start:

#!/bin/bash

set -e

# Stop previous recording
cameraid=$1
stream=$2
output=/mnt/oldnas/motion/rtmpdump
pidfile=/mnt/oldnas/motion/rtmpdump/$cameraid.pid

# || : -> ignores the error returned by kill and reports success
cat $pidfile | xargs -r kill || :

outputfilename=$output/`date +'%Y-%m-%d_%H_%M_%S'`_$cameraid.rtmp
rtmpdump -r $stream -o $outputfilename 2>/dev/null &
echo $! > $pidfile

on-event-end:

#!/bin/bash

set -e

# Stop previous recording
cameraid=$1
pidfile=/mnt/oldnas/motion/rtmpdump/$cameraid.pid

cat $pidfile | xargs -r kill
truncate -s 0 $pidfile

Cleaning up disk space

In crontab, add:

10 * * * * cd /mnt/oldnas/cameras && sudo -u cameras /mnt/oldnas/cameras/video-cleanup.sh

And the video-cleanup.sh:

#!/bin/bash

###
### This script checks available disk space
### and deletes videos sequentially, day by day, until disk space requirement is reached.
###

# 50 GB free disk space
required_free_disk_space=53530324
file_location1=/mnt/oldnas/cameras/mp4/
file_location2=/mnt/oldnas/cameras/rtmpdump

### THIS SECTION REMOVES LOOP VIDEO

find /mnt/oldnas/cameras/loop/ -type f -mtime +2 -exec rm {} \;

### THIS SECTION REMOVES MOTION-DETECTED FRAMES (using motion-project, if applicable)
days=90
while [ `df /mnt/oldnas/motion/ | tail -n1 | awk {' print $4 '}` -lt $required_free_disk_space ] && [ $days -gt 14 ]
do
        logger -t nvr "Removing videos over $days, available disk space: `df /mnt/oldnas/motion/ | tail -n1 | awk {' print $4 '}`"
        find $file_location1 -type f -mtime "+$days" -print0 | xargs -r -0 rm
        find $file_location2 -type f -mtime "+$days" -print0 | xargs -r -0 rm
        days=$((days-1))
done
logger -t nvr "Finished removal of archival videos, leaving $days days on disk"

Conclusion

For now, I actually keep running both, motion-project and my loop recording. It’s a bit inefficient in terms of storage, but makes it easier for me to find when motion happened.

Even with three cameras with motion detection enabled, my CPU utilization is on the low side:

root@usa:/etc/scripts# cat /proc/cpuinfo  | grep MHz
cpu MHz         : 800.083
cpu MHz         : 800.150
cpu MHz         : 800.040
cpu MHz         : 800.052

Which is great 🙂

Bonus points

Those cameras (both Reolink and Amcrest) try to call home all the time:

client @0x7fc2a839db90 10.0.11.19#50341 (amcrestview.com): query (cache) 'amcrestview.com/A/IN' denied
 client @0x7fc2a839db90 10.0.11.19#55489 (config.amcrestcloud.com): query (cache) 'config.amcrestcloud.com/A/IN' denied

client @0x7fc2b4418850 10.0.11.11#41502 (p2p.reolink.com): query (cache) 'p2p.reolink.com/A/IN' denied

I strongly recommend not giving them internet (or local network) access. The companies are not known for neither: providing frequent firmware updates, nor for being secure to begin with.

I put the cameras on a separate network from all my other devices, without internet access.

Leave a Reply

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