mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-08-02 00:52:17 +03:00
Merge remote-tracking branch 'origin/master' into dev
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
This commit is contained in:
+64
-1
@@ -4,13 +4,20 @@ import datetime
|
||||
import errno
|
||||
import logging
|
||||
import os
|
||||
import subprocess as sp
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
from typing import Iterable
|
||||
|
||||
from peewee import DatabaseError, chunked
|
||||
|
||||
from frigate.const import CLIPS_DIR, EXPORT_DIR, RECORD_DIR, THUMB_DIR
|
||||
from frigate.const import (
|
||||
CLIPS_DIR,
|
||||
DEFAULT_FFMPEG_VERSION,
|
||||
EXPORT_DIR,
|
||||
RECORD_DIR,
|
||||
THUMB_DIR,
|
||||
)
|
||||
from frigate.models import (
|
||||
Event,
|
||||
Export,
|
||||
@@ -26,6 +33,12 @@ logger = logging.getLogger(__name__)
|
||||
# Safety threshold - abort if more than 50% of files would be deleted
|
||||
SAFETY_THRESHOLD = 0.5
|
||||
|
||||
FFPROBE_PATH = (
|
||||
f"/usr/lib/ffmpeg/{DEFAULT_FFMPEG_VERSION}/bin/ffprobe"
|
||||
if DEFAULT_FFMPEG_VERSION
|
||||
else "ffprobe"
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class SyncResult:
|
||||
@@ -808,3 +821,53 @@ def sync_all_media(
|
||||
)
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def get_keyframe_before(path: str, offset_ms: int) -> int | None:
|
||||
"""Get the timestamp (ms) of the last keyframe at or before offset_ms.
|
||||
|
||||
Uses ffprobe packet index to read keyframe positions from the mp4 file.
|
||||
Returns None if ffprobe fails or no keyframe is found before the offset.
|
||||
"""
|
||||
try:
|
||||
result = sp.run(
|
||||
[
|
||||
FFPROBE_PATH,
|
||||
"-select_streams",
|
||||
"v:0",
|
||||
"-show_entries",
|
||||
"packet=pts_time,flags",
|
||||
"-of",
|
||||
"csv=p=0",
|
||||
"-loglevel",
|
||||
"error",
|
||||
path,
|
||||
],
|
||||
capture_output=True,
|
||||
timeout=5,
|
||||
)
|
||||
except (sp.TimeoutExpired, FileNotFoundError):
|
||||
return None
|
||||
|
||||
if result.returncode != 0:
|
||||
return None
|
||||
|
||||
offset_s = offset_ms / 1000.0
|
||||
best_ms = None
|
||||
for line in result.stdout.decode().strip().splitlines():
|
||||
parts = line.strip().split(",")
|
||||
if len(parts) != 2:
|
||||
continue
|
||||
ts_str, flags = parts
|
||||
if "K" not in flags:
|
||||
continue
|
||||
try:
|
||||
ts = float(ts_str)
|
||||
except ValueError:
|
||||
continue
|
||||
if ts <= offset_s:
|
||||
best_ms = int(ts * 1000)
|
||||
else:
|
||||
break
|
||||
|
||||
return best_ms
|
||||
|
||||
Reference in New Issue
Block a user