Skip to content

Commit d0da652

Browse files
committed
[detector] Remove is_processing_required
1 parent b7e99de commit d0da652

File tree

6 files changed

+46
-100
lines changed

6 files changed

+46
-100
lines changed

scenedetect/detectors/content_detector.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,6 @@ def __init__(
142142
def get_metrics(self):
143143
return ContentDetector.METRIC_KEYS
144144

145-
def is_processing_required(self, frame_num):
146-
return True
147-
148145
def _calculate_frame_score(self, frame_num: int, frame_img: numpy.ndarray) -> float:
149146
"""Calculate score representing relative amount of motion in `frame_img` compared to
150147
the last time the function was called (returns 0.0 on the first call)."""

scenedetect/detectors/hash_detector.py

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -82,25 +82,10 @@ def __init__(
8282
def get_metrics(self):
8383
return [self._metric_key]
8484

85-
def is_processing_required(self, frame_num):
86-
return True
87-
88-
def process_frame(self, frame_num, frame_img):
85+
def process_frame(self, frame_num: int, frame_img: numpy.ndarray):
8986
"""Similar to ContentDetector, but using a perceptual hashing algorithm
9087
to calculate a hash for each frame and then calculate a hash difference
91-
frame to frame.
92-
93-
Arguments:
94-
frame_num (int): Frame number of frame that is being passed.
95-
96-
frame_img (Optional[int]): Decoded frame image (numpy.ndarray) to perform scene
97-
detection on. Can be None *only* if the self.is_processing_required() method
98-
(inhereted from the base SceneDetector class) returns True.
99-
100-
Returns:
101-
ty.List[int]: List of frames where scene cuts have been detected. There may be 0
102-
or more frames in the list, and not necessarily the same as frame_num.
103-
"""
88+
frame to frame."""
10489

10590
cut_list = []
10691

scenedetect/detectors/histogram_detector.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,5 @@ def calculate_histogram(
160160

161161
return hist
162162

163-
def is_processing_required(self, frame_num: int) -> bool:
164-
return True
165-
166163
def get_metrics(self) -> ty.List[str]:
167164
return [self._metric_key]

scenedetect/scene_detector.py

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -50,29 +50,6 @@ class SceneDetector:
5050
"""Optional :class:`StatsManager <scenedetect.stats_manager.StatsManager>` to
5151
use for caching frame metrics to and from."""
5252

53-
# TODO(v1.0): Remove - this is a rarely used case for what is now a neglegible performance gain.
54-
def is_processing_required(self, frame_num: int) -> bool:
55-
"""[DEPRECATED] DO NOT USE
56-
57-
Test if all calculations for a given frame are already done.
58-
59-
Returns:
60-
False if the SceneDetector has assigned _metric_keys, and the
61-
stats_manager property is set to a valid StatsManager object containing
62-
the required frame metrics/calculations for the given frame - thus, not
63-
needing the frame to perform scene detection.
64-
65-
True otherwise (i.e. the frame_img passed to process_frame is required
66-
to be passed to process_frame for the given frame_num).
67-
68-
:meta private:
69-
"""
70-
metric_keys = self.get_metrics()
71-
return not metric_keys or not (
72-
self.stats_manager is not None
73-
and self.stats_manager.metrics_exist(frame_num, metric_keys)
74-
)
75-
7653
def stats_manager_required(self) -> bool:
7754
"""Stats Manager Required: Prototype indicating if detector requires stats.
7855

scenedetect/scene_manager.py

Lines changed: 40 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1369,53 +1369,47 @@ def _decode_thread(
13691369
# We don't do any kind of locking here since the worst-case of this being wrong
13701370
# is that we do some extra work, and this function should never mutate any data
13711371
# (all of which should be modified under the GIL).
1372-
# TODO(v1.0): This optimization should be removed as it is an uncommon use case and
1373-
# greatly increases the complexity of detection algorithms using it.
1374-
if self._is_processing_required(video.position._frame_num):
1375-
frame_im = video.read()
1376-
if frame_im is False:
1377-
break
1378-
# Verify the decoded frame size against the video container's reported
1379-
# resolution, and also verify that consecutive frames have the correct size.
1380-
decoded_size = (frame_im.shape[1], frame_im.shape[0])
1381-
if self._frame_size is None:
1382-
self._frame_size = decoded_size
1383-
if video.frame_size != decoded_size:
1384-
logger.warn(
1385-
f"WARNING: Decoded frame size ({decoded_size}) does not match "
1386-
f" video resolution {video.frame_size}, possible corrupt input."
1387-
)
1388-
elif self._frame_size != decoded_size:
1389-
self._frame_size_errors += 1
1390-
if self._frame_size_errors <= MAX_FRAME_SIZE_ERRORS:
1391-
logger.error(
1392-
f"ERROR: Frame at {str(video.position)} has incorrect size and "
1393-
f"cannot be processed: decoded size = {decoded_size}, "
1394-
f"expected = {self._frame_size}. Video may be corrupt."
1395-
)
1396-
if self._frame_size_errors == MAX_FRAME_SIZE_ERRORS:
1397-
logger.warn(
1398-
"WARNING: Too many errors emitted, skipping future messages."
1399-
)
1400-
# Skip processing frames that have an incorrect size.
1401-
continue
1402-
1403-
if self._crop:
1404-
(x0, y0, x1, y1) = self._crop
1405-
frame_im = frame_im[y0:y1, x0:x1]
1406-
1407-
if downscale_factor > 1.0:
1408-
frame_im = cv2.resize(
1409-
frame_im,
1410-
(
1411-
max(1, round(frame_im.shape[1] / downscale_factor)),
1412-
max(1, round(frame_im.shape[0] / downscale_factor)),
1413-
),
1414-
interpolation=self._interpolation.value,
1372+
frame_im = video.read()
1373+
if frame_im is False:
1374+
break
1375+
# Verify the decoded frame size against the video container's reported
1376+
# resolution, and also verify that consecutive frames have the correct size.
1377+
decoded_size = (frame_im.shape[1], frame_im.shape[0])
1378+
if self._frame_size is None:
1379+
self._frame_size = decoded_size
1380+
if video.frame_size != decoded_size:
1381+
logger.warn(
1382+
f"WARNING: Decoded frame size ({decoded_size}) does not match "
1383+
f" video resolution {video.frame_size}, possible corrupt input."
14151384
)
1416-
else:
1417-
if video.read(decode=False) is False:
1418-
break
1385+
elif self._frame_size != decoded_size:
1386+
self._frame_size_errors += 1
1387+
if self._frame_size_errors <= MAX_FRAME_SIZE_ERRORS:
1388+
logger.error(
1389+
f"ERROR: Frame at {str(video.position)} has incorrect size and "
1390+
f"cannot be processed: decoded size = {decoded_size}, "
1391+
f"expected = {self._frame_size}. Video may be corrupt."
1392+
)
1393+
if self._frame_size_errors == MAX_FRAME_SIZE_ERRORS:
1394+
logger.warn(
1395+
"WARNING: Too many errors emitted, skipping future messages."
1396+
)
1397+
# Skip processing frames that have an incorrect size.
1398+
continue
1399+
1400+
if self._crop:
1401+
(x0, y0, x1, y1) = self._crop
1402+
frame_im = frame_im[y0:y1, x0:x1]
1403+
1404+
if downscale_factor > 1.0:
1405+
frame_im = cv2.resize(
1406+
frame_im,
1407+
(
1408+
max(1, round(frame_im.shape[1] / downscale_factor)),
1409+
max(1, round(frame_im.shape[0] / downscale_factor)),
1410+
),
1411+
interpolation=self._interpolation.value,
1412+
)
14191413

14201414
# Set the start position now that we decoded at least the first frame.
14211415
if self._start_pos is None:
@@ -1505,9 +1499,3 @@ def get_event_list(self, base_timecode: ty.Optional[FrameTimecode] = None) -> Sc
15051499
# TODO(v0.7): Use the warnings module to turn this into a warning.
15061500
logger.error("`get_event_list()` is deprecated and will be removed in a future release.")
15071501
return self._get_event_list()
1508-
1509-
def _is_processing_required(self, frame_num: int) -> bool:
1510-
"""True if frame metrics not in StatsManager, False otherwise."""
1511-
if self.stats_manager is None:
1512-
return True
1513-
return all([detector.is_processing_required(frame_num) for detector in self._detector_list])

website/pages/changelog.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -659,8 +659,10 @@ Development
659659

660660
#### Breaking
661661

662-
- `FrameTimecode` fields `frame_num` and `framerate` are now read-only properties, construct a new `FrameTimecode` to change them
663-
- Remove `FrameTimecode.previous_frame()` method
662+
- `FrameTimecode` fields `frame_num` and `framerate` are now read-only properties, construct a new `FrameTimecode` to change them
663+
- Remove `FrameTimecode.previous_frame()` method
664+
- Remove `SceneDetector.is_processing_required()` method, already had no effect in v0.6 as part of deprecation
665+
- `SceneDetector` instances can now assume they always have frame data to process when `process_frame` is called
664666

665667
#### Deprecation
666668

0 commit comments

Comments
 (0)