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

View File

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