(context: CliContext)
| 103 | |
| 104 | |
| 105 | def _detect(context: CliContext) -> tuple[SceneList, CutList] | None: |
| 106 | perf_start_time = time.time() |
| 107 | assert context.scene_manager is not None |
| 108 | assert context.video_stream is not None |
| 109 | assert context.frame_skip is not None |
| 110 | |
| 111 | context.ensure_detector() |
| 112 | if context.start_time is not None: |
| 113 | logger.debug("Seeking to start time...") |
| 114 | try: |
| 115 | context.video_stream.seek(target=context.start_time) |
| 116 | except SeekError as ex: |
| 117 | logger.critical( |
| 118 | "Failed to seek to %s / frame %d: %s", |
| 119 | context.start_time.get_timecode(), |
| 120 | context.start_time.frame_num, |
| 121 | str(ex), |
| 122 | ) |
| 123 | return None |
| 124 | |
| 125 | num_frames = context.scene_manager.detect_scenes( |
| 126 | video=context.video_stream, |
| 127 | duration=context.duration, |
| 128 | end_time=context.end_time, |
| 129 | frame_skip=context.frame_skip, |
| 130 | show_progress=not context.quiet_mode, |
| 131 | ) |
| 132 | |
| 133 | # Handle case where video failure is most likely due to multiple audio tracks (#179). |
| 134 | # TODO(https://scenedetect.com/issues/380): Ensure this does not erroneusly fire. |
| 135 | if num_frames <= 0 and isinstance(context.video_stream, VideoStreamCv2): |
| 136 | logger.critical( |
| 137 | "Failed to read any frames from video file. This could be caused by the video" |
| 138 | " having multiple audio tracks. If so, try installing the PyAV backend:\n" |
| 139 | " pip install av\n" |
| 140 | "Or remove the audio tracks by running either:\n" |
| 141 | " ffmpeg -i input.mp4 -c copy -an output.mp4\n" |
| 142 | " mkvmerge -o output.mkv input.mp4\n" |
| 143 | "For details, see https://scenedetect.com/faq/" |
| 144 | ) |
| 145 | return None |
| 146 | |
| 147 | perf_duration = time.time() - perf_start_time |
| 148 | logger.info( |
| 149 | "Processed %d frames in %.1f seconds (average %.2f FPS).", |
| 150 | num_frames, |
| 151 | perf_duration, |
| 152 | float(num_frames) / perf_duration, |
| 153 | ) |
| 154 | |
| 155 | # Get list of detected cuts/scenes from the SceneManager to generate the required output |
| 156 | # files, based on the given commands (list-scenes, split-video, save-images, etc...). |
| 157 | cut_list = context.scene_manager.get_cut_list(show_warning=False) |
| 158 | scene_list = context.scene_manager.get_scene_list(start_in_scene=True) |
| 159 | |
| 160 | return scene_list, cut_list |
| 161 | |
| 162 |
no test coverage detected