204 lines
5.4 KiB
Markdown
204 lines
5.4 KiB
Markdown
+++
|
|
categories = ["software"]
|
|
tags = ["docker"]
|
|
date = 2024-04-18T17:00:33Z
|
|
description = ""
|
|
draft = false
|
|
slug = "ipcam-timelapse"
|
|
title = "📹 IP Camera Time-lapse in Frigate"
|
|
author = "nicholas"
|
|
+++
|
|
|
|
I have a container running `Frigate`, which captures and republishes a feed from my security camera overlooking the area beyond my deck. I will periodically capture a frame from this stream for some time, and compile the frames into time-lapses using `ffmpeg`
|
|
|
|
{{< image
|
|
src="images/ip-cam-mounted.JPG"
|
|
caption="IP camera mounted" >}}
|
|
|
|
{{< image
|
|
src="images/ip-cam-view.JPG"
|
|
caption="IP camera view of deck overlooking the neighborhood" >}}
|
|
|
|
## Docker Container - Frigate
|
|
As I mention above, I am already using `Frigate` to manage my IP camera stream for things like object detection, recording, and other such functions that are common in video management systems. The software lacks built-in features relating to time-lapses, but this is easily implemented through other means.
|
|
## Docker Compose
|
|
First, I include here the basic `docker-compose.yml` file that I use to get a `Frigate` container up and running. Not a lot of software configuration is defined here, this will mostly be done later in the frigate configuration file.
|
|
|
|
```yaml
|
|
services:
|
|
frigate:
|
|
container_name: frigate
|
|
privileged: true
|
|
restart: unless-stopped
|
|
image: ghcr.io/blakeblackshear/frigate:stable
|
|
shm_size: "512mb"
|
|
devices:
|
|
- /dev/dri/renderD128 # for intel hwaccel
|
|
volumes:
|
|
- /etc/localtime:/etc/localtime:ro
|
|
- ${HOST_PATH_CONFIG}:/config
|
|
- ${HOST_PATH_MEDIA}:/media/frigate
|
|
- type: tmpfs # Optional: 1GB of memory, reduces SSD/SD Card wear
|
|
target: /tmp/cache
|
|
tmpfs:
|
|
size: 1000000000
|
|
ports:
|
|
- "${PORT}:5000"
|
|
- "8554:8554" # RTSP feeds
|
|
- "8555:8555/tcp" # WebRTC over tcp
|
|
- "8555:8555/udp" # WebRTC over udp
|
|
environment:
|
|
- FRIGATE_CAMERA_USER=${FRIGATE_CAMERA_USER}
|
|
- FRIGATE_CAMERA_PASSWORD=${FRIGATE_CAMERA_PASSWORD}
|
|
```
|
|
|
|
```
|
|
PORT=<port number>
|
|
HOST_PATH_CONFIG=<host path for config>
|
|
HOST_PATH_MEDIA=<host path for media>
|
|
```
|
|
|
|
This is my frigate configuration file config.yml. In this configuration, I am not recording or capturing snapshots of anything, which are major features of frigate. Instead I am using frigate to monitor the feed in real time and to periodically grab frames from the stream it publishes. In other words, it is superfluous to use frigate for the purpose of capturing frames. One could go straight to the source RTSP stream and circumvent the re-stream. But I do this anyway because sometimes I like to capture videos of squirrels and birds using frigate's object detection.
|
|
|
|
```yaml
|
|
ui:
|
|
live_mode: mse
|
|
|
|
mqtt:
|
|
enabled: false
|
|
|
|
go2rtc:
|
|
streams:
|
|
deck:
|
|
- rtsp://{FRIGATE_CAMERA_USER}:{FRIGATE_CAMERA_PASSWORD}@192.168.1.200:554//h265Preview_01_main
|
|
|
|
birdseye:
|
|
enabled: false
|
|
mode: continuous
|
|
|
|
cameras:
|
|
deck: # <------ Name the camera
|
|
objects:
|
|
track:
|
|
- person
|
|
- animal
|
|
ffmpeg:
|
|
inputs:
|
|
- path: rtsp://127.0.0.1:8554/deck
|
|
roles:
|
|
- record
|
|
- detect
|
|
hwaccel_args: preset-vaapi
|
|
input_args: -tag:v hvc1
|
|
output_args:
|
|
record: preset-record-generic-audio-copy
|
|
|
|
record:
|
|
enabled: false
|
|
events:
|
|
pre_capture: 2
|
|
post_capture: 2
|
|
objects:
|
|
- animal
|
|
|
|
snapshots: # <----- Enable snapshots
|
|
enabled: false
|
|
|
|
detect:
|
|
enabled: false
|
|
width: 3840
|
|
height: 2160
|
|
|
|
detectors:
|
|
ov:
|
|
type: openvino
|
|
device: AUTO
|
|
model:
|
|
path: /openvino-model/ssdlite_mobilenet_v2.xml
|
|
|
|
model:
|
|
width: 300
|
|
height: 300
|
|
input_tensor: nhwc
|
|
input_pixel_format: bgr
|
|
labelmap_path: /openvino-model/coco_91cl_bkgr.txt
|
|
labelmap:
|
|
15: animal
|
|
16: animal
|
|
17: animal
|
|
```
|
|
|
|
|
|
|
|
```shell
|
|
sudo docker compose up -d
|
|
```
|
|
|
|
|
|
|
|
# Time-lapse Parameters
|
|
|
|
The goal is to compress a month (30 days) of time into a minute.
|
|
|
|
|
|
## Clip Duration
|
|
|
|
The view from my deck is not so exciting, so I do not want time-lapse clip to last too long. I settled on 1 minute.
|
|
|
|
|
|
## Frame rate
|
|
|
|
I want the video to be very smooth, so I chose 60 frames per second. This should be plenty. I can change my mind when I generate a video using ffmpeg's -framerate {framerate} option because I am storing each individual frame as a .png file.
|
|
|
|
|
|
## Interval
|
|
|
|
The interval follows from the frame rate and clip duration. The interval is a function of clip duration and frame rate.
|
|
|
|
The relationship between these variables can be expressed:
|
|
|
|
duration = frames * framerate
|
|
interval = duration / framerate
|
|
|
|
|
|
|
|
# Capturing Frames from Frigate
|
|
|
|
```sh
|
|
#!/bin/sh
|
|
|
|
time=`date '+%Y_%m_%d__%H_%M_%S'`;
|
|
|
|
StorageFileName=$time.png
|
|
|
|
/usr/bin/ffmpeg -rtsp_transport tcp -i rtsp://<username>:<password>@<IP address>/Preview_<channel number>_<stream type> -ss 1 -frames:v 1 -update 1 <path>/$StorageFileName
|
|
```
|
|
|
|
Here we use ffmpeg to capture the frames and store them as png files according to the time it was captured. This script runs every 12 minutes via cron:
|
|
|
|
|
|
```sh
|
|
crontab -e
|
|
*/12 * * * * <path_to_timelapse.sh>
|
|
```
|
|
|
|
This is the command I use to generate a video.
|
|
|
|
|
|
```shell
|
|
ffmpeg -framerate 60 -pattern_type glob -i '*.png' -c:v libx265 -crf 28 -preset ultrafast -s 2k 28_ultrafast.mp4
|
|
```
|
|
{{< image
|
|
src="images/timelapse.gif"
|
|
caption="Timelapse" >}}
|
|
|
|
{{< video
|
|
src="videos/timelapse-multiday.mp4"
|
|
width="100%" >}}
|
|
|
|
{{< video
|
|
src="videos/timelapse-deck-planter.mp4"
|
|
width="100%" >}}
|
|
|
|
|
|
ReoLink RLC-810WA |