in Development, Home Automation, Infrastructure, Networking, Scripting

Extracting a Full Day’s Video from UniFi NVR

There are plenty of people looking to extract full-length video from their UniFi Protect instances, either for archival purposes, or (as in my case) to create full and multi-day timelapse videos. The iOS app and the web app both allow limited download of video, but the interface to define your clips is clumsy at best, crashy at worst, and in my experience extracting an entire day seems to fail more often than it succeeds. Given these limitations, I went looking for a more robust way to dump video from the devices – read on for my findings.

I run the UniFi Network Video Recorder, but I suspect these steps apply to the Pro and possibly to other related devices that run the Protect software.

As with all things unsupported by Ubiquiti, we start with SSH. You’ll need to get the SSH password (which you can reset in Settings Advanced) and log on to the devices as root.

Video is stored in /srv/unifi-protect/video in subdirectories by YYYY/MM/DD/ with .ubv files named by the camera’s MAC address.

Some parts of that filename are self-evident, others I’ve taken a best guess:

MAC address    [rotating|timelapse]
| |
B4FBE47EEF30_0_rotating_1642378105047.ubv
| |
Quality Start time in unix epoch time

On my system, the number I’ve labelled quality seems to represents either the highest quality feed (0) or a lower quality (2) about half the resolution – maybe for scrubbing in the phone apps?

I’ve seen just two values so far in the third position: rotating and timelapse. Files with rotating are part of the standard recordings that get purged based on time/disk space, while the timelapse ones seem to be ones created by the system when generating exports in the UI.

Knowing where the files are, we now need to get them off the NVR, or at least get them accessible from another machine.

First, I enabled Samba on the NVR and shared the /srv/unifi-protect/video directory. I did this an incredibly lazy way by enabling a guest user to see the directory. Please adjust settings according to your own risk profile.

Changes to my /etc/samba/smb.conf

Under [global]

map to guest = Bad User

And then create this block at the bottom:

[video]
  path = /srv/unifi-protect/video
  browsable = yes
  guest ok = yes

And restart samba:

sudo systemctl restart smbd.service nmbd.service

You’ll be able to see the files from across the network:

Sadly, this doesn’t help, because as far as I can tell nothing outside of an NVR knows how to process the .ubv file.
(At least neither ffprobe and VLC could do anything with it.)

So with that dead end reached, I tried the next obvious thing: the NVR itself must have a way to convert .ubv to .mp4, since the UI and the iOS apps do it when you export clips. And knowing how Ubiquiti build their systems, it’s almost certainly a separate component called by the main service.

Running ps -aux shows the list of processes on the NVR, one of which is:

/usr/share/unifi-protect/app/node_modules/.bin/ubnt_avcodec_service

A quick search of the directory containing that binary shows a few other likely targets:

That ubnt_ubvexport binary looks promising, let’s see what it can tell us:

Result! Exactly what we need – it’ll even take multiple inputs and stitch them into a single .mp4.

Rather than write the .mp4 back to the NVR, I want to have the NVR push the files across to another machine on my network, so let’s install smbclient and connect.

First, install:

sudo apt install smbclient

Create a directory to mount the share on:

sudo mkdir /mnt/video

Then mount a share on another (in my case, Windows) PC. Replace the username, server, share and (if you didn’t copy me) the mount point:

sudo mount.cifs -o sec=ntlmssp,username=USERNAME //PC_NAME/SHARE /mnt/video

And finally, choose a file to test:

cd /srv/unifi-protect/video

Within that directory, find a file to export, and within the same directory, run:

/usr/share/unifi-protect/app/node_modules/.bin/ubnt_ubvexport -s MACADDRESS_0_rotating_1642402659065.ubv -d /mnt/video/PREFIX

Change PREFIX to set the prefix for the filename(s) generated in the output.

We can pass multiple -s arguments to have the files combined into a single .mp4, so to get the list of files within a directory for a single day:

for i in ls MACADDRESS_0*; do echo -n "-s $i "; done

You can find the MAC address of your cameras by checking in the UI under camera settings. The 0 for me means I get the higher quality stream, your mileage may vary.

The output of that command will be a list of arguments you can copy and paste into the command from before:

/usr/share/unifi-protect/app/node_modules/.bin/ubnt_ubvexport [big long list of -s arguments] -d /mnt/video/ubnt/PREFIX

That’ll take a little while, and then spit out a few massive files – in my case, between two and four files in high quality, plus another two in the lower quality. You get roughly 12 hours of the day in each of the main files at about 12GB each.

My next step is to take those files and sample a few frames per minute to create a timelapse. My experiments with ffmpeg have proven quite slow, so I’m looking for a faster way to do this. Pointers welcome!