Hi there,
I’m working on a Python script that uses GStreamer for both recording segmented MP4 files and streaming them via RTSP. I’m encountering consistent issues with seeking functionality during RTSP playback, particularly when attempting to seek to specific timestamps within the streamed video. Please provide a solution.
Following are the code snippet i have been using-
My recording pipeline creates segmented MP4 files (live_%03d.mp4
) which are later concatenated into a single file (rec_DD_MM_YY_HH_MM_SS.mp4
).
queue leaky=2 max-size-buffers=2 ! videoconvert ! x264enc key-int-max=30 tune=zerolatency bitrate=5000 speed-preset=veryfast pass=cbr ! queue ! splitmuxsink name=sinkmux location=“{file_pattern}” max-size-time=30000000000 muxer=mp4mux
I have a custom GstRtspServer.RTSPMediaFactory
that attempts to serve the recorded files based on a requested datetime. It reads a metadata.json
file to find the appropriate segment.
class PlaybackStreamFactory(GstRtspServer.RTSPMediaFactory):
def __init__(self, metadata_path, video_folder):
super().__init__()
self.set_shared(False)
self.metadata_path = metadata_path
self.video_folder = video_folder
def do_create_element(self, url):
uri = url.get_request_uri()
qs = parse_qs(urlparse(uri).query)
request_dt = qs.get('datetime', [None])[0]
if not request_dt:
print("[ERROR] No datetime provided in request.")
return None
print(f"[INFO] Playback requested for datetime: {request_dt}")
try:
with open(self.metadata_path, 'r') as f:
metadata = json.load(f)
except Exception as e:
print(f"[ERROR] Could not load metadata: {e}")
return None
match_file = None
for key in list(metadata.keys()):
info = metadata[key]
start = datetime.strptime(info["start"], "%d_%m_%y_%H_%M_%S")
end = datetime.strptime(info["end"], "%d_%m_%y_%H_%M_%S")
req = datetime.strptime(request_dt, "%d_%m_%y_%H_%M_%S")
if start <= req <= end:
match_file = os.path.join(self.video_folder, key)
break
if not match_file or not os.path.exists(match_file):
print(f"[ERROR] No file found for datetime: {request_dt}")
return None
print(f"[INFO] Streaming file: {match_file}")
return Gst.parse_launch(
f"( filesrc location=\"{match_file}\" ! qtdemux name=demux "
f"demux.video_0 ! h264parse ! rtph264pay config-interval=1 name=pay0 pt=96 )"
)
I am maintaining a json file for all the recordings that was done previously so that it will be easy to search the time stamp between those mp4 files
The following is the function for creating a combined file using mp4mux →
muxer_pipeline = f"mp4mux name=mux ! filesink location=\"{abs_output_filename}\" "
source_pipeline = []
for segment_file in segment_files:
abs_segment_file = os.path.abspath(segment_file)
source_pipeline.append(
f"filesrc location=\"{abs_segment_file}\" ! decodebin ! videoconvert ! x264enc tune=zerolatency speed-preset=veryfast ! queue ! mux."
)
gst_concat_str = f"{muxer_pipeline} {' '.join(source_pipeline)}"
print(f"pipeline string : \n{gst_concat_str}")
Earlier I have worked on different approaches also but it didn’t go well