forked from Github/frigate
Compare commits
7 Commits
v0.10.0-be
...
v0.10.0-be
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a3301e0347 | ||
|
|
3d556cc2cb | ||
|
|
585efe1a0f | ||
|
|
c7d47439dd | ||
|
|
19a6978228 | ||
|
|
1ebb8a54bf | ||
|
|
ae968044d6 |
@@ -40,10 +40,12 @@ class MotionDetector:
|
||||
# Improve contrast
|
||||
minval = np.percentile(resized_frame, 4)
|
||||
maxval = np.percentile(resized_frame, 96)
|
||||
resized_frame = np.clip(resized_frame, minval, maxval)
|
||||
resized_frame = (((resized_frame - minval) / (maxval - minval)) * 255).astype(
|
||||
np.uint8
|
||||
)
|
||||
# don't adjust if the image is a single color
|
||||
if minval < maxval:
|
||||
resized_frame = np.clip(resized_frame, minval, maxval)
|
||||
resized_frame = (
|
||||
((resized_frame - minval) / (maxval - minval)) * 255
|
||||
).astype(np.uint8)
|
||||
|
||||
# mask frame
|
||||
resized_frame[self.mask] = [255]
|
||||
|
||||
@@ -45,6 +45,8 @@ class RecordingMaintainer(threading.Thread):
|
||||
self.name = "recording_maint"
|
||||
self.config = config
|
||||
self.stop_event = stop_event
|
||||
self.first_pass = True
|
||||
self.end_time_cache = {}
|
||||
|
||||
def move_files(self):
|
||||
cache_files = [
|
||||
@@ -87,19 +89,18 @@ class RecordingMaintainer(threading.Thread):
|
||||
}
|
||||
)
|
||||
|
||||
# delete all cached files past the most recent 2
|
||||
# delete all cached files past the most recent 5
|
||||
keep_count = 5
|
||||
for camera in grouped_recordings.keys():
|
||||
if len(grouped_recordings[camera]) > 2:
|
||||
logger.warning(
|
||||
"Proactively cleaning cache. Your recordings disk may be too slow."
|
||||
)
|
||||
if len(grouped_recordings[camera]) > keep_count:
|
||||
sorted_recordings = sorted(
|
||||
grouped_recordings[camera], key=lambda i: i["start_time"]
|
||||
)
|
||||
to_remove = sorted_recordings[:-2]
|
||||
to_remove = sorted_recordings[:-keep_count]
|
||||
for f in to_remove:
|
||||
Path(f["cache_path"]).unlink(missing_ok=True)
|
||||
grouped_recordings[camera] = sorted_recordings[-2:]
|
||||
self.end_time_cache.pop(f["cache_path"], None)
|
||||
grouped_recordings[camera] = sorted_recordings[-keep_count:]
|
||||
|
||||
for camera, recordings in grouped_recordings.items():
|
||||
# get all events with the end time after the start of the oldest cache file
|
||||
@@ -124,26 +125,32 @@ class RecordingMaintainer(threading.Thread):
|
||||
or not self.config.cameras[camera].record.enabled
|
||||
):
|
||||
Path(cache_path).unlink(missing_ok=True)
|
||||
self.end_time_cache.pop(cache_path, None)
|
||||
continue
|
||||
|
||||
ffprobe_cmd = [
|
||||
"ffprobe",
|
||||
"-v",
|
||||
"error",
|
||||
"-show_entries",
|
||||
"format=duration",
|
||||
"-of",
|
||||
"default=noprint_wrappers=1:nokey=1",
|
||||
f"{cache_path}",
|
||||
]
|
||||
p = sp.run(ffprobe_cmd, capture_output=True)
|
||||
if p.returncode == 0:
|
||||
duration = float(p.stdout.decode().strip())
|
||||
end_time = start_time + datetime.timedelta(seconds=duration)
|
||||
if cache_path in self.end_time_cache:
|
||||
end_time = self.end_time_cache[cache_path]
|
||||
else:
|
||||
logger.warning(f"Discarding a corrupt recording segment: {f}")
|
||||
Path(cache_path).unlink(missing_ok=True)
|
||||
continue
|
||||
ffprobe_cmd = [
|
||||
"ffprobe",
|
||||
"-v",
|
||||
"error",
|
||||
"-show_entries",
|
||||
"format=duration",
|
||||
"-of",
|
||||
"default=noprint_wrappers=1:nokey=1",
|
||||
f"{cache_path}",
|
||||
]
|
||||
p = sp.run(ffprobe_cmd, capture_output=True)
|
||||
if p.returncode == 0:
|
||||
duration = float(p.stdout.decode().strip())
|
||||
self.end_time_cache[
|
||||
cache_path
|
||||
] = end_time = start_time + datetime.timedelta(seconds=duration)
|
||||
else:
|
||||
logger.warning(f"Discarding a corrupt recording segment: {f}")
|
||||
Path(cache_path).unlink(missing_ok=True)
|
||||
continue
|
||||
|
||||
# if cached file's start_time is earlier than the retain_days for the camera
|
||||
if start_time <= (
|
||||
@@ -158,7 +165,7 @@ class RecordingMaintainer(threading.Thread):
|
||||
overlaps = False
|
||||
for event in events:
|
||||
# if the event starts in the future, stop checking events
|
||||
# and let this recording segment expire
|
||||
# and remove this segment
|
||||
if event.start_time > end_time.timestamp():
|
||||
overlaps = False
|
||||
break
|
||||
@@ -218,6 +225,9 @@ class RecordingMaintainer(threading.Thread):
|
||||
Path(cache_path).unlink(missing_ok=True)
|
||||
logger.error(e)
|
||||
|
||||
# clear end_time cache
|
||||
self.end_time_cache.pop(cache_path, None)
|
||||
|
||||
def run(self):
|
||||
# Check for new files every 5 seconds
|
||||
wait_time = 5
|
||||
@@ -230,7 +240,14 @@ class RecordingMaintainer(threading.Thread):
|
||||
"Error occurred when attempting to maintain recording cache"
|
||||
)
|
||||
logger.error(e)
|
||||
wait_time = max(0, 5 - (datetime.datetime.now().timestamp() - run_start))
|
||||
duration = datetime.datetime.now().timestamp() - run_start
|
||||
wait_time = max(0, 5 - duration)
|
||||
if wait_time == 0 and not self.first_pass:
|
||||
logger.warning(
|
||||
"Cache is taking longer than 5 seconds to clear. Your recordings disk may be too slow."
|
||||
)
|
||||
if self.first_pass:
|
||||
self.first_pass = False
|
||||
|
||||
logger.info(f"Exiting recording maintenance...")
|
||||
|
||||
|
||||
@@ -75,25 +75,7 @@ def filtered(obj, objects_to_track, object_filters):
|
||||
|
||||
|
||||
def create_tensor_input(frame, model_shape, region):
|
||||
# TODO: is it faster to just convert grayscale to RGB? or repeat dimensions with numpy?
|
||||
height = frame.shape[0] // 3 * 2
|
||||
width = frame.shape[1]
|
||||
|
||||
# get the crop box if the region extends beyond the frame
|
||||
crop_x1 = max(0, region[0])
|
||||
crop_y1 = max(0, region[1])
|
||||
crop_x2 = min(width, region[2])
|
||||
crop_y2 = min(height, region[3])
|
||||
|
||||
size = region[3] - region[1]
|
||||
cropped_frame = np.zeros((size, size), np.uint8)
|
||||
|
||||
cropped_frame[
|
||||
0 : crop_y2 - crop_y1,
|
||||
0 : crop_x2 - crop_x1,
|
||||
] = frame[crop_y1:crop_y2, crop_x1:crop_x2]
|
||||
|
||||
cropped_frame = np.repeat(np.expand_dims(cropped_frame, -1), 3, 2)
|
||||
cropped_frame = yuv_region_2_rgb(frame, region)
|
||||
|
||||
# Resize to 300x300 if needed
|
||||
if cropped_frame.shape != (model_shape[0], model_shape[1], 3):
|
||||
|
||||
Reference in New Issue
Block a user