Files
web-log/container/site/content/posts/ipcam-timelapse/index.md
T
2025-07-05 15:36:34 +00:00

5.4 KiB

+++ 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.

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.

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
    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

#!/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:

    crontab -e
    */12 * * * * <path_to_timelapse.sh>

This is the command I use to generate a video.

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