Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

detect_scenes seems to fail when used with callback #416

Open
poke1024 opened this issue Sep 2, 2024 · 2 comments · May be fixed by #420
Open

detect_scenes seems to fail when used with callback #416

poke1024 opened this issue Sep 2, 2024 · 2 comments · May be fixed by #420
Labels
Milestone

Comments

@poke1024
Copy link

poke1024 commented Sep 2, 2024

Description:

After running for about 1/3 of the video, the code throws the following unexpected exception. The same run works fine if the callback on detect_scenes is removed.

---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
Cell In[20], line 9
      6 def on_new_scene(frame_img: np.ndarray, frame_num: int):
      7     print(frame_num, video.duration.get_frames())
----> 9 scene_manager.detect_scenes(video, callback=on_new_scene)
     11 scene_manager.get_scene_list()

File ~/anaconda3/envs/jupyter/lib/python3.10/site-packages/scenedetect/scene_manager.py:889, in SceneManager.detect_scenes(self, video, duration, end_time, frame_skip, show_progress, callback, frame_source)
    887 if not next_frame is None:
    888     frame_im = next_frame
--> 889 new_cuts = self._process_frame(position.frame_num, frame_im, callback)
    890 if progress_bar is not None:
    891     if new_cuts:

File ~/anaconda3/envs/jupyter/lib/python3.10/site-packages/scenedetect/scene_manager.py:762, in SceneManager._process_frame(self, frame_num, frame_im, callback)
    760         for cut_frame_num in cuts:
    761             buffer_index = cut_frame_num - (frame_num + 1)
--> 762             callback(self._frame_buffer[buffer_index], cut_frame_num)
    763 for detector in self._sparse_detector_list:
    764     events = detector.process_frame(frame_num, frame_im)

IndexError: list index out of range

Example:

Include code samples that demonstrate the issue:

import scenedetect
import numpy as np

scene_manager = scenedetect.SceneManager()
scene_manager.add_detector(scenedetect.ContentDetector())

def on_new_scene(frame_img: np.ndarray, frame_num: int):
    print(frame_num, video.duration.get_frames())

scene_manager.detect_scenes(video, callback=on_new_scene)

scene_manager.get_scene_list()

Environment:

[PySceneDetect] PySceneDetect 0.6.4

System Info
------------------------------------------------------------
OS           Linux-5.15.0-119-generic-x86_64-with-glibc2.35
Python       3.10.14

Packages
------------------------------------------------------------
av           12.0.0
click        8.1.7
cv2          4.9.0
moviepy      Not Installed
numpy        1.26.4
platformdirs 3.10.0
scenedetect  0.6.4
tqdm         4.66.2

Tools
------------------------------------------------------------
ffmpeg       4.3
mkvmerge     Not Installed

Media/Files:

I cannot share the video file, but it is similar to this one: https://www.youtube.com/watch?app=desktop&v=2JIfwsv28Es

@Breakthrough Breakthrough added this to the 0.6.5 milestone Sep 3, 2024
@Breakthrough
Copy link
Owner

Thanks for sharing this, there's definitely a bug here. Will look into this as soon as possible.

I suspect the fix will be closely tied with resolving #408.

@Breakthrough
Copy link
Owner

Sorry this is unrelated to that actually. The issue is that with the new flash filter, ContentDetector isn't reporting the correct event buffer size. Will have this fixed for the next release, sorry for the troubles. In the meantime here's a few workarounds.

Workarounds

Use AdaptiveDetector instead:

import scenedetect
import numpy as np

scene_manager = scenedetect.SceneManager()
scene_manager.add_detector(scenedetect.AdaptiveDetector())

def on_new_scene(frame_img: np.ndarray, frame_num: int):
    print(frame_num, video.duration.get_frames())

scene_manager.detect_scenes(video, callback=on_new_scene)

scene_manager.get_scene_list()

Set flash filter mode to SUPPRESS:

import scenedetect
from scenedetect.scene_detector import FlashFilter
import numpy as np

scene_manager = scenedetect.SceneManager()
scene_manager.add_detector(scenedetect.ContentDetector(filter_mode=FlashFilter.Mode.SUPPRESS))

def on_new_scene(frame_img: np.ndarray, frame_num: int):
    print(frame_num, video.duration.get_frames())

scene_manager.detect_scenes(video, callback=on_new_scene)

scene_manager.get_scene_list()

Root Cause

This new filter was added as part of #35. The underlying issue is because ContentDetector doesn't override the event_buffer_length property, but this is required with the new filter mode.

Thanks for the report!

Breakthrough added a commit that referenced this issue Sep 8, 2024
With the new flash filter, cuts may be placed behind the current frame.

This is similar to AdaptiveDetector, but when the new filter was landed,
the max look behind property of the detector wasn't updated. Fixes #416.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants