How to flush Gstreamer pipeline queue and elements? - gstreamer

I want to unkink this two queue from pipeline and exchange some element of this queue.
Like that :
gst_element_set_state (pipeline, GST_STATE_PAUSED);
gst_element_set_state (sink, GST_STATE_NULL);
gst_element_unlink_many(screen_queue2, **filter2**, **videobox2**, videoBox2_queue, (char* )0);
gst_element_unlink_many(screen_queue4, **filter4**, **videobox4**, videoBox4_queue, (char* )0);
gst_element_link_many(screen_queue2, **filter2**, **videobox4**, videoBox4_queue, (char* )0);
gst_element_link_many(screen_queue4, **filter4**, **videobox2**, videoBox2_queue, (char* )0);
but my code crashes, kindly help me out to resolved this crash issue. It works properly when pipeline is in NULL state, but I want to handle this when pipeline is in only PAUSED state.

Related

Gstreamer Elements could not be linked

I'm new to GStreamer, I followed the Basic tutorial 2 on GStreamer website and try to make it work with local mp4 file.
My problem is that I can't link "uridecodebin" and "autovideosink", here is my related code :
GstElement *pipeline, *source, *sink;
GstBus *bus;
GstMessage *msg;
GstStateChangeReturn ret;
/* Initialize GStreamer */
gst_init (&argc, &argv);
/* Create the elements */
source = gst_element_factory_make ("uridecodebin", "source");
sink = gst_element_factory_make ("autovideosink", "sink");
/* Create the empty pipeline */
pipeline = gst_pipeline_new ("pipeline");
if (!pipeline || !source || !sink) {
g_printerr ("Not all elements could be created.\n");
return -1;
}
/* Build the pipeline */
gst_bin_add_many (GST_BIN (pipeline), source, sink, NULL);
if (gst_element_link (source, sink) != TRUE) {
g_printerr ("Elements could not be linked.\n");
gst_object_unref (pipeline);
return -1;
}
It always return false with gst_element_link (source, sink), but it worked well if I simply use gst-launch-1.0 uridecodebin uri=file://MyPathToVideo/test.mp4 ! autovideosink command, what am I doing wrong?
Lots of thanks.
Try using gst_parse_launch() and giving it your pipeline. It is shorter this way. And I believe it takes care of some particularities in your case.
The main issue your approach is not working is that uridecodebin does not expose any pads because at that point in time it does not know anything about your MP4 file. So it can contain audio, video, both - or whatever. The correct approach is to implement delayed linking.
So instead of linking it directly you implement the pad-added signal on uridecodebin:
https://gstreamer.freedesktop.org/documentation/gstreamer/gstelement.html?gi-language=c#GstElement::pad-added
Then you start the pipeline with the elements disconnected.
This pad-added signal is triggered when uridecodebin has scanned your media file and exposes pads which can be linked. In case it is your video pad you can connect it to the autovideosink.
gst_parse_launch() if I'm not mistaken will take of this automatically for you (at least that is what gst-lauch-1.0 is doing - not sure if that specific functionality moved to that API as well).
P.S. You jumped the gun. Tutorial 2 does not use uridecodebin but more basic elements. Tutorial 3 will cover dynamic pipelines.

Memory not freed after gstreamer pipeline set to GST_STATE_NULL

My application requires gstreamer pipeline to be restarted multiple times.
But after setting the pipeline to GST_STATE_NULL and calling unref on the pipeline, memory appears to be not freed.
After every restart, the memory associated with the process keeps increasing.
I was able to reproduce the problem with just videotestsrc-fakesink elements as given below :
//g++ -Wall testpage_Simple.cpp -o testpage_Simple $(pkg-config --cflags --libs gstreamer-1.0)
#include <gst/gst.h>
GstElement *pipeline;
GstElement *src;
GstElement *sink;
void clearPipeline () {
// g_print ("clearPipeline ");
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (pipeline);
}
void createPipeline () {
pipeline = gst_pipeline_new ("pipelinePlay");
src = gst_element_factory_make ("videotestsrc", "source");
sink = gst_element_factory_make ("fakesink", "sink");
gst_bin_add_many (GST_BIN (pipeline), src, sink, NULL);
if (gst_element_link (src, sink)!= TRUE) {
g_printerr ("src, sink could not be linked.\n");
}
gst_element_set_state (pipeline, GST_STATE_PLAYING);
}
gint main (gint argc, gchar * argv[])
{
gst_init (NULL, NULL);
system("gst-launch-1.0 --gst-version");
g_print ("Start Test - ");
// for (int i=1; i<=10; i++) {
system ("top -b -n 1 | grep testpage | awk '{print $6}'");
createPipeline();
clearPipeline();
// }
g_print ("End of test !! ");
system ("top -b -n 1 | grep testpage | awk '{print $6}'");
gst_deinit();
return 0;
}
Sample output on Ubuntu 19.04 (showing only RES column value from top command for this process):
GStreamer Core Library version 1.16.1
Start Test - 7140
End of test !! 8504
We observed similar memory trend on Ubuntu 18.04 with gstreamer 1.12.4 as well.
Is this the expected behavior or did I miss something in cleaning up the pipeline ??
I checked the below link. It appears to be a similar problem, but this question is unanswered
GStreamer memory leak after the pipeline restart
I tried the disk cache suggestion in the below link, with a similar problem. But that did not help as well.
http://gstreamer-devel.966125.n4.nabble.com/Properly-freeing-resources-td4658631.html
Just a guess, maybe the problem is related to possible state transitions for elements
according
https://gstreamer.freedesktop.org/documentation/additional/design/states.html?gi-language=c#
the following state changes are possible:
NULL -> READY:
The element must check if the resources it needs are available. Device sinks and sources typically try to probe the device to constrain their caps.
The element opens the device, this is needed if the previous step requires the device to be opened.
READY -> PAUSED:
The element pads are activated in order to receive data in PAUSED. Streaming threads are started.
Some elements might need to return ASYNC and complete the state change when they have enough information. It is a requirement for sinks to return ASYNC and complete the state change when they receive the first buffer or EOS event (preroll). Sinks also block the dataflow when in PAUSED.
A pipeline resets the running_time to 0.
Live sources return NO_PREROLL and don't generate data.
PAUSED -> PLAYING:
Most elements ignore this state change.
The pipeline selects a clock and distributes this to all the children before setting them to PLAYING. This means that it is only allowed to synchronize on the clock in the PLAYING state.
The pipeline uses the clock and the running_time to calculate the base_time. This base_time is distributed to all children when performing the state change.
Sink elements stop blocking on the preroll buffer or event and start rendering the data.
Sinks can post the EOS message in the PLAYING state. It is not allowed to post EOS when not in the PLAYING state.
While streaming in PAUSED or PLAYING elements can create and remove sometimes pads.
Live sources start generating data and return SUCCESS.
PLAYING -> PAUSED:
Most elements ignore this state change.
The pipeline calculates the running_time based on the last selected clock and the base_time. It stores this information to continue playback when going back to the PLAYING state.
Sinks unblock any clock wait calls.
When a sink does not have a pending buffer to play, it returns ASYNC from this state change and completes the state change when it receives a new buffer or an EOS event.
Any queued EOS messages are removed since they will be reposted when going back to the PLAYING state. The EOS messages are queued in GstBins.
Live sources stop generating data and return NO_PREROLL.
PAUSED -> READY:
Sinks unblock any waits in the preroll.
Elements unblock any waits on devices
Chain or get_range() functions return FLUSHING.
The element pads are deactivated so that streaming becomes impossible and all streaming threads are stopped.
The sink forgets all negotiated formats
Elements remove all sometimes pads
READY -> NULL:
Elements close devices
Elements reset any internal state.
if the current state is playing then st. like
gst_element_set_state (pipeline, GST_STATE_PAUSED);
gst_element_set_state (pipeline, GST_STATE_READY);
gst_element_set_state (pipeline, GST_STATE_NULL);
might help
Checking the return value of gst_element_set_state(...) might not be a bad idea either :)

GStreamer c++ - seeking before starting any playback

I added an start-offset option to my C++ application using the GStreamer library. It basically tells the application to start mid-video instead of playing from the beginning.
The pipeline is created like this: filesrc location="file_path" ! qtdemux ! h264parse ! mppvideodec ! waylandsink. This is what gives me best results on my hardware, and I'm running under Weston (wayland)
I do the seeking with a simple gst_element_seek on the pipeline. First I tried waiting until the pipeline changes state to PLAYING or PAUSED in the bus, and then seeking once. This worked, but on some larger videos it produced an effect that after launching the app, the first video frame is displayed for a glimpse of a second and then the video actually jumps to the desired position. I don't want that, I'd like to jump right to where I want without displaying anything else earlier.
So I changed my seeking method to happen before I even set the pipeline to PLAYING state like this:
// seek if needed
if(startTime > 0) {
// First set pipeline to PAUSED and wait for async state change
gst_element_set_state(m_pipeline, GST_STATE_PAUSED);
gst_element_get_state(m_pipeline, nullptr, nullptr, GST_CLOCK_TIME_NONE);
if (!gst_element_seek (m_pipeline, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, startTime, GST_SEEK_TYPE_NONE, -1)) {
g_print ("Seek failed!\n");
}
gst_element_get_state(m_pipeline, nullptr, nullptr, GST_CLOCK_TIME_NONE); // wait for seek to finish and then set to PLAYING
}
m_ret = gst_element_set_state(m_pipeline, GST_STATE_PLAYING);
if (m_ret == GST_STATE_CHANGE_FAILURE) {
g_printerr("Unable to set the pipeline to the playing state.\n");
gst_object_unref(m_pipeline);
exit(0);
}
And while this also works, it unfortunately produces the exact same effect as before...the first frame is still being displayed even though the seek happens before the pipeline is started.
How can I ensure that nothing is displayed until the seek is actually done?
Update
I couldn't get any method of seeking to work like I wanted, but I achieved the effect by setting the show-preroll-frame on the GstVideoSink before constructing the pipeline, like that:
m_sink = gst_element_factory_make("waylandsink", "sink");
g_object_set(m_sink, "show-preroll-frame", FALSE, NULL); // prevent preroll frame when seeking
And it works! I'll use it for now if there's no better way. The seek is still done in PAUSED state, but video is displayed directly from the seeking point.
As the documentation of the gst_element_seek_simple method says:
Some elements allow for seeking in the READY state...
This is true if the pipeline is completely prerolled before the seek.
Then you can get the result you expect, showing only the frames you expect.
gst_element_set_state(m_pipeline, GST_STATE_READY);
//make sure all the pipeline is prerolled (dynamic pads linked and other stuff)
if (!gst_element_seek (m_pipeline, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, startTime, GST_SEEK_TYPE_NONE, -1)) {
g_print ("Seek failed!\n");
}
gst_element_get_state(m_pipeline, nullptr, nullptr, GST_CLOCK_TIME_NONE);

How to restart a pipeline when it is in playing state

I have a pipeline, which is in playing state,
GST_STATE_PLAYING
Now, after a while, when some certain condition met, i would like to restart the same pipeline.
How can i achieve this?
It depends on the situation as stated here
You can put it into NULL and then PLAYING:
gst_element_set_state(pipeline, GST_STATE_NULL);
//do your stuff for example, change some elements, remove some elements etc:
gst_element_set_state(pipeline, GST_STATE_PLAYING);
Or you can just put it into READY(replace NULL with READY in above code) and set some parameters which should work I guess..
Regarding sync/async etc of the gst_element_set_state check docs here

How to solve failing gstreamer assertions in a simple TcpServerSrc to TcpServerSink pipeline

I currently have a simple pipeline consisting of a tcpserversrc that relays its input a tcpserversink. But this pipeline repeats the following 4 error messages every g_main_loop iteration.
(dmp-server:9726): GStreamer-CRITICAL **: gst_mini_object_ref: assertion 'mini_object != NULL' failed
(dmp-server:9726): GStreamer-CRITICAL **: gst_caps_get_structure: assertion 'GST_IS_CAPS (caps)' failed
(dmp-server:9726): GStreamer-CRITICAL **: gst_structure_has_field: assertion 'structure != NULL' failed
(dmp-server:9726): GStreamer-CRITICAL **: gst_mini_object_unref: assertion 'mini_object != NULL' failed
in the constructor of my object I intialise the Gstreamer elements as follows
GMainLoop* loop = g_main_loop_new(nullptr, false);
GstElement* pipeline = gst_pipeline_new("tcp_bridge");
GstElement* source = gst_element_factory_make("tcpserversrc", "recv");
GstElement* sink = gst_element_factory_make("tcpserversink", "send");
GstBus* bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline))
uint16_t recv_port = 2000
uint16_t send_port = 2001
if (!pipeline || !source || !sink)
{
throw std::runtime_error("Could not create the pipeline components for this radio.");
}
g_object_set(G_OBJECT(source), "port", gint(recv_port), nullptr);
g_object_set(G_OBJECT(sink), "port", gint(send_port), nullptr);
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
gst_bus_add_watch (bus, bus_call, this);
gst_bin_add_many (GST_BIN(pipeline), source, sink, nullptr);
gst_element_link_many(source, sink, nullptr);
In a separate function I call the g_main_loop_run() function
The errors suggest something about caps, but the documentation does not suggest it is required for the tcpserver sinks and or sources. 2 other pipelines that decode to and encode from mp3 as well as send to and receive from this pipeline both have no caps attached to them and no assertions fail in those pipelines.
I also should say that the pipeline operates normally, which does not mean my code isn't erroneous, but I find the CRITICAL assertions a bit awkward if the pipeline still works as intended. The main reason I want to get rid of the messages is a possible bug that might come back to bite me and the massive output that clogs up my application log.
In this case the tcpServerSink did not know what it was sending and this triggered the assertions. So in my case as I was streaming MP3 audio over this pipeline I had to add a mpegaudioparse element to my pipeline.
This ensured that the tcpserversink knew what it was about to send (it set the caps) so that it no longer spawns those assertions.
Some tips when facing the same issues, use the G_DEBUG=fatal_warnings environment variable in conjunction with a debugger to get a stacktrace to identify the component that has failing (critical) assertions.
this is a summary and a slight variation to the stackoverflow question found here: gst-launch with tcpserversink not working