videodb

package
v0.0.0-...-b7e086b Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 26, 2024 License: MIT Imports: 13 Imported by: 0

README

Video DB

This is my 2nd attempt at creating the recording database.

The 1st attempt was centered around the idea that there wouldn't be many recordings, and with an emphasis on labeling.

Here I'm focusing first on continuous recording. We need to be efficient when there are hundreds of hours of footage. The user must be able to scan through this footage easily, and we don't want to lose any frames.

Video Archive

All the video footage is stored inside our 'fsv' format archive. Initially, we'll just be supporting our own 'rf1' video format, but we could conceivably support more mainstream formats such as mp4, if that turns out to be useful.

The primary reason for using rf1 is that it is designed to withstand a system crash, and still retain all the video data that was successfully written to disk. The second reason is efficiency. 'rf1' files are extremely simple - we're just copying the raw NALUs to disk.

Database Design

The event table is fat. The objects field is a JSON object that contains up to 5 minutes of object box movement, or 10KB of data, whichever limit comes first.

The event_summary table is lean, and used to draw the colored timeline of a camera, where the colors allow the user to quickly tell which parts of the video had interesting detections.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Migrations

func Migrations(log log.Log) []migration.Migrator

Types

type BaseModel

type BaseModel struct {
	ID int64 `gorm:"primaryKey" json:"id"`
}

BaseModel is our base class for a GORM model. The default GORM Model uses int, but we prefer int64

type Event

type Event struct {
	BaseModel
	Time       dbh.IntTime                         `json:"time"`       // Start of event
	Duration   int32                               `json:"duration"`   // Duration of event in milliseconds
	Camera     string                              `json:"camera"`     // LongLived camera name
	Detections *dbh.JSONField[EventDetectionsJSON] `json:"detections"` // Objects detected in the event
}

An event is one or more frames of motion or object detection. For efficiency sake, we limit events in the database to 5 seconds.

type EventDetectionsJSON

type EventDetectionsJSON struct {
	Objects []*ObjectJSON `json:"objects"` // Objects detected in the event
}

type EventSummary

type EventSummary struct {
	BaseModel
	Camera  string      `json:"camera"`  // LongLived camera name
	Time    dbh.IntTime `json:"time"`    // Start time of event segment
	Classes string      `json:"classes"` // Comma-separated list of classes that were detected
}

An EventSummary record is stored for every 5 minute segment, in order to quickly produce a zoomed-out view of activity within a day, week, or month. If this record takes 40 bytes, and we have 288 5-minute segments in a day, then we use 11.5KB per camera per day. Per month, that is 345KB. During transmission (over the web), we can compress this down significantly, by sending only the "classes" list as a dense array, which would bring this information down by a factor of 10 or more. If the classes were single-digit integers, then we'd have 1 byte for every day separator, and let's say 3 'classes' bytes per segment, for 4 bytes total per segment. 4 * 288 = 1.15KB per day, or 34.5KB per month (per camera). This would compress very well, so we're probably looking at about 300 bytes per day, or 10KB per month, per camera.

type ObjectJSON

type ObjectJSON struct {
	ID        int64                `json:"id"`       // Can be used to track objects across Events
	Class     string               `json:"class"`    // eg "person", "car"
	Positions []ObjectPositionJSON `json:"position"` // Object positions throughout event
}

An object detected by the camera.

type ObjectPositionJSON

type ObjectPositionJSON struct {
	Box  [4]int16 `json:"box"`  // [X1,Y1,X2,Y2]
	Time int32    `json:"time"` // Time in milliseconds relative to start of event.
}

Position of an object in a frame.

type TrackedBox

type TrackedBox struct {
	Time time.Time
	Box  nn.Rect
}

type TrackedObject

type TrackedObject struct {
	ID     int64
	Camera string
	Class  string
	Boxes  []TrackedBox
}

type VideoDB

type VideoDB struct {
	// Root directory
	// root/fsv/...         Video file archive
	// root/videos.sqlite   Our SQLite DB
	Root string

	Archive *fsv.Archive
	// contains filtered or unexported fields
}

VideoDB manages recordings

func NewVideoDB

func NewVideoDB(logs log.Log, root string) (*VideoDB, error)

Open or create a video DB

func (*VideoDB) Close

func (v *VideoDB) Close()

func (*VideoDB) ObjectDetected

func (v *VideoDB) ObjectDetected(camera string, id int64, box nn.Rect, class string)

func (*VideoDB) SetMaxArchiveSize

func (v *VideoDB) SetMaxArchiveSize(maxSize int64)

The archive won't delete any files until this is called, because it doesn't know yet what the size limit is.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL