scenedetect-core 0.7.1.dev0__py3-none-any.whl

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.
Files changed (38) hide show
  1. scenedetect/__init__.py +211 -0
  2. scenedetect/__main__.py +60 -0
  3. scenedetect/_cli/__init__.py +1866 -0
  4. scenedetect/_cli/commands.py +367 -0
  5. scenedetect/_cli/config.py +832 -0
  6. scenedetect/_cli/context.py +567 -0
  7. scenedetect/_cli/controller.py +223 -0
  8. scenedetect/_thirdparty/__init__.py +14 -0
  9. scenedetect/_thirdparty/simpletable.py +326 -0
  10. scenedetect/backends/__init__.py +125 -0
  11. scenedetect/backends/concat.py +387 -0
  12. scenedetect/backends/moviepy.py +295 -0
  13. scenedetect/backends/opencv.py +539 -0
  14. scenedetect/backends/pyav.py +427 -0
  15. scenedetect/common.py +837 -0
  16. scenedetect/detector.py +224 -0
  17. scenedetect/detectors/__init__.py +72 -0
  18. scenedetect/detectors/adaptive_detector.py +143 -0
  19. scenedetect/detectors/content_detector.py +243 -0
  20. scenedetect/detectors/hash_detector.py +151 -0
  21. scenedetect/detectors/histogram_detector.py +166 -0
  22. scenedetect/detectors/threshold_detector.py +191 -0
  23. scenedetect/detectors/transnet_v2.py +210 -0
  24. scenedetect/frame_timecode.py +22 -0
  25. scenedetect/output/__init__.py +660 -0
  26. scenedetect/output/image.py +535 -0
  27. scenedetect/output/video.py +389 -0
  28. scenedetect/platform.py +423 -0
  29. scenedetect/scene_detector.py +22 -0
  30. scenedetect/scene_manager.py +731 -0
  31. scenedetect/stats_manager.py +314 -0
  32. scenedetect/video_splitter.py +22 -0
  33. scenedetect/video_stream.py +222 -0
  34. scenedetect_core-0.7.1.dev0.dist-info/METADATA +106 -0
  35. scenedetect_core-0.7.1.dev0.dist-info/RECORD +38 -0
  36. scenedetect_core-0.7.1.dev0.dist-info/WHEEL +5 -0
  37. scenedetect_core-0.7.1.dev0.dist-info/licenses/LICENSE +28 -0
  38. scenedetect_core-0.7.1.dev0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,211 @@
1
+ #
2
+ # PySceneDetect: Python-Based Video Scene Detector
3
+ # -------------------------------------------------------------------
4
+ # [ Site: https://scenedetect.com ]
5
+ # [ Docs: https://scenedetect.com/docs/ ]
6
+ # [ Github: https://github.com/Breakthrough/PySceneDetect/ ]
7
+ #
8
+ # Copyright (C) 2016 Brandon Castellano <http://www.bcastell.com>.
9
+ # PySceneDetect is licensed under the BSD 3-Clause License; see the
10
+ # included LICENSE file, or visit one of the above pages for details.
11
+ #
12
+ """The ``scenedetect`` module comes with helper functions to simplify common use cases.
13
+ :func:`detect` can be used to perform scene detection on a video by path. :func:`open_video`
14
+ can be used to open a video for a
15
+ :class:`SceneManager <scenedetect.scene_manager.SceneManager>`.
16
+ """
17
+
18
+ from logging import getLogger
19
+
20
+ # OpenCV is a required package, but we don't have it as an explicit dependency since we
21
+ # need to support both opencv-python and opencv-python-headless. Include some additional
22
+ # context with the exception if this is the case.
23
+ try:
24
+ import cv2 as _ # availability check; raise a friendlier error if missing
25
+ except ModuleNotFoundError as ex:
26
+ raise ModuleNotFoundError(
27
+ "OpenCV could not be found, try installing opencv-python:\n\npip install opencv-python",
28
+ name="cv2",
29
+ ) from ex
30
+
31
+ # Commonly used classes/functions exported under the `scenedetect` namespace for brevity.
32
+ # Note that order of importants is important!
33
+ from scenedetect.platform import init_logger # noqa: I001
34
+ from scenedetect.common import (
35
+ FrameTimecode,
36
+ FrameRate,
37
+ SceneList,
38
+ CutList,
39
+ CropRegion,
40
+ TimecodePair,
41
+ TimecodeLike,
42
+ Interpolation,
43
+ )
44
+ from scenedetect.platform import StrPath
45
+ from scenedetect.video_stream import VideoStream, VideoOpenFailure
46
+ from scenedetect.output import (
47
+ save_images,
48
+ split_video_ffmpeg,
49
+ split_video_mkvmerge,
50
+ is_ffmpeg_available,
51
+ is_mkvmerge_available,
52
+ write_scene_list,
53
+ write_scene_list_html,
54
+ PathFormatter,
55
+ VideoMetadata,
56
+ SceneMetadata,
57
+ )
58
+ from scenedetect.detector import SceneDetector
59
+ from scenedetect.detectors import (
60
+ ContentDetector,
61
+ AdaptiveDetector,
62
+ ThresholdDetector,
63
+ HistogramDetector,
64
+ HashDetector,
65
+ )
66
+ from scenedetect.backends import (
67
+ AVAILABLE_BACKENDS,
68
+ VideoStreamCv2,
69
+ VideoStreamAv,
70
+ VideoStreamMoviePy,
71
+ VideoCaptureAdapter,
72
+ VideoStreamConcat,
73
+ SourceSpan,
74
+ )
75
+ from scenedetect.stats_manager import StatsManager, StatsFileCorrupt
76
+ from scenedetect.scene_manager import SceneManager
77
+
78
+ # Used for module identification and when printing version & about info
79
+ # (e.g. calling `scenedetect version` or `scenedetect about`).
80
+ __version__ = "0.7.1-dev0"
81
+
82
+ init_logger()
83
+ logger = getLogger("pyscenedetect")
84
+
85
+
86
+ def open_video(
87
+ path: "StrPath | list[StrPath] | tuple[StrPath, ...]",
88
+ frame_rate: FrameRate | None = None,
89
+ backend: str = "opencv",
90
+ framerate: float | None = None,
91
+ **kwargs,
92
+ ) -> VideoStream:
93
+ """Open a video at the given path. If `backend` is specified but not available on the current
94
+ system, OpenCV (`VideoStreamCv2`) will be used as a fallback.
95
+
96
+ Arguments:
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>`).
100
+ frame_rate: Overrides detected frame rate if set. Takes precedence over `framerate`.
101
+ backend: Name of specific backend to use, if possible. See
102
+ :data:`scenedetect.backends.AVAILABLE_BACKENDS` for backends available on the current
103
+ system. If the backend fails to open the video, OpenCV will be used as a fallback.
104
+ framerate: [DEPRECATED] Use `frame_rate` instead. Retained as a deprecated alias for
105
+ backwards compatibility; ignored when `frame_rate` is provided.
106
+ kwargs: Optional named arguments to pass to the specified `backend` constructor for
107
+ overriding backend-specific options.
108
+
109
+ Returns:
110
+ Backend object created with the specified video path.
111
+
112
+ Raises:
113
+ :class:`VideoOpenFailure`: Constructing the VideoStream fails. If multiple backends have
114
+ been attempted, the error from the first backend will be returned.
115
+ """
116
+ # TODO(https://scenedetect.com/issue/548): emit DeprecationWarning when `framerate=` is
117
+ # used, once internal callers and downstream users have had a release to migrate.
118
+ if frame_rate is None:
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)
124
+ last_error: Exception | None = None
125
+ # If `backend` is available, try to open the video at `path` using it.
126
+ if backend in AVAILABLE_BACKENDS:
127
+ backend_type = AVAILABLE_BACKENDS[backend]
128
+ try:
129
+ logger.debug("Opening video with %s...", backend_type.BACKEND_NAME)
130
+ return backend_type(path, frame_rate, **kwargs)
131
+ except VideoOpenFailure as ex:
132
+ logger.warning("Failed to open video with %s: %s", backend_type.BACKEND_NAME, str(ex))
133
+ if backend == VideoStreamCv2.BACKEND_NAME:
134
+ raise
135
+ last_error = ex
136
+ else:
137
+ logger.warning("Backend %s not available.", backend)
138
+ # Fallback to OpenCV if `backend` is unavailable, or specified backend failed to open `path`.
139
+ backend_type = VideoStreamCv2
140
+ logger.warning("Trying another backend: %s", backend_type.BACKEND_NAME)
141
+ try:
142
+ return backend_type(path, frame_rate)
143
+ except VideoOpenFailure as ex:
144
+ logger.debug("Failed to open video: %s", str(ex))
145
+ if last_error is None:
146
+ last_error = ex
147
+ # Propagate any exceptions raised from specified backend, instead of errors from the fallback.
148
+ assert last_error is not None
149
+ raise last_error
150
+
151
+
152
+ def detect(
153
+ video_path: "StrPath | list[StrPath] | tuple[StrPath, ...]",
154
+ detector: SceneDetector,
155
+ stats_file_path: StrPath | None = None,
156
+ show_progress: bool = False,
157
+ start_time: TimecodeLike | None = None,
158
+ end_time: TimecodeLike | None = None,
159
+ start_in_scene: bool = False,
160
+ backend: str = "opencv",
161
+ ) -> SceneList:
162
+ """Perform scene detection on a given video `path` using the specified `detector`.
163
+
164
+ Arguments:
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.
168
+ detector: A `SceneDetector` instance (see :mod:`scenedetect.detectors` for a full list
169
+ of detectors).
170
+ stats_file_path: Path to save per-frame metrics to for statistical analysis or to
171
+ determine a better threshold value.
172
+ show_progress: Show a progress bar with estimated time remaining. Default is False.
173
+ start_time: Starting point in video, in the form of a timecode ``HH:MM:SS[.nnn]`` (`str`),
174
+ number of seconds ``123.45`` (`float`), or number of frames ``200`` (`int`).
175
+ end_time: Starting point in video, in the form of a timecode ``HH:MM:SS[.nnn]`` (`str`),
176
+ number of seconds ``123.45`` (`float`), or number of frames ``200`` (`int`).
177
+ start_in_scene: Assume the video begins in a scene. This means that when detecting
178
+ fast cuts with `ContentDetector`, if no cuts are found, the resulting scene list
179
+ will contain a single scene spanning the entire video (instead of no scenes).
180
+ When detecting fades with `ThresholdDetector`, the beginning portion of the video
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.
186
+
187
+ Returns:
188
+ List of scenes as pairs of (start, end) :class:`FrameTimecode` objects.
189
+
190
+ Raises:
191
+ :class:`VideoOpenFailure`: `video_path` could not be opened.
192
+ :class:`StatsFileCorrupt`: `stats_file_path` is an invalid stats file
193
+ ValueError: `start_time` or `end_time` are incorrectly formatted.
194
+ TypeError: `start_time` or `end_time` are invalid types.
195
+ """
196
+ video = open_video(video_path, backend=backend)
197
+ if start_time is not None:
198
+ video.seek(FrameTimecode(start_time, video.frame_rate))
199
+ end_timecode = FrameTimecode(end_time, video.frame_rate) if end_time is not None else None
200
+ # To reduce memory consumption when not required, we only add a StatsManager if we
201
+ # need to save frame metrics to disk.
202
+ scene_manager = SceneManager(StatsManager() if stats_file_path else None)
203
+ scene_manager.add_detector(detector)
204
+ scene_manager.detect_scenes(
205
+ video=video,
206
+ show_progress=show_progress,
207
+ end_time=end_timecode,
208
+ )
209
+ if scene_manager.stats_manager is not None and stats_file_path is not None:
210
+ scene_manager.stats_manager.save_to_csv(csv_file=stats_file_path)
211
+ return scene_manager.get_scene_list(start_in_scene=start_in_scene)
@@ -0,0 +1,60 @@
1
+ #
2
+ # PySceneDetect: Python-Based Video Scene Detector
3
+ # -------------------------------------------------------------------
4
+ # [ Site: https://scenedetect.com ]
5
+ # [ Docs: https://scenedetect.com/docs/ ]
6
+ # [ Github: https://github.com/Breakthrough/PySceneDetect/ ]
7
+ #
8
+ # Copyright (C) 2016 Brandon Castellano <http://www.bcastell.com>.
9
+ # PySceneDetect is licensed under the BSD 3-Clause License; see the
10
+ # included LICENSE file, or visit one of the above pages for details.
11
+ #
12
+ """Entry point for PySceneDetect's command-line interface."""
13
+
14
+ import sys
15
+ from logging import getLogger
16
+
17
+ from scenedetect._cli import scenedetect
18
+ from scenedetect._cli.context import CliContext
19
+ from scenedetect._cli.controller import run_scenedetect
20
+ from scenedetect.platform import DEBUG_MODE, FakeTqdmLoggingRedirect, logging_redirect_tqdm
21
+
22
+
23
+ def main():
24
+ """PySceneDetect command-line interface (CLI) entry point."""
25
+ context = CliContext()
26
+ try:
27
+ # Process command line arguments and subcommands to initialize the context.
28
+ scenedetect.main(obj=context) # Parse CLI arguments with registered callbacks.
29
+ except SystemExit as exit:
30
+ help_command = any(arg in sys.argv for arg in ["-h", "--help"])
31
+ if help_command or exit.code != 0:
32
+ raise
33
+
34
+ # If we get here, processing the command line and loading the context worked. Let's run
35
+ # the controller if we didn't process any help requests.
36
+ logger = getLogger("pyscenedetect")
37
+ # Ensure log messages don't conflict with any progress bars. If we're in quiet mode, where
38
+ # no progress bars get created, we instead create a fake context manager. This is done here
39
+ # to avoid needing a separate context manager at each point a progress bar is created.
40
+ log_redirect = (
41
+ FakeTqdmLoggingRedirect() if context.quiet_mode else logging_redirect_tqdm(loggers=[logger])
42
+ )
43
+
44
+ with log_redirect:
45
+ try:
46
+ run_scenedetect(context)
47
+ except KeyboardInterrupt:
48
+ logger.info("Stopped.")
49
+ if DEBUG_MODE:
50
+ raise
51
+ raise SystemExit(1) from None
52
+ except BaseException as ex:
53
+ if DEBUG_MODE:
54
+ raise
55
+ logger.critical("ERROR: Unhandled exception:", exc_info=ex)
56
+ raise SystemExit(1) from ex
57
+
58
+
59
+ if __name__ == "__main__":
60
+ main()