id = "dvr-scan"
name = "DVR-Scan"
homepage = "https://github.com/Breakthrough/DVR-Scan"
description = "An open-source motion detection program for video files."
executables = ["dvr-scan"]
[dotfiles]
paths = [
"~/.config/DVR-Scan/dvr-scan.cfg",
"[configHome]/dvr-scan.cfg",
"~/Library/Preferences/DVR-Scan/dvr-scan.cfg",
"%LOCALAPPDATA%/DVR-Scan/dvr-scan.cfg",
]
secret = []
[commands]
format = 1
label = "Detect motion in video"
description = "Scan one or more videos for motion events and save them. Regions, overlays, config files and time-range options are mostly left out."
quality = "ai-draft"
parser = { end_of_options = "--", interleave = "permute", long_equals = true, short_attached = false, short_bundles = false }
[[commands.source]]
id = "docs"
kind = "manual"
url = "https://www.dvr-scan.com/docs/"
revision = "2026-10-27"
evidence = """
* -i video.mp4, --input video.mp4
* -d path, --output-dir path
* -m mode, --output-mode mode (opencv, encode, ffmpeg, copy)
* -so, --scan-only
* -t value, --threshold value
* -l time, --min-event-length time
* -tb time, --time-before-event time
* -tp time, --time-post-event time
* -st time, --start-time time
* -et time, --end-time time
* -df factor, --downscale-factor factor
* -fs num_frames, --frame-skip num_frames
* -b type, --bg-subtractor type (MOG2, CNT, MOG2_CUDA)
* -bb, --bounding-box
* -tc, --time-code
* -q, --quiet
* --report file
"""
[[commands.field]]
id = "input"
label = "Input video"
description = "Repeat to scan several videos (not supported with the ffmpeg and copy output modes)."
type = "path"
option = ["--input", "-i"]
multiple = true
path = { kind = "file", role = "input", must_exist = true }
sources = ["docs"]
[[commands.field]]
id = "output_dir"
label = "Output directory"
description = "Defaults to the working directory."
type = "path"
option = ["--output-dir", "-d"]
path = { kind = "directory", role = "output", must_exist = false }
sources = ["docs"]
[[commands.field]]
id = "output_mode"
label = "Output mode"
type = "enum"
option = ["--output-mode", "-m"]
choices = [{ value = "encode", label = "Encode (MP4, H.264)" }, { value = "opencv", label = "OpenCV (AVI)" }, { value = "ffmpeg", label = "ffmpeg" }, { value = "copy", label = "Copy streams" }]
sources = ["docs"]
[[commands.field]]
id = "scan_only"
label = "Scan only"
description = "Detect and list events without saving video."
type = "boolean"
option = ["--scan-only", "-so"]
sources = ["docs"]
[[commands.field]]
id = "threshold"
label = "Threshold"
description = "Lower values are more sensitive to motion."
type = "number"
option = ["--threshold", "-t"]
sources = ["docs"]
[[commands.field]]
id = "min_event_length"
label = "Minimum event length"
type = "string"
option = ["--min-event-length", "-l"]
sources = ["docs"]
[[commands.field]]
id = "time_before"
label = "Time before event"
type = "string"
option = ["--time-before-event", "-tb"]
sources = ["docs"]
[[commands.field]]
id = "time_post"
label = "Time after event"
type = "string"
option = ["--time-post-event", "-tp"]
sources = ["docs"]
[[commands.field]]
id = "start_time"
label = "Start time"
description = "Timecode to start detection from, for example 00:35:52."
type = "string"
option = ["--start-time", "-st"]
sources = ["docs"]
[[commands.field]]
id = "end_time"
label = "End time"
type = "string"
option = ["--end-time", "-et"]
sources = ["docs"]
[[commands.field]]
id = "downscale_factor"
label = "Downscale factor"
type = "integer"
option = ["--downscale-factor", "-df"]
sources = ["docs"]
[[commands.field]]
id = "frame_skip"
label = "Frame skip"
type = "integer"
option = ["--frame-skip", "-fs"]
sources = ["docs"]
[[commands.field]]
id = "bg_subtractor"
label = "Background subtractor"
type = "enum"
option = ["--bg-subtractor", "-b"]
choices = [{ value = "MOG2", label = "MOG2" }, { value = "CNT", label = "CNT" }, { value = "MOG2_CUDA", label = "MOG2 (CUDA)" }]
sources = ["docs"]
[[commands.field]]
id = "bounding_box"
label = "Draw bounding box"
type = "boolean"
option = ["--bounding-box", "-bb"]
sources = ["docs"]
[[commands.field]]
id = "time_code"
label = "Draw time code"
type = "boolean"
option = ["--time-code", "-tc"]
sources = ["docs"]
[[commands.field]]
id = "report"
label = "Event report file"
description = "A .csv or .json file listing the detected events."
type = "path"
option = ["--report"]
path = { kind = "file", role = "output", must_exist = false }
effect = "overwrite"
sources = ["docs"]
[[commands.field]]
id = "quiet"
label = "Quiet"
type = "boolean"
option = ["--quiet", "-q"]
sources = ["docs"]
[[commands.task]]
id = "extract"
label = "Extract motion events"
fields = ["input", "output_dir", "output_mode"]
required = ["input"]
[[commands.task]]
id = "scan"
label = "Scan and report only"
fields = ["input", "scan_only", "report"]
required = ["input", "scan_only"]
set = { scan_only = [true] }
[[commands.group]]
id = "basic"
label = "Basic"
fields = ["input", "output_dir", "output_mode", "scan_only", "threshold", "report"]
[[commands.group]]
id = "advanced"
label = "Advanced"
fields = ["min_event_length", "time_before", "time_post", "start_time", "end_time", "downscale_factor", "frame_skip", "bg_subtractor", "bounding_box", "time_code", "quiet"]