Home-ish DVR with RTSP, ffmpeg, and D-Link DCS-8526LH

Another “Today I Learned”, except I was more “doing” than learning. Back in 2024 I was happy to find that the camera I invested in to monitor my kids doing homework back in the COVID days supported RTSP. I made a note to see if I can take it a bit farther, and if it wasn’t for the fact that the DCS-8526LH was eating Micro-SD cards and I was losing valuable information I wouldn’t be where I’m at now.

Enter the “Home DVR”…

Day One

I’m already running a home Linux Server with over 30tb of storage for Plex and other mundane tasks. I decided to see if I can push that again to constantly pull an RTSP stream from the camera and save the raw data on a timely basis, much like a DVR would.

A simple script on a cron was able to give me my 10-minute slices of time:

#!/bin/bash
ROOT="/mnt/usb14/Camera"
YEAR=`date +'%Y'`
MONTH=`date +'%m'`
DAY=`date +'%d'`
FULL=`date +'%Y%m%d-%H%M%S-%s'`
mkdir -p $ROOT/$YEAR/$MONTH/$DAY 2>/dev/null
# 10 minute stream
ffmpeg -i "rtsp://admin:658047@198.162.1.248:554/live/profile.0" -t 600 -c:v copy -c:a copy "$ROOT/$YEAR/$MONTH/$DAY/$FULL.mp4"

Set some variables, make some orderly folders, and use the -t 600 parameter to record for exactly 10 minutes.

Out of the box ffmpeg comes with multiple way to scoop up whatever the input source is going to be, including RTSP with authentication params in the URL.

A simple crontab later and now I’ve got a low CPU-usage process recording on-the-10th-minute videos to an organized folder.

# Streaming local cameras - 10m segments
*/10 * * * * cd /mnt/usb14/Camera && ./rtsp-recorder 2>&1 >/dev/null

Eventually i’ll have a tmpwatch or something that’ll cull oldness or offload them to a long term storage. In the meantime this is more than I wanted, and I’m so happy I got my cheapo DVR for one camera. Next up, the ScamleySafe doorbell camera.

Day Two

Storage seemed to not be an issue at the start, but things slowly looked like they creeped up. Day two created about 13GB of raw video. I decided two things at this point

  1. Munge all the videos together and make one file
  2. See if I can compress it all down

Wrote a quick script that I kindly called “make-the-day”

#!/bin/bash
ROOT="/mnt/usb14/Camera"

if [ "$1" == "" ]; then
  YEAR=`date -d'yesterday' +'%Y'`
  MONTH=`date -d'yesterday' +'%m'`
  DAY=`date -d'yesterday' +'%d'`
else
  if [ "$2" == "" ]; then
    echo "need 2nd parameter as month"
    exit;
  fi
  if [ "$3" == "" ]; then
    echo "need 3rd parameter as day"
    exit;
  fi
    YEAR=$1
    MONTH=$2
    DAY=$3
fi

if [ ! -d $ROOT/$YEAR/$MONTH/$DAY ]; then
  echo "folder $ROOT/$YEAR/$MONTH/$DAY does not exist"
  exit
fi

find $ROOT/$YEAR/$MONTH/$DAY -type f -name '*.mp4' | sort > files
for LINE in `cat files`; do
  echo "file '$LINE'" >> concat.txt
done;
rm files

if [ ! -e concat.txt ]; then
  echo "concat file not made"
  exit
fi

# make our one file for the day
ffmpeg -f concat -safe 0 -i concat.txt -c copy $ROOT/$YEAR/$MONTH/"$YEAR""$MONTH""$DAY".mp4
rm concat.txt

# Compress it down to whatever default x265 is. ~65% original size
if [ -e $ROOT/$YEAR/$MONTH/"$YEAR""$MONTH""$DAY".mp4 ]; then
  ffmpeg -i $ROOT/$YEAR/$MONTH/"$YEAR""$MONTH""$DAY".mp4 -c:v libx265 -c:a copy $ROOT/$YEAR/$MONTH/"$YEAR""$MONTH""$DAY".x265.mp4
fi

if [ -e $ROOT/$YEAR/$MONTH/"$YEAR""$MONTH""$DAY".x265.mp4 ]; then
  rm $ROOT/$YEAR/$MONTH/"$YEAR""$MONTH""$DAY".mp4
fi

TL;DR concatenate all the videos into one large one, then convert it to x265. If all was successful, then we clean up, otherwise leave all the junk everywhere and back to the drawing board.

I forced this script a bit after noonish everyday.

12 12 * * * cd /mnt/usb14/Camera && ./make-the-day 2>&1 >/dev/null

Leave a Reply