Launch GstRTSPServer from GstElement pipeline
Asked Answered
D

2

9

I'm doing a Gstreamer 1.0 application in C. The pipeline is built, based on user configuration and system "state" during runtime. Therefore I'm using multiple GstElements which are later added and linked to a "GstElement pipeline". Here's a minimal example for a better understanding:

GstElement *pipeline = gst_pipeline_new("mypipeline");
...
GstElement *src = gst_element_factory_make("videotestsrc", NULL);
...
gst_bin_add_many(GST_BIN(pipeline), src, enc, pay, NULL);
gst_element_link_many(src, enc, pay, NULL);
...

This pipeline should then be launched by a GstRTSPMediaFactory. The problem I'm facing here is that the gst_rtsp_media_factory_set_launch function is only accepting a const gchar * pipeline.

Therefore my question is, if anybody of you is aware of a function for either

  • transforming the GstElement *pipeline to a const gchar* representation (kinda reverse gst_parse)
  • or launching the GstRTSPMediaFactory from a GstElement *pipeline (see edit #1 below)

Any help is much appreciated! Thank you.


EDIT #1:

From the gst-rtsp-server documentation:

The default implementation of GstRTSPMediaFactory allows you to easily create GStreamer pipelines using the gst-launch syntax. It is possible to create a GstRTSPMediaFactory subclass that uses different methods for constructing pipelines.

Therefore launching a GstRTSPMediaFactory from a GstElement is technically possible. Additional question to this approach: Is anybody aware of such an GstRTSPMediaFactory subclass implementation?

Digestif answered 13/11, 2017 at 16:35 Comment(2)
there isnt anything to convert the pipeline to gst-launch string alternatively you look at [1] for you to implement your option two to pass the pipeline to factory, [1] gstreamer-devel.966125.n4.nabble.com/…Dvandva
I would like to do the same. Did you find a way?Darceydarci
S
1

Yes, the gst-rtsp-server repository has an example in its subfolder examples. To summarise: make a subclass of GstRTSPMediaFactory and override the create_element() virtual method.

As an aside, this also means the 2 options you provided before were incorrect;

  • transforming the GstElement pipeline to a const gchar representation (kinda reverse gst_parse)

This is not possible, since the programmatic API is more expressive and allows you to do more (even a simple example: registering callbacks) than the declarative launch API.

  • or launching the GstRTSPMediaFactory from a GstElement *pipeline (see edit #1 below)

You're thinking the other way around: when the GStreamer RTSP server gets the request to start playing, it will use the GstRTSPMediaFactory to launch a GstPipeline based on your get_element() implementation. Not the other way around, where each pipeline launches its own RTSP server.

Southeastward answered 5/6, 2020 at 12:35 Comment(0)
D
0

For anyone interested, I recently worked on similar problem and its actually very reasonable requirement to build and launch pipeline dynamically based on config.

When creating the source pipeline dynamically, instead of adding pay element, use shared memory sink.

GstElement *pipeline = gst_pipeline_new("mypipeline");
...
GstElement *src = gst_element_factory_make("videotestsrc", NULL);
...
GstElement* shmsink = gst_element_factory_make("shmsink", nullptr);
g_object_set(shmsink, "socket-path", "/tmp/stream.socket",
                      "wait-for-connection", false, nullptr);
gst_bin_add_many(GST_BIN(pipeline), src, enc, shmsink, NULL);
gst_element_link_many(src, enc, shmsink, NULL);
gst_element_set_state(pipeline, GST_STATE_PLAYING);

Then construct the second part of pipeline in char* format which uses shared memory src element to receive this stream and publish it over RTSP stream.

Note: You will need to use the parse element (h264parse, h265parse etc) respective to the encoding format after receiving the stream from shared memory. Also set do_timestamp=false for audio streams.

std::string rtsp_launch_str = " shmsrc socket-path=/tmp/stream.socket do_timestamp=true ! h264parse ! queue max-size-buffers=1 ! rtph264pay name=pay0";

// Start RTSP server
loop = g_main_loop_new (NULL, FALSE);
server = gst_rtsp_server_new ();
g_object_set (server, "service", port, NULL);

mounts = gst_rtsp_server_get_mount_points (server);

// Set the constructed char* as launch str
factory = gst_rtsp_media_factory_new ();
gst_rtsp_media_factory_set_launch (factory, rtsp_launch_str.c_str());
gst_rtsp_media_factory_set_shared (factory, TRUE);
gst_rtsp_mount_points_add_factory (mounts, "/test", factory);

g_object_unref (mounts);

gst_rtsp_server_attach (server, NULL);

g_print ("stream ready at rtsp://127.0.0.1:%s/test\n", port);
g_main_loop_run (loop);

This very rough code to create RTSP server, refer this code for more details https://github.com/GStreamer/gst-rtsp-server/blob/master/examples/test-launch.c

Dogmatic answered 16/1 at 3:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.