diff --git a/docker/main/rootfs/usr/local/nginx/conf/nginx.conf b/docker/main/rootfs/usr/local/nginx/conf/nginx.conf index c55a58562..0dc57a26f 100644 --- a/docker/main/rootfs/usr/local/nginx/conf/nginx.conf +++ b/docker/main/rootfs/usr/local/nginx/conf/nginx.conf @@ -210,7 +210,7 @@ http { include proxy.conf; } - location ~* /api/.*\.(jpg|jpeg|png)$ { + location ~* /api/.*\.(jpg|jpeg|png|webp)$ { rewrite ^/api/(.*)$ $1 break; proxy_pass http://frigate_api; include proxy.conf; diff --git a/frigate/api/media.py b/frigate/api/media.py index 6e986af0b..2c8f37dc8 100644 --- a/frigate/api/media.py +++ b/frigate/api/media.py @@ -30,6 +30,7 @@ from frigate.const import ( CLIPS_DIR, EXPORT_DIR, MAX_SEGMENT_DURATION, + PREVIEW_FRAME_TYPE, RECORD_DIR, ) from frigate.models import Event, Previews, Recordings, Regions, ReviewSegment @@ -1173,8 +1174,8 @@ def preview_gif(camera_name: str, start_ts, end_ts, max_cache_age=2592000): # need to generate from existing images preview_dir = os.path.join(CACHE_DIR, "preview_frames") file_start = f"preview_{camera_name}" - start_file = f"{file_start}-{start_ts}.jpg" - end_file = f"{file_start}-{end_ts}.jpg" + start_file = f"{file_start}-{start_ts}.{PREVIEW_FRAME_TYPE}" + end_file = f"{file_start}-{end_ts}.{PREVIEW_FRAME_TYPE}" selected_previews = [] for file in sorted(os.listdir(preview_dir)): @@ -1258,8 +1259,9 @@ def review_preview(id: str): @MediaBp.route("/preview//thumbnail.jpg") +@MediaBp.route("/preview//thumbnail.webp") def preview_thumbnail(file_name: str): - """Get a thumbnail from the cached preview jpgs.""" + """Get a thumbnail from the cached preview frames.""" safe_file_name_current = secure_filename(file_name) preview_dir = os.path.join(CACHE_DIR, "preview_frames") diff --git a/frigate/api/preview.py b/frigate/api/preview.py index dd9e5d5a0..46d3d0e82 100644 --- a/frigate/api/preview.py +++ b/frigate/api/preview.py @@ -11,7 +11,7 @@ from flask import ( make_response, ) -from frigate.const import CACHE_DIR +from frigate.const import CACHE_DIR, PREVIEW_FRAME_TYPE from frigate.models import Previews logger = logging.getLogger(__name__) @@ -97,8 +97,8 @@ def get_preview_frames_from_cache(camera_name: str, start_ts, end_ts): """Get list of cached preview frames""" preview_dir = os.path.join(CACHE_DIR, "preview_frames") file_start = f"preview_{camera_name}" - start_file = f"{file_start}-{start_ts}.jpg" - end_file = f"{file_start}-{end_ts}.jpg" + start_file = f"{file_start}-{start_ts}.{PREVIEW_FRAME_TYPE}" + end_file = f"{file_start}-{end_ts}.{PREVIEW_FRAME_TYPE}" selected_previews = [] for file in sorted(os.listdir(preview_dir)): diff --git a/frigate/const.py b/frigate/const.py index 62a202c37..9b65fe5c9 100644 --- a/frigate/const.py +++ b/frigate/const.py @@ -57,6 +57,10 @@ DRIVER_AMD = "radeonsi" DRIVER_INTEL_i965 = "i965" DRIVER_INTEL_iHD = "iHD" +# Preview Values + +PREVIEW_FRAME_TYPE = "webp" + # Record Values CACHE_SEGMENT_FORMAT = "%Y%m%d%H%M%S%z" diff --git a/frigate/output/preview.py b/frigate/output/preview.py index 5fd7c5f29..370ac6cce 100644 --- a/frigate/output/preview.py +++ b/frigate/output/preview.py @@ -12,7 +12,7 @@ import numpy as np from frigate.comms.inter_process import InterProcessRequestor from frigate.config import CameraConfig, RecordQualityEnum -from frigate.const import CACHE_DIR, CLIPS_DIR, INSERT_PREVIEW +from frigate.const import CACHE_DIR, CLIPS_DIR, INSERT_PREVIEW, PREVIEW_FRAME_TYPE from frigate.ffmpeg_presets import ( FPS_VFR_PARAM, EncodeTypeEnum, @@ -42,12 +42,12 @@ def get_cache_image_name(camera: str, frame_time: float) -> str: """Get the image name in cache.""" return os.path.join( CACHE_DIR, - f"{FOLDER_PREVIEW_FRAMES}/preview_{camera}-{frame_time}.jpg", + f"{FOLDER_PREVIEW_FRAMES}/preview_{camera}-{frame_time}.{PREVIEW_FRAME_TYPE}", ) class FFMpegConverter(threading.Thread): - """Convert a list of jpg frames into a vfr mp4.""" + """Convert a list of still frames into a vfr mp4.""" def __init__( self, @@ -176,7 +176,7 @@ class PreviewRecorder: ) file_start = f"preview_{config.name}" - start_file = f"{file_start}-{start_ts}.jpg" + start_file = f"{file_start}-{start_ts}.webp" for file in sorted(os.listdir(os.path.join(CACHE_DIR, FOLDER_PREVIEW_FRAMES))): if not file.startswith(file_start): @@ -242,12 +242,7 @@ class PreviewRecorder: small_frame, cv2.COLOR_YUV2BGR_I420, ) - _, jpg = cv2.imencode(".jpg", small_frame) - with open( - get_cache_image_name(self.config.name, frame_time), - "wb", - ) as j: - j.write(jpg.tobytes()) + cv2.imwrite(get_cache_image_name(self.config.name, frame_time), small_frame, [int(cv2.IMWRITE_WEBP_QUALITY), 80]) def write_data( self,