Use recording duration for keyFrameDurations

This commit is contained in:
Justin Wong 2022-08-24 23:41:11 +08:00
parent 139e1c57df
commit 314e05b5c5
2 changed files with 17 additions and 29 deletions

View File

@ -28,7 +28,7 @@ from playhouse.shortcuts import model_to_dict
from frigate.const import CLIPS_DIR
from frigate.models import Event, Recordings
from frigate.stats import stats_snapshot
from frigate.util import get_keyframe_timestamps_and_adjusted_offset
from frigate.util import get_adjusted_offset
from frigate.version import VERSION
logger = logging.getLogger(__name__)
@ -847,24 +847,16 @@ def vod_ts(camera, start_ts, end_ts):
for recording in recordings:
clip = {"type": "source", "path": recording.path}
duration = int(recording.duration * 1000)
clip["keyFrameDurations"] = [duration]
# Determine if offset is needed for first clip
target_offset = (
int((start_ts - recording.start_time) * 1000)
if recording.start_time < start_ts
else 0
)
# If we are clipping, we need to find the keyframe before start_ts and start
# from there. Otherwise we may lose data and our durations will be incorrect.
# Also get the keyframe timestamps so we can use "keyFrameDurations" below.
keyframe_timestamps, offset = get_keyframe_timestamps_and_adjusted_offset(
recording.path, target_offset
)
if keyframe_timestamps:
clip["keyFrameDurations"] = [
j - i for i, j in zip(keyframe_timestamps[:-1], keyframe_timestamps[1:])
] + [duration - keyframe_timestamps[-1]]
clip["clipFrom"] = offset
duration -= offset
if (target_offset := int((start_ts - recording.start_time) * 1000)) > 0:
# If we are clipping, we need to find the keyframe before start_ts and start
# from there. Otherwise we may lose data and our durations will be incorrect.
offset = get_adjusted_offset(recording.path, target_offset)
clip["clipFrom"] = offset
duration -= offset
# Determine if we need to end the last clip early
if recording.end_time > end_ts:
duration -= int((recording.end_time - end_ts) * 1000)

View File

@ -692,15 +692,13 @@ class SharedMemoryFrameManager(FrameManager):
del self.shm_store[name]
def get_keyframe_timestamps_and_adjusted_offset(
source: str, target_offset: int
) -> tuple[list[int], int]:
"""Get timestamp metadata from the source.
def get_adjusted_offset(source: str, target_offset: int) -> int:
"""Get the timestamp of the nearest keyframe before target_offset.
This is used to pass information to the VOD module and is useful for codec variants
with long or variable keyframe intervals.
Returns a tuple of: 1) the keyframe timestamp locations for this source
and 2) the timestamp of the nearest keyframe before target_offset."""
with long or variable keyframe intervals."""
if target_offset == 0:
return 0
ffprobe_cmd = [
"ffprobe",
"-skip_frame",
@ -717,10 +715,8 @@ def get_keyframe_timestamps_and_adjusted_offset(
]
p = sp.run(ffprobe_cmd, capture_output=True)
keyframe_timestamps = [int(1000 * float(pts)) for pts in p.stdout.split()]
if target_offset == 0:
return keyframe_timestamps, 0
for ts in reversed(keyframe_timestamps):
if ts <= target_offset:
return keyframe_timestamps, ts
return ts
logger.warning("Couldn't find starting keyframe for VOD clip")
return keyframe_timestamps, 0
return 0