scenedetect 0.7__tar.gz → 0.7.1.dev0__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.
- {scenedetect-0.7/scenedetect.egg-info → scenedetect-0.7.1.dev0}/PKG-INFO +4 -12
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/README.md +8 -7
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/docs/api/backends.rst +5 -2
- scenedetect-0.7.1.dev0/docs/api/common.rst +9 -0
- scenedetect-0.7.1.dev0/docs/api/detector.rst +9 -0
- scenedetect-0.7.1.dev0/docs/api/detectors.rst +53 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/docs/api/migration_guide.rst +1 -1
- scenedetect-0.7.1.dev0/docs/api/output.rst +9 -0
- scenedetect-0.7.1.dev0/docs/api/platform.rst +9 -0
- scenedetect-0.7.1.dev0/docs/api/scene_manager.rst +9 -0
- scenedetect-0.7.1.dev0/docs/api/stats_manager.rst +9 -0
- scenedetect-0.7.1.dev0/docs/api/video_stream.rst +9 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/docs/api.rst +9 -24
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/docs/cli.rst +4 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/docs/conf.py +3 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/docs/index.rst +2 -1
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/packaging/package-info.rst +2 -0
- scenedetect-0.7.1.dev0/pyproject.toml +81 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/__init__.py +21 -6
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/_cli/__init__.py +11 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/_cli/commands.py +13 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/_cli/config.py +1 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/backends/__init__.py +9 -0
- scenedetect-0.7.1.dev0/scenedetect/backends/concat.py +387 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/backends/opencv.py +4 -3
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/backends/pyav.py +66 -25
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/common.py +60 -3
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/detector.py +2 -2
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/detectors/content_detector.py +1 -1
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/detectors/histogram_detector.py +16 -22
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/detectors/threshold_detector.py +1 -1
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/platform.py +18 -5
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/scene_manager.py +30 -2
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/video_stream.py +10 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect.cfg +5 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0/scenedetect.egg-info}/PKG-INFO +4 -12
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect.egg-info/SOURCES.txt +3 -0
- scenedetect-0.7.1.dev0/scenedetect.egg-info/requires.txt +11 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/tests/test_backend_opencv.py +18 -0
- scenedetect-0.7.1.dev0/tests/test_backend_pyav.py +93 -0
- scenedetect-0.7.1.dev0/tests/test_benchmark_evaluator.py +322 -0
- scenedetect-0.7.1.dev0/tests/test_concat.py +177 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/tests/test_scene_manager.py +52 -1
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/tests/test_timecode.py +57 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/tests/test_vfr.py +20 -9
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/tests/test_video_stream.py +27 -4
- scenedetect-0.7/docs/api/common.rst +0 -9
- scenedetect-0.7/docs/api/detector.rst +0 -9
- scenedetect-0.7/docs/api/detectors.rst +0 -24
- scenedetect-0.7/docs/api/output.rst +0 -36
- scenedetect-0.7/docs/api/platform.rst +0 -9
- scenedetect-0.7/docs/api/scene_manager.rst +0 -9
- scenedetect-0.7/docs/api/stats_manager.rst +0 -9
- scenedetect-0.7/docs/api/video_stream.rst +0 -9
- scenedetect-0.7/pyproject.toml +0 -157
- scenedetect-0.7/scenedetect.egg-info/requires.txt +0 -24
- scenedetect-0.7/tests/test_backend_pyav.py +0 -31
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/LICENSE +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/docs/LATEST_VERSION +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/docs/Makefile +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/docs/_static/favicon.ico +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/docs/_static/pyscenedetect.css +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/docs/_static/pyscenedetect_logo.png +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/docs/_static/pyscenedetect_logo_small.png +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/docs/_templates/navigation.html +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/docs/cli/backends.rst +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/docs/cli/config_file.rst +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/docs/generate_cli_docs.py +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/docs/make.bat +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/__main__.py +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/_cli/context.py +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/_cli/controller.py +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/_thirdparty/__init__.py +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/_thirdparty/simpletable.py +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/backends/moviepy.py +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/detectors/__init__.py +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/detectors/adaptive_detector.py +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/detectors/hash_detector.py +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/detectors/transnet_v2.py +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/frame_timecode.py +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/output/__init__.py +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/output/image.py +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/output/video.py +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/scene_detector.py +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/stats_manager.py +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect/video_splitter.py +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect.egg-info/dependency_links.txt +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect.egg-info/entry_points.txt +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/scenedetect.egg-info/top_level.txt +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/setup.cfg +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/tests/test_api.py +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/tests/test_cli.py +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/tests/test_detectors.py +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/tests/test_output.py +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/tests/test_platform.py +0 -0
- {scenedetect-0.7 → scenedetect-0.7.1.dev0}/tests/test_stats_manager.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: scenedetect
|
|
3
|
-
Version: 0.7
|
|
4
|
-
Summary: Video scene cut/shot detection program and Python library.
|
|
3
|
+
Version: 0.7.1.dev0
|
|
4
|
+
Summary: Video scene cut/shot detection program and Python library (bundles the opencv-python OpenCV variant and the scenedetect CLI).
|
|
5
5
|
Author-email: Brandon Castellano <brandon248@gmail.com>
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
7
7
|
Project-URL: Homepage, https://www.scenedetect.com
|
|
@@ -37,16 +37,6 @@ Provides-Extra: pyav
|
|
|
37
37
|
Requires-Dist: av>=9.2; extra == "pyav"
|
|
38
38
|
Provides-Extra: moviepy
|
|
39
39
|
Requires-Dist: moviepy; extra == "moviepy"
|
|
40
|
-
Provides-Extra: dev
|
|
41
|
-
Requires-Dist: av>=9.2; extra == "dev"
|
|
42
|
-
Requires-Dist: moviepy; extra == "dev"
|
|
43
|
-
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
44
|
-
Provides-Extra: docs
|
|
45
|
-
Requires-Dist: Sphinx==7.0.1; extra == "docs"
|
|
46
|
-
Requires-Dist: sphinx-copybutton==0.5.2; extra == "docs"
|
|
47
|
-
Provides-Extra: website
|
|
48
|
-
Requires-Dist: mkdocs==1.5.2; extra == "website"
|
|
49
|
-
Requires-Dist: jinja2>=3.1.6; extra == "website"
|
|
50
40
|
Dynamic: license-file
|
|
51
41
|
|
|
52
42
|
|
|
@@ -76,6 +66,8 @@ Github Repo: https://github.com/Breakthrough/PySceneDetect/
|
|
|
76
66
|
|
|
77
67
|
Install: ``pip install --upgrade scenedetect`` (or ``scenedetect-headless`` for servers)
|
|
78
68
|
|
|
69
|
+
Packages: `scenedetect <https://pypi.org/project/scenedetect/>`_ (CLI + ``opencv-python``), `scenedetect-headless <https://pypi.org/project/scenedetect-headless/>`_ (CLI + ``opencv-python-headless``), and `scenedetect-core <https://pypi.org/project/scenedetect-core/>`_ (library only, minimal dependencies, bring your own OpenCV variant). All provide the same ``scenedetect`` module -- install only one.
|
|
70
|
+
|
|
79
71
|
----------------------------------------------------------
|
|
80
72
|
|
|
81
73
|
**PySceneDetect** is a tool for detecting shot changes in videos, and can automatically split videos into separate clips. PySceneDetect is free and open-source software, and has several detection methods to find fast-cuts and threshold-based fades.
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/Breakthrough/PySceneDetect/main/website/pages/img/pyscenedetect_logo_small_darkmode.png">
|
|
4
|
+
<img alt="PySceneDetect" src="https://raw.githubusercontent.com/Breakthrough/PySceneDetect/main/website/pages/img/pyscenedetect_logo_small.png">
|
|
5
|
+
</picture>
|
|
6
|
+
|
|
7
|
+
# Video Cut Detection and Analysis Tool
|
|
6
8
|
|
|
7
9
|
[](https://github.com/Breakthrough/PySceneDetect/actions)
|
|
8
10
|
[](https://pypi.python.org/pypi/scenedetect/)
|
|
@@ -25,8 +27,7 @@ Video Cut Detection and Analysis Tool
|
|
|
25
27
|
|
|
26
28
|
**Quick Install**:
|
|
27
29
|
|
|
28
|
-
pip install scenedetect --upgrade
|
|
29
|
-
pip install scenedetect-headless --upgrade # headless servers (depends on opencv-python-headless)
|
|
30
|
+
pip install scenedetect --upgrade
|
|
30
31
|
|
|
31
32
|
Requires ffmpeg/mkvmerge for video splitting support. Windows builds (MSI installer/portable ZIP) can be found on [the download page](https://scenedetect.com/download/).
|
|
32
33
|
|
|
@@ -114,7 +115,7 @@ We evaluate the performance of different detectors in terms of accuracy and proc
|
|
|
114
115
|
Please submit any bugs/issues or feature requests to [the Issue Tracker](https://github.com/Breakthrough/PySceneDetect/issues). Before submission, ensure you search through existing issues (both open and closed) to avoid creating duplicate entries.
|
|
115
116
|
Pull requests are welcome and encouraged. PySceneDetect is released under the BSD 3-Clause license, and submitted code should be compliant.
|
|
116
117
|
|
|
117
|
-
For help or other issues, you can join [the official PySceneDetect Discord Server](https://discord.gg/H83HbJngk7), submit an issue/bug report [here on Github](https://github.com/Breakthrough/PySceneDetect/issues), or contact me via [my website](
|
|
118
|
+
For help or other issues, you can join [the official PySceneDetect Discord Server](https://discord.gg/H83HbJngk7), submit an issue/bug report [here on Github](https://github.com/Breakthrough/PySceneDetect/issues), or contact me via [my website](https://bcastell.com/about/).
|
|
118
119
|
|
|
119
120
|
## Code Signing
|
|
120
121
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
|
|
2
2
|
.. _scenedetect-backends:
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
--------------
|
|
5
5
|
Video Backends
|
|
6
|
-
|
|
6
|
+
--------------
|
|
7
7
|
|
|
8
8
|
.. automodule:: scenedetect.backends
|
|
9
9
|
:members:
|
|
@@ -16,3 +16,6 @@ Video Backends
|
|
|
16
16
|
|
|
17
17
|
.. automodule:: scenedetect.backends.moviepy
|
|
18
18
|
:members:
|
|
19
|
+
|
|
20
|
+
.. automodule:: scenedetect.backends.concat
|
|
21
|
+
:members:
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
|
|
2
|
+
.. _scenedetect-detectors:
|
|
3
|
+
|
|
4
|
+
---------
|
|
5
|
+
Detectors
|
|
6
|
+
---------
|
|
7
|
+
|
|
8
|
+
.. automodule:: scenedetect.detectors
|
|
9
|
+
|
|
10
|
+
AdaptiveDetector
|
|
11
|
+
================
|
|
12
|
+
|
|
13
|
+
.. automodule:: scenedetect.detectors.adaptive_detector
|
|
14
|
+
:no-members:
|
|
15
|
+
|
|
16
|
+
.. autoclass:: scenedetect.detectors.adaptive_detector.AdaptiveDetector
|
|
17
|
+
:members:
|
|
18
|
+
|
|
19
|
+
ContentDetector
|
|
20
|
+
===============
|
|
21
|
+
|
|
22
|
+
.. automodule:: scenedetect.detectors.content_detector
|
|
23
|
+
:no-members:
|
|
24
|
+
|
|
25
|
+
.. autoclass:: scenedetect.detectors.content_detector.ContentDetector
|
|
26
|
+
:members:
|
|
27
|
+
|
|
28
|
+
HashDetector
|
|
29
|
+
============
|
|
30
|
+
|
|
31
|
+
.. automodule:: scenedetect.detectors.hash_detector
|
|
32
|
+
:no-members:
|
|
33
|
+
|
|
34
|
+
.. autoclass:: scenedetect.detectors.hash_detector.HashDetector
|
|
35
|
+
:members:
|
|
36
|
+
|
|
37
|
+
HistogramDetector
|
|
38
|
+
=================
|
|
39
|
+
|
|
40
|
+
.. automodule:: scenedetect.detectors.histogram_detector
|
|
41
|
+
:no-members:
|
|
42
|
+
|
|
43
|
+
.. autoclass:: scenedetect.detectors.histogram_detector.HistogramDetector
|
|
44
|
+
:members:
|
|
45
|
+
|
|
46
|
+
ThresholdDetector
|
|
47
|
+
=================
|
|
48
|
+
|
|
49
|
+
.. automodule:: scenedetect.detectors.threshold_detector
|
|
50
|
+
:no-members:
|
|
51
|
+
|
|
52
|
+
.. autoclass:: scenedetect.detectors.threshold_detector.ThresholdDetector
|
|
53
|
+
:members:
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
.. _scenedetect-migration-guide:
|
|
3
3
|
|
|
4
4
|
***********************************************************************
|
|
5
|
-
Migration Guide
|
|
5
|
+
Migration Guide (v0.7)
|
|
6
6
|
***********************************************************************
|
|
7
7
|
|
|
8
8
|
PySceneDetect v0.7 is a major release that overhauls timestamp handling to support variable framerate (VFR) videos. While the high-level :func:`scenedetect.detect` workflow is largely unchanged, several internal APIs have been restructured. This guide covers the changes needed to update applications from v0.6 to v0.7.
|
|
@@ -9,15 +9,15 @@ The `scenedetect` API is easy to integrate with most application workflows, whil
|
|
|
9
9
|
|
|
10
10
|
* :ref:`scenedetect.detectors 🕵️ <scenedetect-detectors>`: detection algorithms:
|
|
11
11
|
|
|
12
|
-
* :
|
|
12
|
+
* :class:`AdaptiveDetector <scenedetect.detectors.adaptive_detector.AdaptiveDetector>`: finds fast cuts using rolling average of HSL changes
|
|
13
13
|
|
|
14
|
-
* :
|
|
14
|
+
* :class:`ContentDetector <scenedetect.detectors.content_detector.ContentDetector>`: detects fast cuts using weighted average of HSV changes
|
|
15
15
|
|
|
16
|
-
* :
|
|
16
|
+
* :class:`ThresholdDetector <scenedetect.detectors.threshold_detector.ThresholdDetector>`: finds fades in/out using average pixel intensity changes in RGB
|
|
17
17
|
|
|
18
|
-
* :
|
|
18
|
+
* :class:`HistogramDetector <scenedetect.detectors.histogram_detector.HistogramDetector>`: finds fast cuts using HSV histogram changes
|
|
19
19
|
|
|
20
|
-
* :
|
|
20
|
+
* :class:`HashDetector <scenedetect.detectors.hash_detector.HashDetector>`: finds fast cuts using perceptual image hashing
|
|
21
21
|
|
|
22
22
|
* :ref:`scenedetect.output ✂️ <scenedetect-output>`: Output formats:
|
|
23
23
|
|
|
@@ -29,19 +29,21 @@ The `scenedetect` API is easy to integrate with most application workflows, whil
|
|
|
29
29
|
|
|
30
30
|
* :ref:`scenedetect.backends 🎥 <scenedetect-backends>`: PySceneDetect supports multiple libraries as an input backend:
|
|
31
31
|
|
|
32
|
-
* OpenCV: :class:`VideoStreamCv2 <scenedetect.backends.opencv.
|
|
32
|
+
* OpenCV: :class:`VideoStreamCv2 <scenedetect.backends.opencv.VideoStreamCv2>`
|
|
33
33
|
|
|
34
34
|
* PyAV: :class:`VideoStreamAv <scenedetect.backends.pyav.VideoStreamAv>`
|
|
35
35
|
|
|
36
36
|
* MoviePy: :class:`VideoStreamMoviePy <scenedetect.backends.moviepy.VideoStreamMoviePy>`
|
|
37
37
|
|
|
38
|
+
* Multiple videos can be treated as a single continuous stream using :class:`VideoStreamConcat <scenedetect.backends.concat.VideoStreamConcat>` (e.g. ``open_video(["part1.mp4", "part2.mp4"])``)
|
|
39
|
+
|
|
38
40
|
* :ref:`scenedetect.common ⏱️ <scenedetect-common>`: common functionality such as :class:`FrameTimecode <scenedetect.common.FrameTimecode>` for timecode handling
|
|
39
41
|
|
|
40
42
|
* :ref:`scenedetect.scene_manager 🎞️ <scenedetect-scene_manager>`: the :class:`SceneManager <scenedetect.scene_manager.SceneManager>` coordinates performing scene detection on a video with one or more detectors
|
|
41
43
|
|
|
42
44
|
* :ref:`scenedetect.detector 🌐 <scenedetect-detector>`: the interface (:class:`SceneDetector <scenedetect.detector.SceneDetector>`) that detectors must implement to be compatible with PySceneDetect
|
|
43
45
|
|
|
44
|
-
* :ref:`scenedetect.video_stream
|
|
46
|
+
* :ref:`scenedetect.video_stream 📹 <scenedetect-video_stream>`: the interface (:class:`VideoStream <scenedetect.video_stream.VideoStream>`) that video backends must implement to be compatible with PySceneDetect
|
|
45
47
|
|
|
46
48
|
* :ref:`scenedetect.stats_manager 🧮 <scenedetect-stats_manager>`: the :class:`StatsManager <scenedetect.stats_manager.StatsManager>` allows you to store detection metrics for each frame and save them to CSV for further analysis
|
|
47
49
|
|
|
@@ -96,23 +98,6 @@ Functions
|
|
|
96
98
|
.. automodule:: scenedetect
|
|
97
99
|
:members:
|
|
98
100
|
|
|
99
|
-
.. toctree::
|
|
100
|
-
:maxdepth: 3
|
|
101
|
-
:caption: PySceneDetect Module Documentation
|
|
102
|
-
:name: fullapitoc
|
|
103
|
-
:hidden:
|
|
104
|
-
|
|
105
|
-
api/migration_guide
|
|
106
|
-
api/detectors
|
|
107
|
-
api/scene_manager
|
|
108
|
-
api/common
|
|
109
|
-
api/output
|
|
110
|
-
api/backends
|
|
111
|
-
api/stats_manager
|
|
112
|
-
api/detector
|
|
113
|
-
api/video_stream
|
|
114
|
-
api/platform
|
|
115
|
-
|
|
116
101
|
|
|
117
102
|
=======================================================================
|
|
118
103
|
Logging
|
|
@@ -857,6 +857,10 @@ Options
|
|
|
857
857
|
|
|
858
858
|
Split video using mkvmerge. Faster than re-encoding, but less precise. If set, options other than :option:`-f/--filename <-f>`, :option:`-q/--quiet <-q>` and :option:`-o/--output <-o>` will be ignored. Note that mkvmerge automatically appends the $SCENE_NUMBER suffix.
|
|
859
859
|
|
|
860
|
+
.. option:: --expand
|
|
861
|
+
|
|
862
|
+
Extend the first/last output clips to cover the full input video, even if the :ref:`time <command-time>` command's ``--start``/``--end`` limited the analysis window. Useful for keeping content outside the analyzed region attached to the adjacent split.
|
|
863
|
+
|
|
860
864
|
|
|
861
865
|
.. _command-time:
|
|
862
866
|
|
|
@@ -45,6 +45,9 @@ autodoc_member_order = "groupwise"
|
|
|
45
45
|
autodoc_typehints = "description"
|
|
46
46
|
autodoc_typehints_format = "short"
|
|
47
47
|
|
|
48
|
+
add_module_names = False
|
|
49
|
+
python_use_unqualified_type_names = True
|
|
50
|
+
|
|
48
51
|
# Add any paths that contain templates here, relative to this directory.
|
|
49
52
|
templates_path = ["_templates"]
|
|
50
53
|
|
|
@@ -8,7 +8,7 @@ PySceneDetect Documentation
|
|
|
8
8
|
|
|
9
9
|
Welcome to the PySceneDetect docs. The docs are split into two separate parts: one for the command-line interface (the `scenedetect` command) and another for the Python API (the `scenedetect` module).
|
|
10
10
|
|
|
11
|
-
You can install the latest release of PySceneDetect by running `pip install scenedetect` (or `pip install scenedetect-headless` on servers without GUI libraries), or by downloading the Windows build from `scenedetect.com/download <http://www.scenedetect.com/download/>`_. PySceneDetect requires `ffmpeg` or `mkvmerge` for video splitting support.
|
|
11
|
+
You can install the latest release of PySceneDetect by running `pip install scenedetect` (or `pip install scenedetect-headless` on servers without GUI libraries), or by downloading the Windows build from `scenedetect.com/download <http://www.scenedetect.com/download/>`_. Library-only installs that need a specific OpenCV variant (e.g. `opencv-contrib-python`) can use `pip install scenedetect-core`, which has no CLI dependencies and lets you supply any OpenCV package. PySceneDetect requires `ffmpeg` or `mkvmerge` for video splitting support.
|
|
12
12
|
|
|
13
13
|
.. note::
|
|
14
14
|
|
|
@@ -54,6 +54,7 @@ Table of Contents
|
|
|
54
54
|
api/video_stream
|
|
55
55
|
api/stats_manager
|
|
56
56
|
api/platform
|
|
57
|
+
api/migration_guide
|
|
57
58
|
|
|
58
59
|
=======================================================================
|
|
59
60
|
Indices and Tables
|
|
@@ -25,6 +25,8 @@ Github Repo: https://github.com/Breakthrough/PySceneDetect/
|
|
|
25
25
|
|
|
26
26
|
Install: ``pip install --upgrade scenedetect`` (or ``scenedetect-headless`` for servers)
|
|
27
27
|
|
|
28
|
+
Packages: `scenedetect <https://pypi.org/project/scenedetect/>`_ (CLI + ``opencv-python``), `scenedetect-headless <https://pypi.org/project/scenedetect-headless/>`_ (CLI + ``opencv-python-headless``), and `scenedetect-core <https://pypi.org/project/scenedetect-core/>`_ (library only, minimal dependencies, bring your own OpenCV variant). All provide the same ``scenedetect`` module -- install only one.
|
|
29
|
+
|
|
28
30
|
----------------------------------------------------------
|
|
29
31
|
|
|
30
32
|
**PySceneDetect** is a tool for detecting shot changes in videos, and can automatically split videos into separate clips. PySceneDetect is free and open-source software, and has several detection methods to find fast-cuts and threshold-based fades.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#
|
|
2
|
+
# PySceneDetect: Python-Based Video Scene Detector
|
|
3
|
+
# ---------------------------------------------------------------
|
|
4
|
+
# [ Site: http://www.bcastell.com/projects/PySceneDetect/ ]
|
|
5
|
+
# [ Github: https://github.com/Breakthrough/PySceneDetect/ ]
|
|
6
|
+
# [ Documentation: http://www.scenedetect.com/docs/ ]
|
|
7
|
+
#
|
|
8
|
+
# Copyright (C) 2014 Brandon Castellano <http://www.bcastell.com>.
|
|
9
|
+
#
|
|
10
|
+
# pyproject.toml for the `scenedetect` package: the same code as scenedetect-core,
|
|
11
|
+
# but bundling the opencv-python (GUI-capable) OpenCV variant, the CLI dependencies,
|
|
12
|
+
# and the `scenedetect` console script. packaging/build_all.py temporarily swaps
|
|
13
|
+
# this file into the repo root and builds from there, so the code, readme, and
|
|
14
|
+
# dynamic version are shared with the other variants.
|
|
15
|
+
#
|
|
16
|
+
# Keep [project] metadata (classifiers, requires-python, etc.) in sync with the
|
|
17
|
+
# root pyproject.toml and pyproject-scenedetect-headless.toml. Only the name,
|
|
18
|
+
# description, dependencies, extras, and console script differ between variants.
|
|
19
|
+
|
|
20
|
+
[build-system]
|
|
21
|
+
requires = ["setuptools>=77"]
|
|
22
|
+
build-backend = "setuptools.build_meta"
|
|
23
|
+
|
|
24
|
+
[project]
|
|
25
|
+
name = "scenedetect"
|
|
26
|
+
dynamic = ["version"]
|
|
27
|
+
description = "Video scene cut/shot detection program and Python library (bundles the opencv-python OpenCV variant and the scenedetect CLI)."
|
|
28
|
+
readme = { file = "packaging/package-info.rst", content-type = "text/x-rst" }
|
|
29
|
+
license = "BSD-3-Clause"
|
|
30
|
+
license-files = ["LICENSE"]
|
|
31
|
+
requires-python = ">=3.10"
|
|
32
|
+
authors = [{ name = "Brandon Castellano", email = "brandon248@gmail.com" }]
|
|
33
|
+
keywords = ["video", "computer-vision", "analysis"]
|
|
34
|
+
classifiers = [
|
|
35
|
+
"Development Status :: 5 - Production/Stable",
|
|
36
|
+
"Environment :: Console",
|
|
37
|
+
"Environment :: Console :: Curses",
|
|
38
|
+
"Intended Audience :: Developers",
|
|
39
|
+
"Intended Audience :: End Users/Desktop",
|
|
40
|
+
"Intended Audience :: System Administrators",
|
|
41
|
+
"Operating System :: OS Independent",
|
|
42
|
+
"Programming Language :: Python :: 3",
|
|
43
|
+
"Programming Language :: Python :: 3.10",
|
|
44
|
+
"Programming Language :: Python :: 3.11",
|
|
45
|
+
"Programming Language :: Python :: 3.12",
|
|
46
|
+
"Programming Language :: Python :: 3.13",
|
|
47
|
+
"Topic :: Multimedia :: Video",
|
|
48
|
+
"Topic :: Multimedia :: Video :: Conversion",
|
|
49
|
+
"Topic :: Multimedia :: Video :: Non-Linear Editor",
|
|
50
|
+
"Topic :: Utilities",
|
|
51
|
+
]
|
|
52
|
+
dependencies = [
|
|
53
|
+
# click 8.3.0 specifically is excluded per https://scenedetect.com/issues/521; 8.3.1+ are fine.
|
|
54
|
+
"click~=8.0,!=8.3.0",
|
|
55
|
+
"numpy",
|
|
56
|
+
"opencv-python",
|
|
57
|
+
"platformdirs",
|
|
58
|
+
"tqdm",
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
[project.optional-dependencies]
|
|
62
|
+
pyav = ["av>=9.2"]
|
|
63
|
+
moviepy = ["moviepy"]
|
|
64
|
+
|
|
65
|
+
[project.urls]
|
|
66
|
+
Homepage = "https://www.scenedetect.com"
|
|
67
|
+
Documentation = "https://www.scenedetect.com/docs/"
|
|
68
|
+
Source = "https://github.com/Breakthrough/PySceneDetect"
|
|
69
|
+
Issues = "https://github.com/Breakthrough/PySceneDetect/issues"
|
|
70
|
+
|
|
71
|
+
[project.scripts]
|
|
72
|
+
scenedetect = "scenedetect.__main__:main"
|
|
73
|
+
|
|
74
|
+
[tool.setuptools]
|
|
75
|
+
include-package-data = true
|
|
76
|
+
|
|
77
|
+
[tool.setuptools.packages.find]
|
|
78
|
+
include = ["scenedetect*"]
|
|
79
|
+
|
|
80
|
+
[tool.setuptools.dynamic]
|
|
81
|
+
version = { attr = "scenedetect.__version__" }
|
|
@@ -69,20 +69,22 @@ from scenedetect.backends import (
|
|
|
69
69
|
VideoStreamAv,
|
|
70
70
|
VideoStreamMoviePy,
|
|
71
71
|
VideoCaptureAdapter,
|
|
72
|
+
VideoStreamConcat,
|
|
73
|
+
SourceSpan,
|
|
72
74
|
)
|
|
73
75
|
from scenedetect.stats_manager import StatsManager, StatsFileCorrupt
|
|
74
76
|
from scenedetect.scene_manager import SceneManager
|
|
75
77
|
|
|
76
78
|
# Used for module identification and when printing version & about info
|
|
77
79
|
# (e.g. calling `scenedetect version` or `scenedetect about`).
|
|
78
|
-
__version__ = "0.7"
|
|
80
|
+
__version__ = "0.7.1-dev0"
|
|
79
81
|
|
|
80
82
|
init_logger()
|
|
81
83
|
logger = getLogger("pyscenedetect")
|
|
82
84
|
|
|
83
85
|
|
|
84
86
|
def open_video(
|
|
85
|
-
path: StrPath,
|
|
87
|
+
path: "StrPath | list[StrPath] | tuple[StrPath, ...]",
|
|
86
88
|
frame_rate: FrameRate | None = None,
|
|
87
89
|
backend: str = "opencv",
|
|
88
90
|
framerate: float | None = None,
|
|
@@ -92,7 +94,9 @@ def open_video(
|
|
|
92
94
|
system, OpenCV (`VideoStreamCv2`) will be used as a fallback.
|
|
93
95
|
|
|
94
96
|
Arguments:
|
|
95
|
-
path: Path to video file to open.
|
|
97
|
+
path: Path to video file to open. May also be a list of paths, in which case the videos
|
|
98
|
+
are concatenated and treated as a single continuous stream
|
|
99
|
+
(see :class:`VideoStreamConcat <scenedetect.backends.concat.VideoStreamConcat>`).
|
|
96
100
|
frame_rate: Overrides detected frame rate if set. Takes precedence over `framerate`.
|
|
97
101
|
backend: Name of specific backend to use, if possible. See
|
|
98
102
|
:data:`scenedetect.backends.AVAILABLE_BACKENDS` for backends available on the current
|
|
@@ -113,6 +117,10 @@ def open_video(
|
|
|
113
117
|
# used, once internal callers and downstream users have had a release to migrate.
|
|
114
118
|
if frame_rate is None:
|
|
115
119
|
frame_rate = framerate
|
|
120
|
+
# A list of paths is opened as a single concatenated stream. VideoStreamConcat handles
|
|
121
|
+
# backend selection/fallback internally, so this must come before the lookup below.
|
|
122
|
+
if isinstance(path, (list, tuple)):
|
|
123
|
+
return VideoStreamConcat(path, frame_rate, backend=backend, **kwargs)
|
|
116
124
|
last_error: Exception | None = None
|
|
117
125
|
# If `backend` is available, try to open the video at `path` using it.
|
|
118
126
|
if backend in AVAILABLE_BACKENDS:
|
|
@@ -142,18 +150,21 @@ def open_video(
|
|
|
142
150
|
|
|
143
151
|
|
|
144
152
|
def detect(
|
|
145
|
-
video_path: StrPath,
|
|
153
|
+
video_path: "StrPath | list[StrPath] | tuple[StrPath, ...]",
|
|
146
154
|
detector: SceneDetector,
|
|
147
155
|
stats_file_path: StrPath | None = None,
|
|
148
156
|
show_progress: bool = False,
|
|
149
157
|
start_time: TimecodeLike | None = None,
|
|
150
158
|
end_time: TimecodeLike | None = None,
|
|
151
159
|
start_in_scene: bool = False,
|
|
160
|
+
backend: str = "opencv",
|
|
152
161
|
) -> SceneList:
|
|
153
162
|
"""Perform scene detection on a given video `path` using the specified `detector`.
|
|
154
163
|
|
|
155
164
|
Arguments:
|
|
156
|
-
video_path: Path to input video (absolute or relative to working directory).
|
|
165
|
+
video_path: Path to input video (absolute or relative to working directory). May also
|
|
166
|
+
be a list of paths, in which case the videos are concatenated and treated as a
|
|
167
|
+
single continuous stream.
|
|
157
168
|
detector: A `SceneDetector` instance (see :mod:`scenedetect.detectors` for a full list
|
|
158
169
|
of detectors).
|
|
159
170
|
stats_file_path: Path to save per-frame metrics to for statistical analysis or to
|
|
@@ -168,6 +179,10 @@ def detect(
|
|
|
168
179
|
will contain a single scene spanning the entire video (instead of no scenes).
|
|
169
180
|
When detecting fades with `ThresholdDetector`, the beginning portion of the video
|
|
170
181
|
will always be included until the first fade-out event is detected.
|
|
182
|
+
backend: Name of the backend to use for video decoding. See
|
|
183
|
+
:data:`scenedetect.backends.AVAILABLE_BACKENDS` for backends available on the
|
|
184
|
+
current system. Defaults to OpenCV; falls back to OpenCV if the requested backend
|
|
185
|
+
is unavailable or fails to open the video.
|
|
171
186
|
|
|
172
187
|
Returns:
|
|
173
188
|
List of scenes as pairs of (start, end) :class:`FrameTimecode` objects.
|
|
@@ -178,7 +193,7 @@ def detect(
|
|
|
178
193
|
ValueError: `start_time` or `end_time` are incorrectly formatted.
|
|
179
194
|
TypeError: `start_time` or `end_time` are invalid types.
|
|
180
195
|
"""
|
|
181
|
-
video = open_video(video_path)
|
|
196
|
+
video = open_video(video_path, backend=backend)
|
|
182
197
|
if start_time is not None:
|
|
183
198
|
video.seek(FrameTimecode(start_time, video.frame_rate))
|
|
184
199
|
end_timecode = FrameTimecode(end_time, video.frame_rate) if end_time is not None else None
|
|
@@ -1294,6 +1294,15 @@ Customized filenames:
|
|
|
1294
1294
|
USER_CONFIG.get_help_string("split-video", "mkvmerge")
|
|
1295
1295
|
),
|
|
1296
1296
|
)
|
|
1297
|
+
@click.option(
|
|
1298
|
+
"--expand",
|
|
1299
|
+
is_flag=True,
|
|
1300
|
+
flag_value=True,
|
|
1301
|
+
default=False,
|
|
1302
|
+
help="Extend the first/last output clips to cover the full input video, even if `time -s/-e` limited the analysis window. Useful for keeping content outside the analyzed region attached to the adjacent split.{}".format(
|
|
1303
|
+
USER_CONFIG.get_help_string("split-video", "expand")
|
|
1304
|
+
),
|
|
1305
|
+
)
|
|
1297
1306
|
@click.pass_context
|
|
1298
1307
|
def split_video_command(
|
|
1299
1308
|
ctx: click.Context,
|
|
@@ -1306,6 +1315,7 @@ def split_video_command(
|
|
|
1306
1315
|
preset: str | None,
|
|
1307
1316
|
args: str | None,
|
|
1308
1317
|
mkvmerge: bool,
|
|
1318
|
+
expand: bool,
|
|
1309
1319
|
):
|
|
1310
1320
|
ctx = ctx.obj
|
|
1311
1321
|
assert isinstance(ctx, CliContext)
|
|
@@ -1372,6 +1382,7 @@ def split_video_command(
|
|
|
1372
1382
|
"output": ctx.config.get_value("split-video", "output", output),
|
|
1373
1383
|
"show_output": not ctx.config.get_value("split-video", "quiet", quiet),
|
|
1374
1384
|
"ffmpeg_args": args,
|
|
1385
|
+
"expand": ctx.config.get_value("split-video", "expand", expand),
|
|
1375
1386
|
}
|
|
1376
1387
|
ctx.add_command(cli_commands.split_video, split_video_args)
|
|
1377
1388
|
|
|
@@ -37,6 +37,7 @@ from scenedetect.scene_manager import (
|
|
|
37
37
|
CutList,
|
|
38
38
|
Interpolation,
|
|
39
39
|
SceneList,
|
|
40
|
+
expand_scenes_to_bounds,
|
|
40
41
|
)
|
|
41
42
|
|
|
42
43
|
logger = logging.getLogger("pyscenedetect")
|
|
@@ -216,11 +217,23 @@ def split_video(
|
|
|
216
217
|
output: str,
|
|
217
218
|
show_output: bool,
|
|
218
219
|
ffmpeg_args: str,
|
|
220
|
+
expand: bool,
|
|
219
221
|
):
|
|
220
222
|
"""Handles the `split-video` command."""
|
|
221
223
|
del cuts # split-video only uses scenes.
|
|
222
224
|
assert context.video_stream is not None
|
|
223
225
|
|
|
226
|
+
if expand and scenes:
|
|
227
|
+
video_duration = context.video_stream.duration
|
|
228
|
+
if video_duration is None:
|
|
229
|
+
logger.warning("Cannot --expand: video duration is unavailable for this stream.")
|
|
230
|
+
else:
|
|
231
|
+
scenes = expand_scenes_to_bounds(
|
|
232
|
+
scenes,
|
|
233
|
+
start=context.video_stream.base_timecode,
|
|
234
|
+
end=video_duration,
|
|
235
|
+
)
|
|
236
|
+
|
|
224
237
|
if use_mkvmerge:
|
|
225
238
|
name_format = name_format.removesuffix("-$SCENE_NUMBER")
|
|
226
239
|
|
|
@@ -50,6 +50,14 @@ Lastly, to use a specific backend directly:
|
|
|
50
50
|
In both examples above, the resulting ``video`` can be used with
|
|
51
51
|
:meth:`SceneManager.detect_scenes() <scenedetect.scene_manager.SceneManager.detect_scenes>`.
|
|
52
52
|
|
|
53
|
+
Multiple videos can be opened as one continuous stream by passing a list of paths to
|
|
54
|
+
:func:`open_video`, which returns a
|
|
55
|
+
:class:`VideoStreamConcat <scenedetect.backends.concat.VideoStreamConcat>`:
|
|
56
|
+
|
|
57
|
+
.. code:: python
|
|
58
|
+
|
|
59
|
+
video = open_video(["part1.mp4", "part2.mp4"])
|
|
60
|
+
|
|
53
61
|
===============================================================
|
|
54
62
|
Devices / Cameras / Pipes
|
|
55
63
|
===============================================================
|
|
@@ -84,6 +92,7 @@ examples for details.
|
|
|
84
92
|
# - Nvidia VPF: https://developer.nvidia.com/blog/vpf-hardware-accelerated-video-processing-framework-in-python/
|
|
85
93
|
|
|
86
94
|
# OpenCV must be available at minimum.
|
|
95
|
+
from scenedetect.backends.concat import SourceSpan, VideoStreamConcat
|
|
87
96
|
from scenedetect.backends.opencv import VideoCaptureAdapter, VideoStreamCv2
|
|
88
97
|
|
|
89
98
|
try:
|