Search code examples
pythonvideo-streamingrtspffplay

Is there a way to stream multiple videos continuosly with the same address and route using RTSP?


I am participating in a project using RTSP and cameras footage. My objective is to create a continuous flow of videos streamed in the same address and route to update the videos according to the footage we need to display.

So, the expected behavior I have to create is to change the video streamed in the address while using ffplay to visualize the stream I am creating. This is recreated by this diagram:

enter image description here

But this simply does not work. Whenever I try to change the video, the original video just freeze and it is impossible to visualize anything. ffplay throws an error: rtsp://localhost:8554/sample: error while seeking. And this is weird for me because when I shut down the transmition and I open it again, it shows the changed footage that I wanted to visualize now.

To create the RTSP server I am using this repository: https://github.com/p513817/rtsp4k. It is based on mediamtx and Python to recreate all the logic.

I have no knowledge in RTSP, so I don't know if I should do anything low-level to keep the flow without finishing the video or I should try other framework. I need help!

The logic I am doing to update the video is

    def put_placeholder(self, input:str, route: str):
        success = True
        try:
            # I change the Displayer to show my placeholder instead the original video
            self.dprs[route] = Displayer(
                input='./utils/placeholder.mp4',
                route=str(route),
                start_stream=True
            )

            # Same here
            if route in PARAMS.CONF["streams"] :
                PARAMS.CONF["streams"][route] = {
                    "input": './utils/placeholder.mp4'
                }
                write_config(PARAMS.CONF_PATH, PARAMS.CONF)

        except Exception as e:
            logging.exception(e)
            success = False

        finally:
            # I update the info in the .json that summarize all the streams
            self._update_info(
                input='./utils/placeholder.mp4', 
                route=route, 
                url=self.dprs[route].get_url() if success else "", 
                status=success )

        return self.info[route]

Solution

  • I realized that I was creating a new object instead of changing the current one. This made that ffplay was incapable of keeping track of the address and route because loses connection and then it is reconnected immediately, making the stream to crash.

    The final code for updating the videos is a modification of the function put_placeholder that I created in the Manager class in rtsp_handler.py. It is added a new function called change_input() in the Displayer class by creating a function that updates the file's path and not creates a new thread or class instance.

        def put_placeholder(self, input:str, route: str):
            success = True
            try:
                # NOTE: modify config
                path = ""
                if input == 'placeholder':
                    path = './utils/placeholder.mp4'
                else:
                    path = './data/'+input+'.mp4'
                
                self.dprs[route].change_input(path)
    
                if route in PARAMS.CONF["streams"] :
                        PARAMS.CONF["streams"][route] = {
                            "input": path
                        }
                        write_config(PARAMS.CONF_PATH, PARAMS.CONF)
    
            except Exception as e:
                logging.exception(e)
                success = False
    
            finally:
                self._update_info(
                    input=path, 
                    route=route, 
                    url=self.dprs[route].get_url() if success else "", 
                    status=success )
    
            return self.info[route]
    
        def change_input(self, new_input:str):
            self.input = new_input
            self.src = self._create_source()