Save previews when restarting (#10261)

This commit is contained in:
Nicolas Mowen 2024-03-05 12:56:38 -07:00 committed by GitHub
parent a174d0000f
commit 7be2923d2d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 48 additions and 7 deletions

View File

@ -2,6 +2,8 @@
import logging import logging
import multiprocessing as mp import multiprocessing as mp
import os
import shutil
import signal import signal
import threading import threading
from typing import Optional from typing import Optional
@ -18,6 +20,7 @@ from ws4py.server.wsgiutils import WebSocketWSGIApplication
from frigate.comms.detections_updater import DetectionSubscriber, DetectionTypeEnum from frigate.comms.detections_updater import DetectionSubscriber, DetectionTypeEnum
from frigate.comms.ws import WebSocket from frigate.comms.ws import WebSocket
from frigate.config import FrigateConfig from frigate.config import FrigateConfig
from frigate.const import CACHE_DIR, CLIPS_DIR
from frigate.output.birdseye import Birdseye from frigate.output.birdseye import Birdseye
from frigate.output.camera import JsmpegCamera from frigate.output.camera import JsmpegCamera
from frigate.output.preview import PreviewRecorder from frigate.output.preview import PreviewRecorder
@ -61,6 +64,8 @@ def output_frames(
birdseye: Optional[Birdseye] = None birdseye: Optional[Birdseye] = None
preview_recorders: dict[str, PreviewRecorder] = {} preview_recorders: dict[str, PreviewRecorder] = {}
move_preview_frames("cache")
for camera, cam_config in config.cameras.items(): for camera, cam_config in config.cameras.items():
if not cam_config.enabled: if not cam_config.enabled:
continue continue
@ -151,6 +156,8 @@ def output_frames(
for preview in preview_recorders.values(): for preview in preview_recorders.values():
preview.stop() preview.stop()
move_preview_frames("clips")
if birdseye is not None: if birdseye is not None:
birdseye.stop() birdseye.stop()
@ -160,3 +167,16 @@ def output_frames(
websocket_server.shutdown() websocket_server.shutdown()
websocket_thread.join() websocket_thread.join()
logger.info("exiting output process...") logger.info("exiting output process...")
def move_preview_frames(loc: str):
preview_holdover = os.path.join(CLIPS_DIR, "preview_restart_cache")
preview_cache = os.path.join(CACHE_DIR, "preview_frames")
if loc == "clips":
shutil.move(preview_cache, preview_holdover)
elif loc == "cache":
if not os.path.exists(preview_holdover):
return
shutil.move(preview_holdover, preview_cache)

View File

@ -3,7 +3,6 @@
import datetime import datetime
import logging import logging
import os import os
import shutil
import subprocess as sp import subprocess as sp
import threading import threading
from pathlib import Path from pathlib import Path
@ -26,6 +25,7 @@ from frigate.util.image import copy_yuv_to_position, get_yuv_crop
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
FOLDER_PREVIEW_FRAMES = "preview_frames" FOLDER_PREVIEW_FRAMES = "preview_frames"
PREVIEW_CACHE_DIR = os.path.join(CACHE_DIR, FOLDER_PREVIEW_FRAMES)
PREVIEW_SEGMENT_DURATION = 3600 # one hour PREVIEW_SEGMENT_DURATION = 3600 # one hour
# important to have lower keyframe to maintain scrubbing performance # important to have lower keyframe to maintain scrubbing performance
PREVIEW_KEYFRAME_INTERVAL = 60 PREVIEW_KEYFRAME_INTERVAL = 60
@ -163,11 +163,37 @@ class PreviewRecorder:
.timestamp() .timestamp()
) )
Path(os.path.join(CACHE_DIR, "preview_frames")).mkdir(exist_ok=True) Path(PREVIEW_CACHE_DIR).mkdir(exist_ok=True)
Path(os.path.join(CLIPS_DIR, f"previews/{config.name}")).mkdir( Path(os.path.join(CLIPS_DIR, f"previews/{config.name}")).mkdir(
parents=True, exist_ok=True parents=True, exist_ok=True
) )
# check for existing items in cache
start_ts = (
datetime.datetime.now()
.replace(minute=0, second=0, microsecond=0)
.timestamp()
)
file_start = f"preview_{config.name}"
start_file = f"{file_start}-{start_ts}.jpg"
for file in sorted(os.listdir(os.path.join(CACHE_DIR, FOLDER_PREVIEW_FRAMES))):
if not file.startswith(file_start):
continue
if file < start_file:
os.unlink(os.path.join(PREVIEW_CACHE_DIR, file))
continue
ts = float(file.split("-")[1][:-4])
if self.start_time == 0:
self.start_time = ts
self.last_output_time = ts
self.output_frames.append(ts)
def should_write_frame( def should_write_frame(
self, self,
current_tracked_objects: list[dict[str, any]], current_tracked_objects: list[dict[str, any]],
@ -269,11 +295,6 @@ class PreviewRecorder:
self.write_frame_to_cache(frame_time, frame) self.write_frame_to_cache(frame_time, frame)
def stop(self) -> None: def stop(self) -> None:
try:
shutil.rmtree(os.path.join(CACHE_DIR, FOLDER_PREVIEW_FRAMES))
except FileNotFoundError:
pass
self.requestor.stop() self.requestor.stop()