DVR-Scan-Headless 1.8.2__tar.gz → 2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dvr_scan_headless-2.0/PKG-INFO +108 -0
- {dvr_scan_headless-1.8.2 → dvr_scan_headless-2.0}/README.md +6 -6
- {dvr_scan_headless-1.8.2 → dvr_scan_headless-2.0}/dvr-scan.cfg +75 -24
- {dvr_scan_headless-1.8.2 → dvr_scan_headless-2.0}/dvr_scan/__init__.py +2 -2
- {dvr_scan_headless-1.8.2 → dvr_scan_headless-2.0}/dvr_scan/__main__.py +6 -0
- {dvr_scan_headless-1.8.2 → dvr_scan_headless-2.0}/dvr_scan/app/__main__.py +70 -3
- {dvr_scan_headless-1.8.2 → dvr_scan_headless-2.0}/dvr_scan/app/about_window.py +2 -1
- {dvr_scan_headless-1.8.2 → dvr_scan_headless-2.0}/dvr_scan/app/application.py +889 -159
- dvr_scan_headless-2.0/dvr_scan/app/common.py +143 -0
- {dvr_scan_headless-1.8.2 → dvr_scan_headless-2.0}/dvr_scan/app/region_editor.py +121 -24
- dvr_scan_headless-2.0/dvr_scan/app/scan_window.py +547 -0
- dvr_scan_headless-2.0/dvr_scan/app/startup.py +110 -0
- dvr_scan_headless-2.0/dvr_scan/app/thumbnails.py +298 -0
- dvr_scan_headless-2.0/dvr_scan/app/video_list.py +545 -0
- {dvr_scan_headless-1.8.2 → dvr_scan_headless-2.0}/dvr_scan/app/widgets.py +2 -0
- dvr_scan_headless-2.0/dvr_scan/app/wizard.py +1351 -0
- {dvr_scan_headless-1.8.2 → dvr_scan_headless-2.0}/dvr_scan/cli.py +65 -33
- {dvr_scan_headless-1.8.2 → dvr_scan_headless-2.0}/dvr_scan/config.py +287 -71
- {dvr_scan_headless-1.8.2 → dvr_scan_headless-2.0}/dvr_scan/controller.py +136 -35
- dvr_scan_headless-2.0/dvr_scan/docs/404.html +1 -0
- dvr_scan_headless-2.0/dvr_scan/docs/assets/javascripts/bundle.c21346df.min.js +15 -0
- dvr_scan_headless-2.0/dvr_scan/docs/assets/stylesheets/main.57a0d79d.min.css +6 -0
- dvr_scan_headless-2.0/dvr_scan/docs/assets/stylesheets/palette.fb2fffe2.min.css +4 -0
- dvr_scan_headless-2.0/dvr_scan/docs/changelog.html +1 -0
- dvr_scan_headless-2.0/dvr_scan/docs/docs.html +84 -0
- dvr_scan_headless-2.0/dvr_scan/docs/faq.html +15 -0
- dvr_scan_headless-2.0/dvr_scan/docs/guide.html +1 -0
- dvr_scan_headless-2.0/dvr_scan/docs/index.html +5 -0
- dvr_scan_headless-2.0/dvr_scan/docs/literature.html +7 -0
- dvr_scan_headless-2.0/dvr_scan/docs/resources.html +30 -0
- dvr_scan_headless-2.0/dvr_scan/docs/style.min.css +1 -0
- dvr_scan_headless-2.0/dvr_scan/dvr-scan-logo.png +0 -0
- dvr_scan_headless-2.0/dvr_scan/dvr-scan.ico +0 -0
- dvr_scan_headless-2.0/dvr_scan/dvr-scan.png +0 -0
- dvr_scan_headless-2.0/dvr_scan/encoder.py +756 -0
- dvr_scan_headless-2.0/dvr_scan/presets.py +277 -0
- dvr_scan_headless-2.0/dvr_scan/report.py +120 -0
- dvr_scan_headless-2.0/dvr_scan/scanner.py +1328 -0
- {dvr_scan_headless-1.8.2 → dvr_scan_headless-2.0}/dvr_scan/shared/__init__.py +28 -4
- {dvr_scan_headless-1.8.2 → dvr_scan_headless-2.0}/dvr_scan/shared/cli.py +7 -2
- {dvr_scan_headless-1.8.2 → dvr_scan_headless-2.0}/dvr_scan/shared/settings.py +5 -0
- {dvr_scan_headless-1.8.2 → dvr_scan_headless-2.0}/dvr_scan/subtractor.py +31 -0
- dvr_scan_headless-2.0/dvr_scan/video_input.py +295 -0
- dvr_scan_headless-2.0/dvr_scan_headless.egg-info/PKG-INFO +108 -0
- {dvr_scan_headless-1.8.2/DVR_Scan_Headless.egg-info → dvr_scan_headless-2.0/dvr_scan_headless.egg-info}/SOURCES.txt +30 -13
- dvr_scan_headless-2.0/dvr_scan_headless.egg-info/requires.txt +11 -0
- dvr_scan_headless-2.0/pyproject.toml +123 -0
- dvr_scan_headless-2.0/setup.cfg +4 -0
- dvr_scan_headless-2.0/tests/test_application.py +1024 -0
- dvr_scan_headless-2.0/tests/test_cli.py +677 -0
- dvr_scan_headless-2.0/tests/test_encode_mode.py +267 -0
- dvr_scan_headless-2.0/tests/test_encoder.py +546 -0
- dvr_scan_headless-2.0/tests/test_presets.py +373 -0
- dvr_scan_headless-2.0/tests/test_release_scripts.py +124 -0
- dvr_scan_headless-2.0/tests/test_report.py +85 -0
- dvr_scan_headless-2.0/tests/test_scan_context.py +812 -0
- dvr_scan_headless-2.0/tests/test_startup.py +306 -0
- dvr_scan_headless-2.0/tests/test_subtractor.py +51 -0
- dvr_scan_headless-2.0/tests/test_thumbnails.py +262 -0
- dvr_scan_headless-2.0/tests/test_video_input.py +191 -0
- dvr_scan_headless-2.0/tests/test_video_list.py +599 -0
- dvr_scan_headless-2.0/tests/test_wizard.py +833 -0
- dvr_scan_headless-1.8.2/DVR_Scan_Headless.egg-info/PKG-INFO +0 -117
- dvr_scan_headless-1.8.2/DVR_Scan_Headless.egg-info/requires.txt +0 -7
- dvr_scan_headless-1.8.2/PKG-INFO +0 -117
- dvr_scan_headless-1.8.2/dvr_scan/app/common.py +0 -31
- dvr_scan_headless-1.8.2/dvr_scan/app/scan_window.py +0 -258
- dvr_scan_headless-1.8.2/dvr_scan/docs/404.html +0 -1
- dvr_scan_headless-1.8.2/dvr_scan/docs/assets/javascripts/bundle.88dd0f4e.min.js +0 -15
- dvr_scan_headless-1.8.2/dvr_scan/docs/assets/stylesheets/main.6f8fc17f.min.css +0 -1
- dvr_scan_headless-1.8.2/dvr_scan/docs/assets/stylesheets/palette.06af60db.min.css +0 -1
- dvr_scan_headless-1.8.2/dvr_scan/docs/changelog.html +0 -1
- dvr_scan_headless-1.8.2/dvr_scan/docs/docs.html +0 -73
- dvr_scan_headless-1.8.2/dvr_scan/docs/faq.html +0 -13
- dvr_scan_headless-1.8.2/dvr_scan/docs/guide.html +0 -1
- dvr_scan_headless-1.8.2/dvr_scan/docs/index.html +0 -5
- dvr_scan_headless-1.8.2/dvr_scan/docs/resources.html +0 -30
- dvr_scan_headless-1.8.2/dvr_scan/docs/style.min.css +0 -1
- dvr_scan_headless-1.8.2/dvr_scan/dvr-scan-logo.png +0 -0
- dvr_scan_headless-1.8.2/dvr_scan/dvr-scan.ico +0 -0
- dvr_scan_headless-1.8.2/dvr_scan/dvr-scan.png +0 -0
- dvr_scan_headless-1.8.2/dvr_scan/scanner.py +0 -1310
- dvr_scan_headless-1.8.2/dvr_scan/video_joiner.py +0 -192
- dvr_scan_headless-1.8.2/pyproject.toml +0 -45
- dvr_scan_headless-1.8.2/setup.cfg +0 -70
- dvr_scan_headless-1.8.2/tests/test_cli.py +0 -307
- dvr_scan_headless-1.8.2/tests/test_maxarea.py +0 -111
- dvr_scan_headless-1.8.2/tests/test_scan_context.py +0 -251
- dvr_scan_headless-1.8.2/tests/test_video_joiner.py +0 -37
- {dvr_scan_headless-1.8.2 → dvr_scan_headless-2.0}/LICENSE +0 -0
- {dvr_scan_headless-1.8.2 → dvr_scan_headless-2.0}/dist/package-info.rst +0 -0
- {dvr_scan_headless-1.8.2 → dvr_scan_headless-2.0}/dvr_scan/LICENSE +0 -0
- {dvr_scan_headless-1.8.2 → dvr_scan_headless-2.0}/dvr_scan/app/__init__.py +0 -0
- {dvr_scan_headless-1.8.2 → dvr_scan_headless-2.0}/dvr_scan/detector.py +0 -0
- {dvr_scan_headless-1.8.2 → dvr_scan_headless-2.0}/dvr_scan/opencv_loader.py +0 -0
- {dvr_scan_headless-1.8.2 → dvr_scan_headless-2.0}/dvr_scan/overlays.py +0 -0
- {dvr_scan_headless-1.8.2 → dvr_scan_headless-2.0}/dvr_scan/platform.py +0 -0
- {dvr_scan_headless-1.8.2 → dvr_scan_headless-2.0}/dvr_scan/region.py +0 -0
- {dvr_scan_headless-1.8.2/DVR_Scan_Headless.egg-info → dvr_scan_headless-2.0/dvr_scan_headless.egg-info}/dependency_links.txt +0 -0
- {dvr_scan_headless-1.8.2/DVR_Scan_Headless.egg-info → dvr_scan_headless-2.0/dvr_scan_headless.egg-info}/entry_points.txt +0 -0
- {dvr_scan_headless-1.8.2/DVR_Scan_Headless.egg-info → dvr_scan_headless-2.0/dvr_scan_headless.egg-info}/top_level.txt +0 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dvr-scan-headless
|
|
3
|
+
Version: 2.0
|
|
4
|
+
Summary: Tool for finding and extracting motion events in video files (e.g. security camera footage).
|
|
5
|
+
Author-email: Brandon Castellano <brandon248@gmail.com>
|
|
6
|
+
License: BSD-2-Clause
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/Breakthrough/DVR-Scan/issues
|
|
8
|
+
Project-URL: Documentation, https://www.dvr-scan.com/docs
|
|
9
|
+
Project-URL: Homepage, https://www.dvr-scan.com/
|
|
10
|
+
Project-URL: Repository, https://github.com/Breakthrough/DVR-Scan
|
|
11
|
+
Keywords: analysis,computer-vision,video
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Environment :: Console :: Curses
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
17
|
+
Classifier: Intended Audience :: System Administrators
|
|
18
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Classifier: Programming Language :: Python :: 3
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Topic :: Multimedia :: Video
|
|
25
|
+
Classifier: Topic :: Multimedia :: Video :: Conversion
|
|
26
|
+
Classifier: Topic :: Multimedia :: Video :: Non-Linear Editor
|
|
27
|
+
Classifier: Topic :: Utilities
|
|
28
|
+
Requires-Python: >=3.11
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Requires-Dist: numpy
|
|
32
|
+
Requires-Dist: platformdirs
|
|
33
|
+
Requires-Dist: scenedetect-headless[pyav]~=0.7.2
|
|
34
|
+
Requires-Dist: av
|
|
35
|
+
Requires-Dist: tqdm
|
|
36
|
+
Requires-Dist: pillow
|
|
37
|
+
Requires-Dist: opencv-contrib-python-headless
|
|
38
|
+
Provides-Extra: dev
|
|
39
|
+
Requires-Dist: pytest; extra == "dev"
|
|
40
|
+
Requires-Dist: ruff; extra == "dev"
|
|
41
|
+
Dynamic: license-file
|
|
42
|
+
|
|
43
|
+

|
|
44
|
+
|
|
45
|
+
:vhs: Find and extract motion events in videos.
|
|
46
|
+
|
|
47
|
+
------------------------------------------------
|
|
48
|
+
|
|
49
|
+
### Latest Release: v2.0 (November 8, 2026)
|
|
50
|
+
|
|
51
|
+
**Website**: [dvr-scan.com](https://www.dvr-scan.com)
|
|
52
|
+
|
|
53
|
+
**User Guide**: [dvr-scan.com/guide](https://www.dvr-scan.com/guide/)
|
|
54
|
+
|
|
55
|
+
**Documentation**: [dvr-scan.com/docs](https://www.dvr-scan.com/docs/)
|
|
56
|
+
|
|
57
|
+
**Discord**: [discord.gg/69kf6f2Exb](https://discord.gg/69kf6f2Exb)
|
|
58
|
+
|
|
59
|
+
------------------------------------------------------
|
|
60
|
+
|
|
61
|
+
DVR-Scan is a command-line application that **automatically detects motion events in video files** (e.g. security camera footage). DVR-Scan looks for areas in footage containing motion, and saves each event to a separate video clip. DVR-Scan is free and open-source software, and works on Windows, Linux, and Mac.
|
|
62
|
+
|
|
63
|
+
## Quick Install
|
|
64
|
+
|
|
65
|
+
pip install dvr-scan --upgrade
|
|
66
|
+
|
|
67
|
+
Windows builds (installer + portable) are also available on [the Downloads page](https://www.dvr-scan.com/download/).
|
|
68
|
+
|
|
69
|
+
## Quickstart (UI)
|
|
70
|
+
|
|
71
|
+
Start DVR-Scan (run `dvr-scan-app` or click the app shortcut). The Scan Wizard walks you through each step: add your input videos, pick a preset, choose where to save the output, and hit **Start Scan**:
|
|
72
|
+
|
|
73
|
+
<img alt="scan wizard" src="https://www.dvr-scan.com/assets/app-wizard-videos.jpg" width="480"/>
|
|
74
|
+
|
|
75
|
+
See the [User Guide](https://www.dvr-scan.com/guide/) for a more comprehensive overview.
|
|
76
|
+
|
|
77
|
+
## Quickstart (CLI)
|
|
78
|
+
|
|
79
|
+
Scan `video.mp4` (separate clips for each event):
|
|
80
|
+
|
|
81
|
+
dvr-scan -i video.mp4
|
|
82
|
+
|
|
83
|
+
Select a region to scan using [the region editor](https://www.dvr-scan.com/guide/):
|
|
84
|
+
|
|
85
|
+
dvr-scan -i video.mp4 -r
|
|
86
|
+
|
|
87
|
+
<img alt="example of region editor" src="https://www.dvr-scan.com/assets/region-editor-mask.jpg" width="480"/>
|
|
88
|
+
|
|
89
|
+
Select a region to scan using command line (list of points as X Y):
|
|
90
|
+
|
|
91
|
+
dvr-scan -i video.mp4 -a 50 50 100 50 100 100 100 50
|
|
92
|
+
|
|
93
|
+
Draw boxes around motion:
|
|
94
|
+
|
|
95
|
+
dvr-scan -i video.mp4 -bb
|
|
96
|
+
|
|
97
|
+
<img alt="example of bounding boxes" src="https://www.dvr-scan.com/assets/bounding-box.gif" width="480"/>
|
|
98
|
+
|
|
99
|
+
Use `ffmpeg` to extract events:
|
|
100
|
+
|
|
101
|
+
dvr-scan -i video.mp4 -m ffmpeg
|
|
102
|
+
|
|
103
|
+
See [the documentation](https://www.dvr-scan.com/docs) for a complete list of all command-line and configuration file options which can be set. You can also type `dvr-scan --help` for an overview of command line options. Some program options can also be set [using a config file](https://www.dvr-scan.com/docs/#config-file).
|
|
104
|
+
|
|
105
|
+
------------------------------------------------
|
|
106
|
+
|
|
107
|
+
Copyright © 2016-2026 Brandon Castellano. All rights reserved.
|
|
108
|
+
Licensed under BSD 2-Clause (see the LICENSE file for details).
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-

|
|
2
2
|
|
|
3
3
|
:vhs: Find and extract motion events in videos.
|
|
4
4
|
|
|
5
5
|
------------------------------------------------
|
|
6
6
|
|
|
7
|
-
### Latest Release:
|
|
7
|
+
### Latest Release: v2.0 (November 8, 2026)
|
|
8
8
|
|
|
9
9
|
**Website**: [dvr-scan.com](https://www.dvr-scan.com)
|
|
10
10
|
|
|
@@ -26,9 +26,9 @@ Windows builds (installer + portable) are also available on [the Downloads page]
|
|
|
26
26
|
|
|
27
27
|
## Quickstart (UI)
|
|
28
28
|
|
|
29
|
-
Start DVR-Scan (run `dvr-scan-app` or click the app shortcut)
|
|
29
|
+
Start DVR-Scan (run `dvr-scan-app` or click the app shortcut). The Scan Wizard walks you through each step: add your input videos, pick a preset, choose where to save the output, and hit **Start Scan**:
|
|
30
30
|
|
|
31
|
-
<img alt="
|
|
31
|
+
<img alt="scan wizard" src="https://www.dvr-scan.com/assets/app-wizard-videos.jpg" width="480"/>
|
|
32
32
|
|
|
33
33
|
See the [User Guide](https://www.dvr-scan.com/guide/) for a more comprehensive overview.
|
|
34
34
|
|
|
@@ -42,7 +42,7 @@ Select a region to scan using [the region editor](https://www.dvr-scan.com/guide
|
|
|
42
42
|
|
|
43
43
|
dvr-scan -i video.mp4 -r
|
|
44
44
|
|
|
45
|
-
<img alt="example of region editor" src="https://
|
|
45
|
+
<img alt="example of region editor" src="https://www.dvr-scan.com/assets/region-editor-mask.jpg" width="480"/>
|
|
46
46
|
|
|
47
47
|
Select a region to scan using command line (list of points as X Y):
|
|
48
48
|
|
|
@@ -52,7 +52,7 @@ Draw boxes around motion:
|
|
|
52
52
|
|
|
53
53
|
dvr-scan -i video.mp4 -bb
|
|
54
54
|
|
|
55
|
-
<img alt="example of bounding boxes" src="https://
|
|
55
|
+
<img alt="example of bounding boxes" src="https://www.dvr-scan.com/assets/bounding-box.gif" width="480"/>
|
|
56
56
|
|
|
57
57
|
Use `ffmpeg` to extract events:
|
|
58
58
|
|
|
@@ -9,25 +9,34 @@
|
|
|
9
9
|
# Windows: C:/Users/%USERNAME%/AppData/Local/DVR-Scan/dvr-scan.cfg
|
|
10
10
|
#
|
|
11
11
|
# Linux: ~/.config/DVR-Scan/dvr-scan.cfg
|
|
12
|
-
# $XDG_CONFIG_HOME/dvr-scan.cfg
|
|
12
|
+
# ($XDG_CONFIG_HOME/DVR-Scan/dvr-scan.cfg if XDG_CONFIG_HOME is set)
|
|
13
13
|
#
|
|
14
|
-
#
|
|
14
|
+
# macOS: ~/Library/Application Support/DVR-Scan/dvr-scan.cfg
|
|
15
15
|
#
|
|
16
16
|
# Run `dvr-scan --help` to see the exact path on your system which will be
|
|
17
17
|
# used (it will be listed under the help text for the -c/--config option).
|
|
18
18
|
#
|
|
19
19
|
|
|
20
|
+
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
21
|
+
# APPLICATION
|
|
22
|
+
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
23
|
+
|
|
24
|
+
# Which mode the DVR-Scan app (dvr-scan-app) starts in: WIZARD or ADVANCED.
|
|
25
|
+
# The Scan Wizard provides a simplified step-by-step workflow, while Advanced
|
|
26
|
+
# Mode shows all settings at once. If this option is not set, the app starts
|
|
27
|
+
# in ADVANCED mode. Can also be changed from File -> Startup Mode in the app,
|
|
28
|
+
# or overridden for one launch with `dvr-scan-app --startup-mode`. Has no
|
|
29
|
+
# effect on the command line.
|
|
30
|
+
startup-mode = WIZARD
|
|
31
|
+
|
|
32
|
+
|
|
20
33
|
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
21
34
|
# INPUT
|
|
22
35
|
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
23
36
|
|
|
24
|
-
# Which mode to use for decoding frames. Possible values are:
|
|
37
|
+
# Which mode to use for decoding frames. Possible values are: PYAV, OPENCV,
|
|
25
38
|
# MOVIEPY.
|
|
26
|
-
#input-mode =
|
|
27
|
-
|
|
28
|
-
# Use presentation time instead of frame number for timestamps. May improve
|
|
29
|
-
# timestamp accuracy with videos and network streams that may skip frames.
|
|
30
|
-
#use-pts = no
|
|
39
|
+
#input-mode = PYAV
|
|
31
40
|
|
|
32
41
|
# Integer factor to shrink video before processing. Values <= 1 have no effect.
|
|
33
42
|
#downscale-factor = 0
|
|
@@ -38,6 +47,10 @@
|
|
|
38
47
|
# Always show the region editor window (-r/--region-editor) before scanning.
|
|
39
48
|
#region-editor = no
|
|
40
49
|
|
|
50
|
+
# Load region data from a file. Each line must be a list of points in the
|
|
51
|
+
# format specified by -a/--add-region. Each line is treated as a polygon.
|
|
52
|
+
#load-region = regions.txt
|
|
53
|
+
|
|
41
54
|
|
|
42
55
|
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
43
56
|
# OUTPUT
|
|
@@ -51,38 +64,75 @@
|
|
|
51
64
|
#open-output-dir = yes
|
|
52
65
|
|
|
53
66
|
# Method of generating output videos. Possible values are: SCAN_ONLY, OPENCV,
|
|
54
|
-
# FFMPEG, COPY.
|
|
55
|
-
#
|
|
67
|
+
# FFMPEG, COPY, ENCODE. The default (ENCODE) produces MP4 (H.264) output with
|
|
68
|
+
# overlay and audio support, and requires ffmpeg (OPENCV is used as a fallback
|
|
69
|
+
# if ffmpeg is missing). Not all features are supported in FFMPEG/COPY mode.
|
|
70
|
+
#output-mode = ENCODE
|
|
71
|
+
|
|
72
|
+
# Encoder parameters used when generating output files in ENCODE mode. Stream
|
|
73
|
+
# mappings are generated automatically and must not be set here. If no -pix_fmt
|
|
74
|
+
# is given, -pix_fmt yuv420p is added and odd frame sizes are padded to even.
|
|
75
|
+
#encode-args = -c:v libx264 -preset veryfast -crf 22 -c:a aac
|
|
56
76
|
|
|
57
77
|
# Arguments to add before the input when calling ffmpeg in output-mode FFMPEG
|
|
58
78
|
# or COPY. Note that `-y` and `-nostdin` are always added.
|
|
59
79
|
#ffmpeg-input-args = -v error
|
|
60
80
|
|
|
61
81
|
# Encoder parameters used when generating output files in FFMPEG mode.
|
|
62
|
-
#ffmpeg-output-args = -map 0 -c:v libx264 -preset
|
|
82
|
+
#ffmpeg-output-args = -map 0:v:0 -map 0:a? -map 0:s? -c:v libx264 -preset veryfast -crf 22 -c:a aac
|
|
63
83
|
|
|
64
84
|
# Four-letter identifier of the encoder/video codec to use in OPENCV mode.
|
|
65
85
|
# Possible values are: XVID, MP4V, MP42, H264
|
|
66
86
|
#opencv-codec = XVID
|
|
67
87
|
|
|
88
|
+
# Only perform motion detection without writing any files to disk. If set,
|
|
89
|
+
# output-mode is ignored.
|
|
90
|
+
#scan-only = no
|
|
91
|
+
|
|
92
|
+
# Produce thumbnail image(s) for each event. Possible values are: HIGHSCORE
|
|
93
|
+
# (saves the frame with the highest motion score).
|
|
94
|
+
#thumbnails = HIGHSCORE
|
|
95
|
+
|
|
96
|
+
# Format of event list printed at the end of a scan (this is exactly what is
|
|
97
|
+
# output in quiet mode). Must be one of:
|
|
98
|
+
# parts: start-end,start-end,... (syntax of `mkvmerge --split parts:`)
|
|
99
|
+
# timecodes: start,end,start,end,... (syntax of `mkvmerge --split timecodes:`)
|
|
100
|
+
# lines: one start-end pair per line (accepted as file input)
|
|
101
|
+
#timecode-list-format = timecodes
|
|
102
|
+
|
|
68
103
|
|
|
69
104
|
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
70
105
|
# MOTION
|
|
71
106
|
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
72
107
|
|
|
108
|
+
# Maximum number of motion events to detect before stopping the scan early
|
|
109
|
+
# (0 for no limit).
|
|
110
|
+
#max-events = 0
|
|
111
|
+
|
|
73
112
|
# Amount of time which must have motion in each frame to trigger an event.
|
|
74
|
-
#min-event-length =
|
|
113
|
+
#min-event-length = 0.1s
|
|
114
|
+
|
|
115
|
+
# Maximum length of a single event, including pre/post-event padding. Longer
|
|
116
|
+
# events are split into consecutive events of at most this length (no padding
|
|
117
|
+
# is added at a split; if motion continues the next event starts there).
|
|
118
|
+
#max-event-length = 999999s
|
|
75
119
|
|
|
76
120
|
# Amount of time to include before an event.
|
|
77
121
|
#time-before-event = 1.5s
|
|
78
122
|
|
|
79
|
-
# Amount of time to include after an event.
|
|
123
|
+
# Amount of time to include after an event. Cannot be larger than merge-window.
|
|
80
124
|
#time-post-event = 2.0s
|
|
81
125
|
|
|
82
|
-
#
|
|
83
|
-
#
|
|
84
|
-
#
|
|
85
|
-
#
|
|
126
|
+
# Merge groups of motion which occur less than this amount of time apart into
|
|
127
|
+
# the same event. The default (auto) uses the same value as time-post-event,
|
|
128
|
+
# which matches the behavior of previous versions.
|
|
129
|
+
#merge-window = auto
|
|
130
|
+
|
|
131
|
+
# Threshold representing amount of motion in a frame (or in the detection
|
|
132
|
+
# regions, if set) for a motion event to be triggered. Lower values require
|
|
133
|
+
# less movement, and are more sensitive to motion. If too high, some movement
|
|
134
|
+
# may not be detected, while too low of a threshold can result in false
|
|
135
|
+
# detection events.
|
|
86
136
|
#threshold = 0.15
|
|
87
137
|
|
|
88
138
|
|
|
@@ -159,14 +209,14 @@
|
|
|
159
209
|
# Enable/disable frame metrics overlay in top right of video frame.
|
|
160
210
|
#frame-metrics = yes
|
|
161
211
|
|
|
162
|
-
#
|
|
212
|
+
# Padding between the text and the edge of its background box, in pixels.
|
|
163
213
|
#text-border = 4
|
|
164
214
|
|
|
165
|
-
#
|
|
215
|
+
# Margin between the background box and the edge of the frame, in pixels.
|
|
166
216
|
#text-margin = 4
|
|
167
217
|
|
|
168
218
|
# Font scale factor.
|
|
169
|
-
#text-font-scale =
|
|
219
|
+
#text-font-scale = 1.0
|
|
170
220
|
|
|
171
221
|
# Thickness of font (integer values only).
|
|
172
222
|
#text-font-thickness = 2
|
|
@@ -182,12 +232,13 @@
|
|
|
182
232
|
# LOGGING
|
|
183
233
|
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
184
234
|
|
|
185
|
-
# Suppress all console output
|
|
186
|
-
# the
|
|
235
|
+
# Suppress all console output except for the final event list (see
|
|
236
|
+
# timecode-list-format). Output can still be saved using the --logfile option.
|
|
187
237
|
#quiet-mode = no
|
|
188
238
|
|
|
189
|
-
# Verbosity of
|
|
190
|
-
#
|
|
239
|
+
# Verbosity of log output (debug, info, warning, error). Applies to the console
|
|
240
|
+
# and to --logfile. If quiet-mode is enabled, nothing except the final event
|
|
241
|
+
# list is printed to the console regardless of verbosity.
|
|
191
242
|
#verbosity = info
|
|
192
243
|
|
|
193
244
|
# Automatically save rolling logs. Useful for bug reports.
|
|
@@ -24,7 +24,7 @@ main modules under `dvr_scan` are organized as follows:
|
|
|
24
24
|
|
|
25
25
|
There are also a few helper modules:
|
|
26
26
|
|
|
27
|
-
``
|
|
27
|
+
``video_input``: opens one or more input videos as a single contiguous stream
|
|
28
28
|
|
|
29
29
|
``opencv_loader``: helper for resolving dynamic libraries used by OpenCV
|
|
30
30
|
|
|
@@ -35,7 +35,7 @@ import pkgutil
|
|
|
35
35
|
import sys
|
|
36
36
|
|
|
37
37
|
# Used for module/distribution identification.
|
|
38
|
-
__version__ = "
|
|
38
|
+
__version__ = "2.0"
|
|
39
39
|
|
|
40
40
|
# Handle loading OpenCV. This **MUST** be first before any other DVR-Scan or third-party
|
|
41
41
|
# packages are imported which might attempt to import the `cv2` module.
|
|
@@ -65,6 +65,12 @@ def main():
|
|
|
65
65
|
logger.critical("Error (Not Implemented): %s", str(ex), exc_info=show_traceback)
|
|
66
66
|
if debug_mode:
|
|
67
67
|
raise
|
|
68
|
+
except (OSError, RuntimeError) as ex:
|
|
69
|
+
# I/O errors (e.g. an unwritable output path) and ffmpeg failures: the message
|
|
70
|
+
# is enough to act on, so only show the traceback in debug mode.
|
|
71
|
+
logger.critical("Error: %s", str(ex), exc_info=show_traceback)
|
|
72
|
+
if debug_mode:
|
|
73
|
+
raise
|
|
68
74
|
except Exception as ex:
|
|
69
75
|
logger.critical("Critical Error: %s", str(ex), exc_info=True)
|
|
70
76
|
if debug_mode:
|
|
@@ -21,6 +21,13 @@ from scenedetect import VideoOpenFailure
|
|
|
21
21
|
import dvr_scan
|
|
22
22
|
from dvr_scan import get_license_info
|
|
23
23
|
from dvr_scan.app.application import Application
|
|
24
|
+
from dvr_scan.app.startup import (
|
|
25
|
+
STARTUP_MODE_OPTION,
|
|
26
|
+
has_prior_logs,
|
|
27
|
+
normalize_startup_mode,
|
|
28
|
+
resolve_default_startup_mode,
|
|
29
|
+
save_startup_mode,
|
|
30
|
+
)
|
|
24
31
|
from dvr_scan.config import CHOICE_MAP, USER_CONFIG_FILE_PATH, ConfigLoadFailure, ConfigRegistry
|
|
25
32
|
from dvr_scan.shared import (
|
|
26
33
|
ScanSettings,
|
|
@@ -40,6 +47,13 @@ EXIT_ERROR: int = 1
|
|
|
40
47
|
LOGFILE_PATH = logfile_path(name_prefix="dvr-scan-app")
|
|
41
48
|
|
|
42
49
|
|
|
50
|
+
def _startup_mode_type(value: str) -> str:
|
|
51
|
+
"""argparse type for `--startup-mode`: accepts the legacy alias "classic" (normalized
|
|
52
|
+
to "advanced") in addition to the values in CHOICE_MAP, any case."""
|
|
53
|
+
check = string_type_check(CHOICE_MAP[STARTUP_MODE_OPTION], False, "mode")
|
|
54
|
+
return check(normalize_startup_mode(value))
|
|
55
|
+
|
|
56
|
+
|
|
43
57
|
def get_cli_parser():
|
|
44
58
|
parser = argparse.ArgumentParser(
|
|
45
59
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
@@ -101,6 +115,16 @@ def get_cli_parser():
|
|
|
101
115
|
help=("Ignore loading the user config file if present."),
|
|
102
116
|
)
|
|
103
117
|
|
|
118
|
+
parser.add_argument(
|
|
119
|
+
"--startup-mode",
|
|
120
|
+
metavar="mode",
|
|
121
|
+
type=_startup_mode_type,
|
|
122
|
+
help=(
|
|
123
|
+
"Mode to start the application in. Must be one of: %s. Overrides the startup-mode "
|
|
124
|
+
"config option for this launch only." % (", ".join(CHOICE_MAP["startup-mode"]),)
|
|
125
|
+
),
|
|
126
|
+
)
|
|
127
|
+
|
|
104
128
|
parser.add_argument(
|
|
105
129
|
"--debug",
|
|
106
130
|
action="store_true",
|
|
@@ -178,20 +202,63 @@ def main():
|
|
|
178
202
|
logger.debug("Error loading config file:", exc_info=config_load_error)
|
|
179
203
|
# Intentionally suppress the exception in release mode since we've already logged the
|
|
180
204
|
# failure reason to the user above. We can now exit with an error code.
|
|
181
|
-
errors =
|
|
205
|
+
errors = "\n".join(message for (severity, message) in init_log if severity >= logging.ERROR)
|
|
182
206
|
tkinter.messagebox.showerror(
|
|
183
207
|
title="DVR-Scan Startup Error",
|
|
184
|
-
message=f"Error loading config file. Reason:\n\n{
|
|
208
|
+
message=f"Error loading config file. Reason:\n\n{errors}",
|
|
185
209
|
)
|
|
186
210
|
raise SystemExit(1)
|
|
187
211
|
|
|
188
212
|
show_traceback = getattr(logging, settings.get("verbosity").upper()) == logging.DEBUG
|
|
189
213
|
# TODO: Use Python __debug__ mode instead of hard-coding as config option.
|
|
190
214
|
debug_mode = settings.get("debug")
|
|
215
|
+
|
|
216
|
+
# Resolve the default startup mode (wizard or advanced). The first-run heuristic only
|
|
217
|
+
# applies when the user config is in play and no file was given explicitly, since it
|
|
218
|
+
# may write the result to the user config file.
|
|
219
|
+
allow_heuristic = not args.ignore_user_config and not hasattr(args, "config")
|
|
220
|
+
default_startup_mode, persist_startup_mode = resolve_default_startup_mode(
|
|
221
|
+
config,
|
|
222
|
+
user_config_exists=USER_CONFIG_FILE_PATH.exists(),
|
|
223
|
+
prior_logs=has_prior_logs(LOGFILE_PATH.parent, exclude=LOGFILE_PATH),
|
|
224
|
+
allow_heuristic=allow_heuristic,
|
|
225
|
+
)
|
|
226
|
+
if persist_startup_mode:
|
|
227
|
+
try:
|
|
228
|
+
path = save_startup_mode(default_startup_mode)
|
|
229
|
+
logger.debug("first run: saved startup-mode = %s to %s", default_startup_mode, path)
|
|
230
|
+
except (OSError, UnicodeError) as ex:
|
|
231
|
+
logger.warning("Failed to save startup mode to user config file: %s", ex)
|
|
232
|
+
startup_mode = (
|
|
233
|
+
normalize_startup_mode(args.startup_mode)
|
|
234
|
+
if hasattr(args, "startup_mode")
|
|
235
|
+
else default_startup_mode
|
|
236
|
+
)
|
|
237
|
+
# The File > Startup Mode menu shows and edits the value in the user config file. With
|
|
238
|
+
# -c or --ignore-user-config that is not the config we launched from, so read it here
|
|
239
|
+
# (falling back to the program default if the user config is missing or invalid).
|
|
240
|
+
menu_startup_mode = default_startup_mode
|
|
241
|
+
if not allow_heuristic:
|
|
242
|
+
try:
|
|
243
|
+
user_config = ConfigRegistry()
|
|
244
|
+
user_config.load(log_level=logging.DEBUG)
|
|
245
|
+
menu_startup_mode = normalize_startup_mode(user_config.get(STARTUP_MODE_OPTION))
|
|
246
|
+
except ConfigLoadFailure:
|
|
247
|
+
menu_startup_mode = normalize_startup_mode(ConfigRegistry().get(STARTUP_MODE_OPTION))
|
|
248
|
+
logger.debug(
|
|
249
|
+
"startup mode: %s (default: %s, user config: %s)",
|
|
250
|
+
startup_mode,
|
|
251
|
+
default_startup_mode,
|
|
252
|
+
menu_startup_mode,
|
|
253
|
+
)
|
|
254
|
+
|
|
191
255
|
with logging_redirect_tqdm(loggers=[logger]):
|
|
192
256
|
try:
|
|
193
257
|
app = Application(
|
|
194
|
-
settings=settings,
|
|
258
|
+
settings=settings,
|
|
259
|
+
initial_videos=args.input if hasattr(args, "input") else [],
|
|
260
|
+
startup_mode=startup_mode,
|
|
261
|
+
default_startup_mode=menu_startup_mode,
|
|
195
262
|
)
|
|
196
263
|
app.run()
|
|
197
264
|
|
|
@@ -27,7 +27,8 @@ from dvr_scan.platform import get_system_version_info
|
|
|
27
27
|
|
|
28
28
|
TITLE = "About DVR-Scan"
|
|
29
29
|
COPYRIGHT = (
|
|
30
|
-
f"DVR-Scan {dvr_scan.__version__}\n\
|
|
30
|
+
f"DVR-Scan {dvr_scan.__version__}\n\n"
|
|
31
|
+
"Copyright \N{COPYRIGHT SIGN} Brandon Castellano.\nAll rights reserved."
|
|
31
32
|
)
|
|
32
33
|
|
|
33
34
|
|