Loop a video with gst-rtsp-server

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Loop a video with gst-rtsp-server

Tyler Compton
Hi list,

I've been trying to create an RTSP stream from a video file source and have the video loop back to the start when it ends. This has ended up being quite tricky and I suspect I'm missing something obvious. My pipeline looks something like this:

filesrc location=video.mp4 ! parsebin ! rtph264pay name=pay0

My current solution is to subclass RTSPMedia and override the do_handle_message method. I capture EOS messages and seek the pipeline back to the start. However, this doesn't seem to have any effect. The stream just ends like normal.

class MyRTSPMedia(GstRtspServer.RTSPMedia):
    def do_handle_message(self, message):
        print("Got message:", message.type)
        if message.type == Gst.MessageType.EOS:
            pipeline: Gst.Pipeline = self.get_property("element")
            seek_result = pipeline.seek(
                rate=1.0,
                format=Gst.Format.TIME,
                flags=Gst.SeekFlags.FLUSH,
                start_type=Gst.SeekType.SET,
                start=0,
                stop_type=Gst.SeekType.NONE,
                stop=-1)
            if not seek_result:
                logging.error(
                    f"Failed to seek stream back to start! Seek "
                    f"returned {seek_result}")
            return True
        return GstRtspServer.RTSPMedia.do_handle_message(self, message)

I provide this class to my RTSPMediaFactory with the set_media_gtype method.

I noticed that gst-rtsp-server reports the video length to the client, so the client expects the stream to only last for as long as the original video. I would like the client to treat the source as a live, unending stream. Is it possible that this inaccurate runtime is the source of my problem?

_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: Loop a video with gst-rtsp-server

cfoch
Hello,
Do a SEGMENT seek to 0.0 when you receive Gst.MessageType.SEGMENT_DONE.


\o

On Sun, Mar 29, 2020 at 9:45 PM Tyler Compton <[hidden email]> wrote:
Hi list,

I've been trying to create an RTSP stream from a video file source and have the video loop back to the start when it ends. This has ended up being quite tricky and I suspect I'm missing something obvious. My pipeline looks something like this:

filesrc location=video.mp4 ! parsebin ! rtph264pay name=pay0

My current solution is to subclass RTSPMedia and override the do_handle_message method. I capture EOS messages and seek the pipeline back to the start. However, this doesn't seem to have any effect. The stream just ends like normal.

class MyRTSPMedia(GstRtspServer.RTSPMedia):
    def do_handle_message(self, message):
        print("Got message:", message.type)
        if message.type == Gst.MessageType.EOS:
            pipeline: Gst.Pipeline = self.get_property("element")
            seek_result = pipeline.seek(
                rate=1.0,
                format=Gst.Format.TIME,
                flags=Gst.SeekFlags.FLUSH,
                start_type=Gst.SeekType.SET,
                start=0,
                stop_type=Gst.SeekType.NONE,
                stop=-1)
            if not seek_result:
                logging.error(
                    f"Failed to seek stream back to start! Seek "
                    f"returned {seek_result}")
            return True
        return GstRtspServer.RTSPMedia.do_handle_message(self, message)

I provide this class to my RTSPMediaFactory with the set_media_gtype method.

I noticed that gst-rtsp-server reports the video length to the client, so the client expects the stream to only last for as long as the original video. I would like the client to treat the source as a live, unending stream. Is it possible that this inaccurate runtime is the source of my problem?
_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel

_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: Loop a video with gst-rtsp-server

Tyler Compton
Thank you for the tip, Fabián! I was not aware of segment seeking, it definitely seems like a better way to loop. However, it didn't entirely solve my problem. The video stream loops, but the client (in this case, gst-play-1.0) closes the connection because it expects the video stream to only last as long as the video file's original run time.

I looked into the way gst-rtsp-server determines run time, and I found the "gst_rtsp_stream_query_stop" method does this by reading the pipeline's current segment stop time. Since the stop time will in my case always be the end of the video, gst-rtsp-server assumes that to be the run time of the stream. I was able to get around this by overriding RTSPMedia.do_query_stop to always return -1, which causes gst-rtsp-server to assume this is an unending source.

If anyone knows a more elegant solution I would be interested to hear it, but for the time being this seems to work well.

My complete RTSPMedia subclass looks like this:

class RTSPMedia(GstRtspServer.RTSPMedia):
    def do_query_stop(self, _stop):
        return -1

    def do_handle_message(self, message: Gst.Message):
        if message.type == Gst.MessageType.STATE_CHANGED:
            # Set up segment seeking once the pipeline starts playing
            pipeline = self.get_property("element")
            _, new_state, _ = message.parse_state_changed()
            if message.src == pipeline and new_state == Gst.State.PLAYING:
                seek_result = pipeline.seek(
                    rate=1.0,
                    format=Gst.Format.TIME,
                    flags=Gst.SeekFlags.FLUSH | Gst.SeekFlags.SEGMENT,
                    start_type=Gst.SeekType.SET,
                    start=0,
                    stop_type=Gst.SeekType.NONE,
                    stop=-1)
                if not seek_result:
                    raise RuntimeError(f"Failed to send seek event")
        elif message.type == Gst.MessageType.SEGMENT_DONE:
            # Seek playback to the start when the segment is done
            seek_result = pipeline.seek(
                rate=1.0,
                format=Gst.Format.TIME,
                flags=Gst.SeekFlags.SEGMENT,
                start_type=Gst.SeekType.SET,
                start=0,
                stop_type=Gst.SeekType.NONE,
                stop=-1)
            if not seek_result:
                raise RuntimeError(f"Failed to send seek event")

        return GstRtspServer.RTSPMedia.do_handle_message(self, message)


On Sun, Mar 29, 2020 at 8:03 PM Fabián Orccón <[hidden email]> wrote:
Hello,
Do a SEGMENT seek to 0.0 when you receive Gst.MessageType.SEGMENT_DONE.


\o

On Sun, Mar 29, 2020 at 9:45 PM Tyler Compton <[hidden email]> wrote:
Hi list,

I've been trying to create an RTSP stream from a video file source and have the video loop back to the start when it ends. This has ended up being quite tricky and I suspect I'm missing something obvious. My pipeline looks something like this:

filesrc location=video.mp4 ! parsebin ! rtph264pay name=pay0

My current solution is to subclass RTSPMedia and override the do_handle_message method. I capture EOS messages and seek the pipeline back to the start. However, this doesn't seem to have any effect. The stream just ends like normal.

class MyRTSPMedia(GstRtspServer.RTSPMedia):
    def do_handle_message(self, message):
        print("Got message:", message.type)
        if message.type == Gst.MessageType.EOS:
            pipeline: Gst.Pipeline = self.get_property("element")
            seek_result = pipeline.seek(
                rate=1.0,
                format=Gst.Format.TIME,
                flags=Gst.SeekFlags.FLUSH,
                start_type=Gst.SeekType.SET,
                start=0,
                stop_type=Gst.SeekType.NONE,
                stop=-1)
            if not seek_result:
                logging.error(
                    f"Failed to seek stream back to start! Seek "
                    f"returned {seek_result}")
            return True
        return GstRtspServer.RTSPMedia.do_handle_message(self, message)

I provide this class to my RTSPMediaFactory with the set_media_gtype method.

I noticed that gst-rtsp-server reports the video length to the client, so the client expects the stream to only last for as long as the original video. I would like the client to treat the source as a live, unending stream. Is it possible that this inaccurate runtime is the source of my problem?
_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel

_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel