How to dynamically link to tee after pipeline started using gst_parse_launch

Nick_law nicholas at umantec.net
Tue Mar 2 11:34:12 UTC 2021


Good afternoon all,

Thanks to @gotsring in this post
http://gstreamer-devel.966125.n4.nabble.com/Is-it-possible-to-dynamically-update-tee-sink-interleave-src-td4696637.html

I have learnt how to unlink and relink pads in a pipeline. 

What I would like to do now is start a pipeline with audiotestsrcs connected
to a Fakesink and once the pipeline is started then link the audiotestsrcs
using tees to the corresponding interleave pads. 

I am unsure if this is even possible using gst_parse_launch but I am hoping
someone is able to lead me in a direction where I can get access to
interleave and tee pads without having them linked in the original parse
launch string.

I can see that the tee plugin has a num-src-pads property which would allow
to specify the number of pads needed but thereafter I don't know how to
access them. The main problem being that I would hope a tee src pad doesn't
need to be defined with a named pad in the string.

It would also be nice to be able to access individual interleave pads
without creating named pads as well.
i.e i.src_2 or t2_src3 etc just from the named tee and interleave values.

The main idea is to be able to create a multichannel (16 channels +)
pipeline that initially outputs 0 until audio sources are mapped to the
desired channels.

I have a current broken example that shows a little of what I'm trying to do
but obviously missing some core concepts:

```
        gst_init(NULL, NULL);

	GError* err = NULL;

	std::stringstream gst_parse;

	//audiotestsrc needed the is-live=true flag added to allow for remapping
and continued playout.
	//Currently unsure how that would react with a file player (wavparse and
rawaudioparse)
	gst_parse << "interleave name=i ! audioconvert ! wavenc ! filesink
location=test.wav ";
	gst_parse << "audiotestsrc is-live=true ! tee name=t1 ";
	gst_parse << "audiotestsrc is-live=true wave=2 ! tee name=t2 ";
	gst_parse << "audiotestsrc is-live=true wave=4 ! tee name=t3 "; //Silent
wave used as Fakesrc

	gst_parse << "t3. ! queue ! volume name=out0 volume=1.0 ! i. ";
	gst_parse << "t3. ! queue ! volume name=out1 volume=1.0 ! i. ";
	gst_parse << "t3. ! queue ! volume name=out2 volume=1.0 ! i. ";
	gst_parse << "t3. ! queue ! volume name=out3 volume=1.0 ! i. ";

	gst_parse << "t1. ! queue ! volume name=vol0 volume=1.0 ! fakesink ";
//Ideally this is not needed to start pipeline
	gst_parse << "t2. ! queue ! volume name=vol1 volume=1.0 ! fakesink ";

	GstElement* pipeline = gst_parse_launch(gst_parse.str().c_str(), &err);

	if (err != NULL) {
		g_print("Pipeline failed to be created! You did a bad parse!\n");
		g_printerr("Error: %s\n", err->message);
		return -1;
	}

	// Get elements by name
	GstElement* out0 = gst_bin_get_by_name(GST_BIN(pipeline), "out0");
	GstElement* out1 = gst_bin_get_by_name(GST_BIN(pipeline), "out1");
	GstElement* out2 = gst_bin_get_by_name(GST_BIN(pipeline), "out2");
	GstElement* out3 = gst_bin_get_by_name(GST_BIN(pipeline), "out3");

	GstElement* vol0 = gst_bin_get_by_name(GST_BIN(pipeline), "vol0");//Again
ideally not needed
	GstElement* vol1 = gst_bin_get_by_name(GST_BIN(pipeline), "vol1");

	if (
		!out0 ||
		!out1 ||
		!out2 ||
		!out3 ||
		!vol0 ||
		!vol1) {
		g_print("Error getting bins!\n");
		return -1;
	}

	// Get their the sink and src pads that need to be unlinked and re-linked
	GstPad* out0_sink_pad = gst_element_get_static_pad(out0, "sink"); //sink
side is where the fakesrc silent wave is conected
	GstPad* out1_sink_pad = gst_element_get_static_pad(out1, "sink");
	GstPad* out2_sink_pad = gst_element_get_static_pad(out2, "sink");
	GstPad* out3_sink_pad = gst_element_get_static_pad(out3, "sink");

	GstPad* vol0_src_pad = gst_element_get_static_pad(vol0, "src"); //src side
is where the Fakesink is connected
	GstPad* vol1_src_pad = gst_element_get_static_pad(vol1, "src");

	if (
		!out0_sink_pad ||
		!out1_sink_pad ||
		!out2_sink_pad ||
		!out3_sink_pad ||
		!vol0_src_pad ||
		!vol1_src_pad) {
		g_print("Error getting src pads!\n");
		return -1;
	}

	// I'm not sure that pad order is guaranteed when the pipeline is
constructed,
	// meaning interleave pad sink1 might be connected to vol0 instead of vol1
	// So, get pads based on peers! peers are the element that the pad is
connected to.
	GstPad* fakesrc0_pad = gst_pad_get_peer(out0_sink_pad);
	GstPad* fakesrc1_pad = gst_pad_get_peer(out1_sink_pad);
	GstPad* fakesrc2_pad = gst_pad_get_peer(out2_sink_pad);
	GstPad* fakesrc3_pad = gst_pad_get_peer(out3_sink_pad);

	GstPad* fakesink0_pad = gst_pad_get_peer(vol0_src_pad);
	GstPad* fakesink1_pad = gst_pad_get_peer(vol1_src_pad);

	if (!fakesrc0_pad ||
		!fakesrc1_pad ||
		!fakesrc2_pad ||
		!fakesrc3_pad ||
		!fakesink0_pad ||
		!fakesink1_pad) {
		g_print("Error getting peer pads!\n");
		return -1;
	}

	// Play for a bit
	g_print("Playing...\n");
	gst_element_set_state(pipeline, GST_STATE_PLAYING);
	GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(pipeline), GST_DEBUG_GRAPH_SHOW_ALL,
"playing_orig");
	g_usleep(2000000);

	// Swap around pads
	g_print("Rearranging pads...\n");
	gst_element_set_state(pipeline, GST_STATE_PAUSED);

	gboolean good = TRUE;
	good &= gst_pad_unlink(fakesrc0_pad, out0_sink_pad);
	good &= gst_pad_unlink(fakesrc1_pad, out1_sink_pad);
	good &= gst_pad_unlink(fakesrc2_pad, out2_sink_pad);
	good &= gst_pad_unlink(fakesrc3_pad, out3_sink_pad);

	good &= gst_pad_unlink(vol0_src_pad, fakesink0_pad);
	good &= gst_pad_unlink(vol1_src_pad, fakesink1_pad);

	if (!good) {
		g_print("Pad unlink was not good!");
		REQUIRE(0);
	}
        // This is where I am unsure how to relink to a tee that hasn't got
a named pad in the original parse launch string.
        // The relink won't work as the vol*_src_pads are being relinked to
more than one pad.

  	good &= gst_pad_link(vol0_src_pad, out0_sink_pad) == GST_PAD_LINK_OK;
	good &= gst_pad_link(vol1_src_pad, out1_sink_pad) == GST_PAD_LINK_OK;

	good &= gst_pad_link(vol0_src_pad, out2_sink_pad) == GST_PAD_LINK_OK;
	good &= gst_pad_link(vol1_src_pad, out3_sink_pad) == GST_PAD_LINK_OK;

	//It seems that you MUST reconnect the fakesinks and Fakesrcs or the relink
doesn't play out
	good &= gst_pad_link(fakesrc0_pad, fakesink0_pad) == GST_PAD_LINK_OK;
	good &= gst_pad_link(fakesrc1_pad, fakesink1_pad) == GST_PAD_LINK_OK;
	good &= gst_pad_link(fakesrc2_pad, fakesink0_pad) == GST_PAD_LINK_OK;
	good &= gst_pad_link(fakesrc3_pad, fakesink1_pad) == GST_PAD_LINK_OK;

	if (!good) {
		g_print("Pad relink was not good!");
		REQUIRE(0);
	}

	// Play some more
	g_print("Playing more...\n");
	gst_element_set_state(pipeline, GST_STATE_PLAYING);
	GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(pipeline), GST_DEBUG_GRAPH_SHOW_ALL,
"playing_swapped");
	g_usleep(2000000);

	g_print("Stopping...\n");
	//TODO: test this with the hanging fifo issue and see if that stops
gstreamer from hanging
	gst_element_send_event(pipeline, gst_event_new_eos());
	gst_element_set_state(pipeline, GST_STATE_NULL);

	g_print("Done.\n");

```

I hope I have explained my problem clearly and that someone can help?

Thanks so much,
Nick



--
Sent from: http://gstreamer-devel.966125.n4.nabble.com/


More information about the gstreamer-devel mailing list