remove frame extraction logic

This commit is contained in:
Josh Hawkins 2026-01-22 10:48:08 -06:00
parent a6c5f4a82b
commit db485ddafa
2 changed files with 39 additions and 118 deletions

View File

@ -165,9 +165,8 @@ async def latest_frame(
frame_processor.get_current_frame_time(camera_name) + retry_interval frame_processor.get_current_frame_time(camera_name) + retry_interval
): ):
last_frame_time = frame_processor.get_current_frame_time(camera_name) last_frame_time = frame_processor.get_current_frame_time(camera_name)
config: FrigateConfig = request.app.frigate_config
preview_path = get_most_recent_preview_frame( preview_path = get_most_recent_preview_frame(
camera_name, before=last_frame_time, ffmpeg_config=config.ffmpeg camera_name, before=last_frame_time
) )
if preview_path: if preview_path:

View File

@ -8,14 +8,13 @@ import subprocess as sp
import threading import threading
import time import time
from pathlib import Path from pathlib import Path
from typing import Any, Optional from typing import Any
import cv2 import cv2
import numpy as np import numpy as np
from peewee import DoesNotExist
from frigate.comms.inter_process import InterProcessRequestor from frigate.comms.inter_process import InterProcessRequestor
from frigate.config import CameraConfig, FfmpegConfig, RecordQualityEnum from frigate.config import CameraConfig, RecordQualityEnum
from frigate.const import CACHE_DIR, CLIPS_DIR, INSERT_PREVIEW, PREVIEW_FRAME_TYPE from frigate.const import CACHE_DIR, CLIPS_DIR, INSERT_PREVIEW, PREVIEW_FRAME_TYPE
from frigate.ffmpeg_presets import ( from frigate.ffmpeg_presets import (
FPS_VFR_PARAM, FPS_VFR_PARAM,
@ -24,12 +23,7 @@ from frigate.ffmpeg_presets import (
) )
from frigate.models import Previews from frigate.models import Previews
from frigate.track.object_processing import TrackedObject from frigate.track.object_processing import TrackedObject
from frigate.util.image import ( from frigate.util.image import copy_yuv_to_position, get_blank_yuv_frame, get_yuv_crop
copy_yuv_to_position,
get_blank_yuv_frame,
get_yuv_crop,
run_ffmpeg_snapshot,
)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -63,26 +57,11 @@ def get_cache_image_name(camera: str, frame_time: float) -> str:
) )
def get_most_recent_preview_frame( def get_most_recent_preview_frame(camera: str, before: float = None) -> str | None:
camera: str, before: float = None, ffmpeg_config: Optional[FfmpegConfig] = None """Get the most recent preview frame for a camera."""
) -> str | None:
"""Get the most recent preview frame for a camera.
First tries to find a cached preview webp frame. If none exists (e.g., they've been
cleaned up after preview video creation), attempts to extract the last frame from
the most recent preview video.
Args:
camera: Camera name
before: Optional timestamp to find frames before this time
ffmpeg_config: Optional ffmpeg configuration for extracting from video fallback
Returns:
Path to a preview frame image file, or None if not available
"""
if not os.path.exists(PREVIEW_CACHE_DIR): if not os.path.exists(PREVIEW_CACHE_DIR):
logger.debug(f"Preview cache directory does not exist: {PREVIEW_CACHE_DIR}") return None
else:
try: try:
# files are named preview_{camera}-{timestamp}.webp # files are named preview_{camera}-{timestamp}.webp
# we want the largest timestamp that is less than or equal to before # we want the largest timestamp that is less than or equal to before
@ -93,7 +72,9 @@ def get_most_recent_preview_frame(
and f.endswith(f".{PREVIEW_FRAME_TYPE}") and f.endswith(f".{PREVIEW_FRAME_TYPE}")
] ]
if preview_files: if not preview_files:
return None
# sort by timestamp in descending order # sort by timestamp in descending order
# filenames are like preview_front-1712345678.901234.webp # filenames are like preview_front-1712345678.901234.webp
preview_files.sort(reverse=True) preview_files.sort(reverse=True)
@ -114,69 +95,10 @@ def get_most_recent_preview_frame(
return os.path.join(PREVIEW_CACHE_DIR, file_name) return os.path.join(PREVIEW_CACHE_DIR, file_name)
except (ValueError, IndexError): except (ValueError, IndexError):
continue continue
return None
except Exception as e: except Exception as e:
logger.error(f"Error searching for cached preview frames: {e}") logger.error(f"Error searching for most recent preview frame: {e}")
# If no cached frames exist and ffmpeg_config is provided, try extracting from preview video
if ffmpeg_config is not None:
try:
logger.debug(
f"No cached preview frames found for {camera}, attempting to extract from preview video"
)
query = Previews.select().where(Previews.camera == camera)
if before is not None:
query = query.where(Previews.end_time <= before)
preview = query.order_by(Previews.end_time.desc()).limit(1).get()
if preview and os.path.exists(preview.path):
logger.debug(
f"Found preview video for {camera}: {preview.path} (duration: {preview.duration}s)"
)
# Extract the last frame from the video
# Use webp for consistency with cached frames
image_data, error_msg = run_ffmpeg_snapshot(
ffmpeg_config,
preview.path,
codec="webp",
seek_time=max(0, preview.duration - 0.1), # Seek to near the end
height=PREVIEW_HEIGHT,
timeout=10,
)
if image_data:
# Write to a temporary file in the cache directory
# Use timestamp from the preview end time
temp_frame_path = os.path.join(
PREVIEW_CACHE_DIR,
f"preview_{camera}-{preview.end_time}_from_video.{PREVIEW_FRAME_TYPE}",
)
with open(temp_frame_path, "wb") as f:
f.write(image_data)
logger.debug(
f"Successfully extracted last frame from preview video to {temp_frame_path}"
)
return temp_frame_path
else:
logger.warning(
f"Failed to extract frame from preview video {preview.path}: {error_msg}"
)
else:
if preview:
logger.warning(f"Preview video path does not exist: {preview.path}")
else:
logger.debug(f"No preview video found in database for {camera}")
except DoesNotExist:
logger.debug(f"No preview video found in database for {camera}")
except Exception as e:
logger.error(f"Error extracting frame from preview video: {e}")
return None return None