GStreamer rtspsrc stops working once 32 streams have been created

290 views Asked by At

I have a device running embedded linux that can show RTSP streams from a camera. The user can change the stream from a windowed stream to a full screen stream, and vice versa. If the stream is changed 32 times, the stream stops working. I have possibly narrowed down the problem to the rtspsrc itself.

My question is, how does one clear the memory for the gst "stuff" without re-starting the program? If I use gst-launch-1.0 with the pipeline, it works for more than 32 re-starts because the program is being killed every time. However, if I run my program and increase the rtspsrc to 31 (by switching between the two streams), and then run gst-launch-1.0 with a rtsp pipeline, the steam does not show up! It appears that until every program that is using gst is killed, the rtspsrc will not reset back to 0.

I enabled debugging the rtspsrc: export GST_DEBUG="rtspsrc:6"

Lots of log messages are shown each time the stream is started. They print the rtspsrcX, which increases even though the previous stream is stopped:

First run log print:
 **rtspsrc gstrtspsrc.c:8834:gst_rtspsrc_print_sdp_media:<rtspsrc0> RTSP response message**
Second run:
 **rtspsrc gstrtspsrc.c:8855:gst_rtspsrc_print_sdp_media:<rtspsrc1>  RTSP response message**
Continue stopping/starting the stream, and it increases up to 31, at which point the stream no longer shows up:
 **rtspsrc gstrtspsrc.c:8855:gst_rtspsrc_print_sdp_media:<rtspsrc31>  RTSP response message**

I'm not sure how to "reset" the stream each time the user stops it. It seems that gst can't release memory unless I kill the whole program (all programs using gst).

I have tried creating a new context each time the stream is re-started, but this doesn't help. When I call gst_is_initialized each subsequent time, it returns true.

The main loop is stopped by calling the following from another thread: g_main_loop_quit(loop_);

The video feeds are controlled with the following:

GMainLoop *loop_;

pipeline = "rtspsrc location=rtsp://192.168.0.243/0 latency=0 ! rtph264depay ! h264parse ! imxvpudec ! imxipuvideosink window-width=512 window-height=384 sync=false"

or

pipeline = "rtspsrc location=rtsp://192.168.0.243/0 latency=0 ! rtph264depay ! h264parse ! imxvpudec ! imxipuvideosink window-width=1024 window-height=768 sync=false"

void stream_video(std::string pipeline)
{
    GMainContext* context;
        
    GstElement *pipelineElement;
    GstBus *bus = NULL;
    guint bus_watch_id = 0;
    GstState state;

    try
    {
        if(!gst_is_initialized()) 
        {
            std::cout << "GST Is not initialized - initializing " << pipeline.c_str();
            gst_init_check(nullptr,nullptr,nullptr);
        }

        context = g_main_contextnew();    // Creating a new context to see if the camera can be started more than 32 times, but the rtspsrc still increases when debugging
        loop_ = g_main_loopnew (context, FALSE);

        pipelineElement = gst_parse_launch(pipeline.c_str(), NULL);

        bus = gst_pipeline_get_bus (GST_PIPELINE (pipelineElement));
        bus_watch_id = gst_bus_add_watch (bus, bus_call, loop_);
        gst_object_unref (bus);
        bus = NULL;

        gst_element_set_state(pipelineElement, GST_STATE_READY );
        gst_element_set_state(pipelineElement, GST_STATE_PAUSED );
        gst_element_set_state(pipelineElement, GST_STATE_PLAYING);

        if (gst_element_get_state (pipelineElement, &state, NULL, 2*GST_SECOND) == GST_STATE_CHANGE_FAILURE)
        {
            std::cout <<  "gst: Failed to chage states State:" << state << " ID: " << stream_id_;
        }
        else
        {
            std::cout << "gst: Running..." << " ID: " << stream_id_ << " State:" << state << " Loop:" << loop_;
            g_main_looprun (loop_); // blocks until loop_ exits (EOS, error, stop request)
        }
        gst_element_set_state(pipelineElement, GST_STATE_PAUSED);
        gst_element_set_state(pipelineElement, GST_STATE_READY );
        gst_element_set_state(pipelineElement, GST_STATE_NULL);    // Can only switch between certian states, see https://gstreamer.freedesktop.org/documentation/additional/design/states.html?gi-language=c

        g_source_remove (bus_watch_id);

        std::cout << "gst: Removing pipelineElement " << pipelineElement;
        gst_object_unref (GST_OBJECT (pipelineElement));
        pipelineElement = NULL;

        
        g_main_contextunref (context);
        context = NULL;

        g_main_loopunref (loop_);
        loop_ = nullptr;    

        std::cout << "gst: Deleted pipeline" << " ID: " << stream_id_ << " State: " << state;
    }
    catch(const std::exception& e)
    {
        std::cout << "Error Caught: stream_video " << e.what();
    }
    return;
}

0

There are 0 answers