My goal is to record an rtsp stream into 5 second segments, but I want those segments to only include every 5th frame and be as compact as possible. Essentially, the resulting video will be a 1 second video that shows 5 seconds of realtime content.
I have found that ffmpeg has video segment muxing that works really well. I have also found that I can apply a -filter:v select=not(mod(n\,{frame_skip})),setpts=PTS/{frame_skip}
filter to only keep every 5th frame and also ensure that the resulting mp4 is 1 second instead of 5 seconds. This time reduction saves space, AND it also ensures that there aren't duplicate frames stored and displayed in the mp4.
This is the segment muxing command that works:
sec_overlap = 1
segment_time = 5
ffmpeg_command = (
f'ffmpeg -rtsp_transport tcp -i "{rtsp_url}" '
f'-c:v libx264 -preset ultrafast -tune zerolatency -an '
f'-vf "scale=iw/10:ih/10" '
f'-f segment '
f'-segment_time {segment_time} '
f'-reset_timestamps 1 '
f'-segment_time_delta {sec_overlap} '
f'-strftime 1 "{directory}\{cam_label}_%Y-%m-%d-%H-%M-%S.mp4"'
)
And this is the the filter command that successfully skips every 5th frame and shrinks the video length by 5x:
sec_overlap = 1
frame_skip = 5
segment_time = 5 #5 / frame_skip**2
ffmpeg_command = (
f'ffmpeg -rtsp_transport tcp -i "{rtsp_url}" '
f'-c:v libx264 -preset ultrafast -tune zerolatency -an '
f"-filter:v '"
f"select=not(mod(n\,{frame_skip})),"
f"setpts=PTS/{frame_skip},"
f"fps={frame_skip*frame_skip}"
f"' "
f'-f segment '
f'-segment_time {segment_time} '
f'-reset_timestamps 1 '
f'-segment_time_delta {sec_overlap} '
f'-strftime 1 '
f'"{directory}\{cam_label}_%Y-%m-%d-%H-%M-%S.mp4"'
)
THIS IS MY PROBLEM. The resulting video ends up being a 10 second duration video that covers 50 SECONDS of realtime rtsp video footage. It appears that adjusting the PTS parameter, causes the segment_time calculation to record much longer.
Does anyone know how to get 1sec videos of 5sec coverage while still applying this video filter?
My goal is to record an rtsp stream into 5 second segments, but I want those segments to only include every 5th frame and be as compact as possible. Essentially, the resulting video will be a 1 second video that shows 5 seconds of realtime content.
I have found that ffmpeg has video segment muxing that works really well. I have also found that I can apply a -filter:v select=not(mod(n\,{frame_skip})),setpts=PTS/{frame_skip}
filter to only keep every 5th frame and also ensure that the resulting mp4 is 1 second instead of 5 seconds. This time reduction saves space, AND it also ensures that there aren't duplicate frames stored and displayed in the mp4.
This is the segment muxing command that works:
sec_overlap = 1
segment_time = 5
ffmpeg_command = (
f'ffmpeg -rtsp_transport tcp -i "{rtsp_url}" '
f'-c:v libx264 -preset ultrafast -tune zerolatency -an '
f'-vf "scale=iw/10:ih/10" '
f'-f segment '
f'-segment_time {segment_time} '
f'-reset_timestamps 1 '
f'-segment_time_delta {sec_overlap} '
f'-strftime 1 "{directory}\{cam_label}_%Y-%m-%d-%H-%M-%S.mp4"'
)
And this is the the filter command that successfully skips every 5th frame and shrinks the video length by 5x:
sec_overlap = 1
frame_skip = 5
segment_time = 5 #5 / frame_skip**2
ffmpeg_command = (
f'ffmpeg -rtsp_transport tcp -i "{rtsp_url}" '
f'-c:v libx264 -preset ultrafast -tune zerolatency -an '
f"-filter:v '"
f"select=not(mod(n\,{frame_skip})),"
f"setpts=PTS/{frame_skip},"
f"fps={frame_skip*frame_skip}"
f"' "
f'-f segment '
f'-segment_time {segment_time} '
f'-reset_timestamps 1 '
f'-segment_time_delta {sec_overlap} '
f'-strftime 1 '
f'"{directory}\{cam_label}_%Y-%m-%d-%H-%M-%S.mp4"'
)
THIS IS MY PROBLEM. The resulting video ends up being a 10 second duration video that covers 50 SECONDS of realtime rtsp video footage. It appears that adjusting the PTS parameter, causes the segment_time calculation to record much longer.
Does anyone know how to get 1sec videos of 5sec coverage while still applying this video filter?
Okay, I found a solution! The problem was using the libx264 compression which took up too much compute time. I switched to using -c:v mpeg1video
instead, which speeds up the compression. On top of this, I just have to set segment_time=min(1, desired_time/frame_skip)
, which will result in desired_time
seconds of rtsp coverage that is recorded, but the recording will still only be desired_time/frame_skip
in duration. The final command and setup to get 5second videos that are compressed is:
desired_time = 5 # how many seconds of rtsp stream to record per video
frame_skip = 5
segment_time = max(1, desired_time//frame_skip)
ffmpeg_command = (
f'ffmpeg -rtsp_transport tcp -i "{rtsp_url}" '
f'-c:v mpeg1video -an '
f"-filter:v '"
f"select=not(mod(n\,{frame_skip})),"
f"setpts=PTS/{frame_skip}"
f"' "
f'-f segment '
f'-segment_time {segment_time} '
f'-reset_timestamps 1 '
f'-segment_time_delta 1 '
f'-strftime 1 '
f'"{directory}\{cam_label}_%Y-%m-%d-%H-%M-%S.mp4"'
)