mirror of
https://github.com/blakeblackshear/frigate.git
synced 2024-11-21 19:07:46 +01:00
Handle in progress previews export and fix time check bug (#14930)
* Handle in progress previews and fix time check bug * Formatting
This commit is contained in:
parent
6c86827d3a
commit
9c20cd5f7b
@ -19,6 +19,7 @@ from frigate.record.export import (
|
|||||||
PlaybackSourceEnum,
|
PlaybackSourceEnum,
|
||||||
RecordingExporter,
|
RecordingExporter,
|
||||||
)
|
)
|
||||||
|
from frigate.util.builtin import is_current_hour
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -86,7 +87,7 @@ def export_recording(
|
|||||||
.count()
|
.count()
|
||||||
)
|
)
|
||||||
|
|
||||||
if previews_count <= 0:
|
if not is_current_hour(start_time) and previews_count <= 0:
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
content=(
|
content=(
|
||||||
{"success": False, "message": "No previews found for time range"}
|
{"success": False, "message": "No previews found for time range"}
|
||||||
|
@ -144,6 +144,9 @@ def output_frames(
|
|||||||
# check for any cameras that are currently offline
|
# check for any cameras that are currently offline
|
||||||
# and need to generate a preview
|
# and need to generate a preview
|
||||||
if generated_preview:
|
if generated_preview:
|
||||||
|
logger.debug(
|
||||||
|
"Checking for offline cameras because another camera generated a preview."
|
||||||
|
)
|
||||||
for camera, time in preview_write_times.copy().items():
|
for camera, time in preview_write_times.copy().items():
|
||||||
if time != 0 and frame_time - time > 10:
|
if time != 0 and frame_time - time > 10:
|
||||||
preview_recorders[camera].flag_offline(frame_time)
|
preview_recorders[camera].flag_offline(frame_time)
|
||||||
|
@ -27,6 +27,7 @@ from frigate.ffmpeg_presets import (
|
|||||||
parse_preset_hardware_acceleration_encode,
|
parse_preset_hardware_acceleration_encode,
|
||||||
)
|
)
|
||||||
from frigate.models import Export, Previews, Recordings
|
from frigate.models import Export, Previews, Recordings
|
||||||
|
from frigate.util.builtin import is_current_hour
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -235,6 +236,32 @@ class RecordingExporter(threading.Thread):
|
|||||||
|
|
||||||
def get_preview_export_command(self, video_path: str) -> list[str]:
|
def get_preview_export_command(self, video_path: str) -> list[str]:
|
||||||
playlist_lines = []
|
playlist_lines = []
|
||||||
|
codec = "-c copy"
|
||||||
|
|
||||||
|
if is_current_hour(self.start_time):
|
||||||
|
# get list of current preview frames
|
||||||
|
preview_dir = os.path.join(CACHE_DIR, "preview_frames")
|
||||||
|
file_start = f"preview_{self.camera}"
|
||||||
|
start_file = f"{file_start}-{self.start_time}.{PREVIEW_FRAME_TYPE}"
|
||||||
|
end_file = f"{file_start}-{self.end_time}.{PREVIEW_FRAME_TYPE}"
|
||||||
|
|
||||||
|
for file in sorted(os.listdir(preview_dir)):
|
||||||
|
if not file.startswith(file_start):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if file < start_file:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if file > end_file:
|
||||||
|
break
|
||||||
|
|
||||||
|
playlist_lines.append(f"file '{os.path.join(preview_dir, file)}'")
|
||||||
|
playlist_lines.append("duration 0.12")
|
||||||
|
|
||||||
|
if playlist_lines:
|
||||||
|
last_file = playlist_lines[-2]
|
||||||
|
playlist_lines.append(last_file)
|
||||||
|
codec = "-c:v libx264"
|
||||||
|
|
||||||
# get full set of previews
|
# get full set of previews
|
||||||
export_previews = (
|
export_previews = (
|
||||||
@ -277,7 +304,7 @@ class RecordingExporter(threading.Thread):
|
|||||||
|
|
||||||
if self.playback_factor == PlaybackFactorEnum.realtime:
|
if self.playback_factor == PlaybackFactorEnum.realtime:
|
||||||
ffmpeg_cmd = (
|
ffmpeg_cmd = (
|
||||||
f"{self.config.ffmpeg.ffmpeg_path} -hide_banner {ffmpeg_input} -c copy -movflags +faststart {video_path}"
|
f"{self.config.ffmpeg.ffmpeg_path} -hide_banner {ffmpeg_input} {codec} -movflags +faststart {video_path}"
|
||||||
).split(" ")
|
).split(" ")
|
||||||
elif self.playback_factor == PlaybackFactorEnum.timelapse_25x:
|
elif self.playback_factor == PlaybackFactorEnum.timelapse_25x:
|
||||||
ffmpeg_cmd = (
|
ffmpeg_cmd = (
|
||||||
|
@ -282,6 +282,17 @@ def get_tomorrow_at_time(hour: int) -> datetime.datetime:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def is_current_hour(timestamp: int) -> bool:
|
||||||
|
"""Returns if timestamp is in the current UTC hour."""
|
||||||
|
start_of_next_hour = (
|
||||||
|
datetime.datetime.now(datetime.timezone.utc).replace(
|
||||||
|
minute=0, second=0, microsecond=0
|
||||||
|
)
|
||||||
|
+ datetime.timedelta(hours=1)
|
||||||
|
).timestamp()
|
||||||
|
return timestamp < start_of_next_hour
|
||||||
|
|
||||||
|
|
||||||
def clear_and_unlink(file: Path, missing_ok: bool = True) -> None:
|
def clear_and_unlink(file: Path, missing_ok: bool = True) -> None:
|
||||||
"""clear file then unlink to avoid space retained by file descriptors."""
|
"""clear file then unlink to avoid space retained by file descriptors."""
|
||||||
if not missing_ok and not file.exists():
|
if not missing_ok and not file.exists():
|
||||||
|
Loading…
Reference in New Issue
Block a user