GStreamer: Closing down RTSP Server within a process

Yurkanin, David dyurkanin at specialtysystems.com
Tue Nov 29 00:23:11 UTC 2022


GREETINGS,



I have been using GStreamer (up to v1.19.1 at this point) for about 2 years now, both with the GStreamer RTSP codebase and within the OpenCV VideoCapture open() method (on Windows 10 and developed using Visual Studio 2019)...



GStreamer functionality along with its launch element model has been a great success for my project...good job...



When running gst-launch-1.0 with various launch strings in the cmd console, when stopping the exe or closing the cmd console I never had any problem with the pipeline being stopped and resources being recovered behind the scenes. When I run my project likewise never had any problem...I can close it down and open it again over and over, no problem...



However, with the RTSP server code I now need to stop and disconnect ('TEAR DOWN') an RTSP server and create a new one within a running exe, and I am having a problem destroying the current RTSP server and its resources.  It seems the pipeline formed during the connection process still is running and I can't start a new one.  I have searched online for doing this and found multiple ways to destroy portions of the assortment of objects of the server and in multiple orders of destruction, none of them work...see https://github.com/GStreamer/gst-rtsp-server/tree/master/examples, yes, I tried test-video-disconnect.c code...



Also, within the OpenCV VideoCapture open() method call which accepts a GStreamer launch string the video acquisition is excellent, but rarely a camera/network/connection can enter a state where the open() method never returns, requiring an app restart. Calling open() using std::async to detect this condition does not work (BTW, calling the OpenCV VideoCapture grab() method with std::async works well and reliably for other purposes though)...



After much research I am thinking that these two behaviors are originating at the GStreamer launch string level, so this is why I am asking both questions in this forum...



I am hoping to find a way to ensure an RTSP server pipeline has been completely destroyed within a running exe...



If you have general thoughts feel free to respond, but if I have sparked your interest please read on for more detail...





I have used the following launch strings which utilize GPU-CUDA-h/w codec capabilities of the NVidia GPU's currently being used:



GStreamer RTSP code - running multiple RTSP servers, each running in different threads (Qt QThread)



                Some code extract, but conforms to the RTSP server examples:



                                gst_init_check(nullptr, nullptr, &gstError)



                                for (int feed_num = 0; feed_num < numOutputVideoFeeds; feed_num++)

                                {



                                QObject[feed_num].moveToThread(&QThread[feed_num]);

                                QObject::connect(&(&QThread[feed_num], &QThread::started, &QObject[feed_num], [&, feed_num]()

                                {

                                                g_main_loop_new(NULL, FALSE);



                                                g_main_loop_get_context(gst_loop);



                                                gst_rtsp_server_new();



                                                gst_rtsp_server_set_address(gst_server, "127.0.0.1");



                                                gst_rtsp_server_set_service(gst_server, "8554");



                                                gst_rtsp_server_get_mount_points(gst_server);



                                                gst_rtsp_media_factory_new();



                                                gst_rtsp_media_factory_set_launch(gst_factory, "( appsrc name=mysrc ! videoconvert ! nvh264enc ! video/x-h264,profile=high ! rtph264pay name=pay0 pt=96 )" );



                                                g_signal_connect(gst_factory, "media-configure", (GCallback)media_configure, &stream_data);



                                                gst_rtsp_media_factory_set_shared(gst_factory, TRUE);



                                                gst_rtsp_mount_points_add_factory(gst_mounts, "/test", gst_factory);



                                                rtsp_sourceID = gst_rtsp_server_attach(gst_server, gst_context);



                                                while (!(QThread[feed_num].isInterruptionRequested()))

                                                                {

                                                                                g_main_context_iteration(gst_context, FALSE);

                                                                }



                                Once the QThread is signaled to exit this main loop, then I try to clean up based on online code, before terminating the QThread, tried a bunch of ways, none worked...



                                                gst_rtsp_server_get_mount_points(gst_server);

                                                gst_rtsp_mount_points_remove_factory(gst_mounts, "/test");

                       gst_object unref ()
      

                                                gst_rtsp_server_get_session_pool(gst_server);

                                                gst_rtsp_session_pool_filter(gst_pool, remove_func, gst_server);

                       gst_object unref ()



                       g_source_remove(rtsp_sourceID);



                                                if (g_main_loop_is_running(gst_loop))

                                                                g_main_loop_quit(gst_loop);

                      gst_object unref ()



                                }

                                }



                                QThread[feed_num].start(QThread::InheritPriority);



When the above recovery code is run I get the following errors:


(DILARTS_PDP_App_2022_Debug.exe:44908): GStreamer-CRITICAL **: 14:25:01.948: gst_object_ref: assertion 'object != NULL' failed



(DILARTS_PDP_App_2022_Debug.exe:44908): GLib-CRITICAL **: 14:25:01.957: g_hash_table_insert_internal: assertion 'hash_table != NULL' failed



(DILARTS_PDP_App_2022_Debug.exe:44908): GStreamer-CRITICAL **: 14:25:01.959: gst_allocator_free: assertion 'GST_IS_ALLOCATOR (allocator)' failed



(DILARTS_PDP_App_2022_Debug.exe:44908): GStreamer-CRITICAL **: 14:25:01.965: gst_object_unref: assertion 'object != NULL' failed


But they don't tell me what objects are involved??



Based on online research, perhaps an EOS signal needs to be sent out the pipeline?  How would that be implemented in this code that uses this media_configure() and need_data() construct?





 Here is the OpenCV code:



OpenCV VideoCapture class open() method - used for multiple camera video acquisition, each running in different threads (std::thread)



                capturePromises[cam_num] = std::promise<void>();

                captureFutures[cam_num] = capturePromises[cam_num].get_future();

                captureThreads[cam_num] = new std::thread(&Controls::capture, this, ipCamPaths[cam_num], ipCamPrefix[cam_num], ipCamAttribs[cam_num], cam_num, std::ref(capture_state), std::move(captureFutures[cam_num]));



                capture(const QString path, const QString prefix, const QString attributes, const int cam_num, std::array<std::atomic<capture_state_mode>, max_num_pano_cameras>& capture_state, std::future<void> future)

                {

                                cv::VideoCapture cap(0, cv::CAP_GSTREAMER);



                                cap.open("path plus latency=0 ! rtph264depay ! h264parse ! d3d11h264dec ! videoconvert ! appsink sync = 0", VIDEO_PROVIDER_API/*, [ (cv::CAP_PROP_HW_ACCELERATION), cv2.VIDEO_ACCELERATION_ANY ]*/);



                                std::future<bool> future_grab = std::async(&cv::VideoCapture::grab, cap);

                                grabbed = (future_grab.wait_for(std::chrono::milliseconds(config.capture_camera_grab_wait_limit_msec)) == std::future_status::ready);



                                retrieved = cap.retrieve(frame);



                                frameBufs[cam_num] = frame;

                }



This OpenCV code works well with GStreamer but sometimes the open() method does not return...



Any help, comments, quidance, links, or code would be appreciated...



David Yurkanin


The preceding message (including attachments) is covered by the Electronic Communication Privacy Act, 18 U.S.C. sections 2510-2512, is intended only for the person or entity to which it is addressed, and may contain information that is confidential, protected by attorney-client or other privilege, or otherwise protected from disclosure by law.  If you are not the intended recipient, you are hereby notified that any retention, dissemination, distribution, or copying of this communication is strictly prohibited.  Please reply to the sender that you have received the message in error and destroy the original message and all copies.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/gstreamer-devel/attachments/20221129/9b201c46/attachment-0001.htm>


More information about the gstreamer-devel mailing list