scenedetect-headless 0.7__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 +196 -0
  2. scenedetect/__main__.py +60 -0
  3. scenedetect/_cli/__init__.py +1855 -0
  4. scenedetect/_cli/commands.py +354 -0
  5. scenedetect/_cli/config.py +831 -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 +116 -0
  11. scenedetect/backends/moviepy.py +295 -0
  12. scenedetect/backends/opencv.py +538 -0
  13. scenedetect/backends/pyav.py +386 -0
  14. scenedetect/common.py +780 -0
  15. scenedetect/detector.py +224 -0
  16. scenedetect/detectors/__init__.py +72 -0
  17. scenedetect/detectors/adaptive_detector.py +143 -0
  18. scenedetect/detectors/content_detector.py +243 -0
  19. scenedetect/detectors/hash_detector.py +151 -0
  20. scenedetect/detectors/histogram_detector.py +172 -0
  21. scenedetect/detectors/threshold_detector.py +191 -0
  22. scenedetect/detectors/transnet_v2.py +210 -0
  23. scenedetect/frame_timecode.py +22 -0
  24. scenedetect/output/__init__.py +660 -0
  25. scenedetect/output/image.py +535 -0
  26. scenedetect/output/video.py +389 -0
  27. scenedetect/platform.py +410 -0
  28. scenedetect/scene_detector.py +22 -0
  29. scenedetect/scene_manager.py +703 -0
  30. scenedetect/stats_manager.py +314 -0
  31. scenedetect/video_splitter.py +22 -0
  32. scenedetect/video_stream.py +212 -0
  33. scenedetect_headless-0.7.dist-info/METADATA +99 -0
  34. scenedetect_headless-0.7.dist-info/RECORD +38 -0
  35. scenedetect_headless-0.7.dist-info/WHEEL +5 -0
  36. scenedetect_headless-0.7.dist-info/entry_points.txt +2 -0
  37. scenedetect_headless-0.7.dist-info/licenses/LICENSE +28 -0
  38. scenedetect_headless-0.7.dist-info/top_level.txt +1 -0
@@ -0,0 +1,196 @@
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
+ )
73
+ from scenedetect.stats_manager import StatsManager, StatsFileCorrupt
74
+ from scenedetect.scene_manager import SceneManager
75
+
76
+ # Used for module identification and when printing version & about info
77
+ # (e.g. calling `scenedetect version` or `scenedetect about`).
78
+ __version__ = "0.7"
79
+
80
+ init_logger()
81
+ logger = getLogger("pyscenedetect")
82
+
83
+
84
+ def open_video(
85
+ path: StrPath,
86
+ frame_rate: FrameRate | None = None,
87
+ backend: str = "opencv",
88
+ framerate: float | None = None,
89
+ **kwargs,
90
+ ) -> VideoStream:
91
+ """Open a video at the given path. If `backend` is specified but not available on the current
92
+ system, OpenCV (`VideoStreamCv2`) will be used as a fallback.
93
+
94
+ Arguments:
95
+ path: Path to video file to open.
96
+ frame_rate: Overrides detected frame rate if set. Takes precedence over `framerate`.
97
+ backend: Name of specific backend to use, if possible. See
98
+ :data:`scenedetect.backends.AVAILABLE_BACKENDS` for backends available on the current
99
+ system. If the backend fails to open the video, OpenCV will be used as a fallback.
100
+ framerate: [DEPRECATED] Use `frame_rate` instead. Retained as a deprecated alias for
101
+ backwards compatibility; ignored when `frame_rate` is provided.
102
+ kwargs: Optional named arguments to pass to the specified `backend` constructor for
103
+ overriding backend-specific options.
104
+
105
+ Returns:
106
+ Backend object created with the specified video path.
107
+
108
+ Raises:
109
+ :class:`VideoOpenFailure`: Constructing the VideoStream fails. If multiple backends have
110
+ been attempted, the error from the first backend will be returned.
111
+ """
112
+ # TODO(https://scenedetect.com/issue/548): emit DeprecationWarning when `framerate=` is
113
+ # used, once internal callers and downstream users have had a release to migrate.
114
+ if frame_rate is None:
115
+ frame_rate = framerate
116
+ last_error: Exception | None = None
117
+ # If `backend` is available, try to open the video at `path` using it.
118
+ if backend in AVAILABLE_BACKENDS:
119
+ backend_type = AVAILABLE_BACKENDS[backend]
120
+ try:
121
+ logger.debug("Opening video with %s...", backend_type.BACKEND_NAME)
122
+ return backend_type(path, frame_rate, **kwargs)
123
+ except VideoOpenFailure as ex:
124
+ logger.warning("Failed to open video with %s: %s", backend_type.BACKEND_NAME, str(ex))
125
+ if backend == VideoStreamCv2.BACKEND_NAME:
126
+ raise
127
+ last_error = ex
128
+ else:
129
+ logger.warning("Backend %s not available.", backend)
130
+ # Fallback to OpenCV if `backend` is unavailable, or specified backend failed to open `path`.
131
+ backend_type = VideoStreamCv2
132
+ logger.warning("Trying another backend: %s", backend_type.BACKEND_NAME)
133
+ try:
134
+ return backend_type(path, frame_rate)
135
+ except VideoOpenFailure as ex:
136
+ logger.debug("Failed to open video: %s", str(ex))
137
+ if last_error is None:
138
+ last_error = ex
139
+ # Propagate any exceptions raised from specified backend, instead of errors from the fallback.
140
+ assert last_error is not None
141
+ raise last_error
142
+
143
+
144
+ def detect(
145
+ video_path: StrPath,
146
+ detector: SceneDetector,
147
+ stats_file_path: StrPath | None = None,
148
+ show_progress: bool = False,
149
+ start_time: TimecodeLike | None = None,
150
+ end_time: TimecodeLike | None = None,
151
+ start_in_scene: bool = False,
152
+ ) -> SceneList:
153
+ """Perform scene detection on a given video `path` using the specified `detector`.
154
+
155
+ Arguments:
156
+ video_path: Path to input video (absolute or relative to working directory).
157
+ detector: A `SceneDetector` instance (see :mod:`scenedetect.detectors` for a full list
158
+ of detectors).
159
+ stats_file_path: Path to save per-frame metrics to for statistical analysis or to
160
+ determine a better threshold value.
161
+ show_progress: Show a progress bar with estimated time remaining. Default is False.
162
+ start_time: Starting point in video, in the form of a timecode ``HH:MM:SS[.nnn]`` (`str`),
163
+ number of seconds ``123.45`` (`float`), or number of frames ``200`` (`int`).
164
+ end_time: Starting point in video, in the form of a timecode ``HH:MM:SS[.nnn]`` (`str`),
165
+ number of seconds ``123.45`` (`float`), or number of frames ``200`` (`int`).
166
+ start_in_scene: Assume the video begins in a scene. This means that when detecting
167
+ fast cuts with `ContentDetector`, if no cuts are found, the resulting scene list
168
+ will contain a single scene spanning the entire video (instead of no scenes).
169
+ When detecting fades with `ThresholdDetector`, the beginning portion of the video
170
+ will always be included until the first fade-out event is detected.
171
+
172
+ Returns:
173
+ List of scenes as pairs of (start, end) :class:`FrameTimecode` objects.
174
+
175
+ Raises:
176
+ :class:`VideoOpenFailure`: `video_path` could not be opened.
177
+ :class:`StatsFileCorrupt`: `stats_file_path` is an invalid stats file
178
+ ValueError: `start_time` or `end_time` are incorrectly formatted.
179
+ TypeError: `start_time` or `end_time` are invalid types.
180
+ """
181
+ video = open_video(video_path)
182
+ if start_time is not None:
183
+ video.seek(FrameTimecode(start_time, video.frame_rate))
184
+ end_timecode = FrameTimecode(end_time, video.frame_rate) if end_time is not None else None
185
+ # To reduce memory consumption when not required, we only add a StatsManager if we
186
+ # need to save frame metrics to disk.
187
+ scene_manager = SceneManager(StatsManager() if stats_file_path else None)
188
+ scene_manager.add_detector(detector)
189
+ scene_manager.detect_scenes(
190
+ video=video,
191
+ show_progress=show_progress,
192
+ end_time=end_timecode,
193
+ )
194
+ if scene_manager.stats_manager is not None and stats_file_path is not None:
195
+ scene_manager.stats_manager.save_to_csv(csv_file=stats_file_path)
196
+ 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()