GNOME Bugzilla – Bug 746808
Queue with min-threshold stalls dynamic pipeline
Last modified: 2015-04-06 21:50:54 UTC
Created attachment 300348 [details] Test application that stalls the pipeline I'm not 100% sure whether this is a bug or a mistake on my part. I have attached the test application I'm using. I have a pipeline that looks like this audiotestsrc is-live=true ! queue min-threshold-time=3s ! fakesink Running that pipeline works as I expect. The pipeline position stays at 0 while the level in the buffer is filling to 3s, and then the pipeline position starts to increase. Now, I want to change the sink at some point, keeping the cached data in the queue. 8 seconds after starting the pipeline, I add a blocking probe to the srcpad of the queue. In the probe callback I do the following: 1. Set the state of the sink to NULL 2. Remove the sink from the pipeline 3. Add a second fakesink element to the pipeline 4. Link the queue and the second fakesink 5. Sync the state of the second fakesink to the pipeline I would expect the pipeline to continue running with the new sink in place. What I'm actually seeing is that the sink is prerolled with a single buffer, and then nothing more happens. The queue is not getting any buffers even though all elements in the pipeline reports as PLAYING, if I save a dot graph. If I don't set min-threshold on the queue, data is flowing after I have changed the sink.
It seems to be working here at first glance: Buit with: gcc `pkg-config --cflags gstreamer-1.0 glib-2.0 gobject-2.0` -o minimal minimal.c `pkg-config --libs gstreamer-1.0 glib-2.0 gobject-2.0` Run with: ./minimal Typical output: $ ./minimal Pipeline position: 0:00:01.626144737, Queue level: 0:00:00.000000000 Pipeline position: 0:00:02.624602787, Queue level: 0:00:00.000000000 Pipeline position: 0:00:03.623060837, Queue level: 0:00:00.000000000 Pipeline position: 0:00:04.621518887, Queue level: 0:00:00.000000000 Pipeline position: 0:00:05.619976936, Queue level: 0:00:00.000000000 Pipeline position: 0:00:06.618434986, Queue level: 0:00:00.000000000 Pipeline position: 0:00:07.616893036, Queue level: 0:00:00.000000000 Pipeline position: 0:00:00.000000000, Queue level: 0:00:00.000000000 Pipeline position: 0:00:09.613809136, Queue level: 0:00:00.000000000 Pipeline position: 0:00:10.612267186, Queue level: 0:00:00.000000000 Pipeline position: 0:00:11.610725236, Queue level: 0:00:00.000000000 Pipeline position: 0:00:12.609183286, Queue level: 0:00:00.023219955 ^C If I run with GST_DEBUG=*SCHED*:9, I see buffers flowing to the sink well after the 8 second mark. Is this not what you're seeing, or am I misunderstanding what you're describing ?
I accidentally uploaded the file where I have set min-threshold-time to 0. Sorry about that. For a min-threshold-time of 0 I can confirm your findings above. The problem appears when min-threshold-time is set to a non-zero value. Try changing line 21 to g_object_set (queue, "min-threshold-time", 3 * GST_SECOND, I get this output Pipeline position: 0:00:00.000000000, Queue level: 0:00:00.836485486 Pipeline position: 0:00:00.000000000, Queue level: 0:00:01.834943536 Pipeline position: 0:00:00.000000000, Queue level: 0:00:02.833401586 Pipeline position: 0:00:00.813265531, Queue level: 0:00:02.995374150 Pipeline position: 0:00:01.834943536, Queue level: 0:00:02.995374150 Pipeline position: 0:00:02.833401586, Queue level: 0:00:02.995374150 Pipeline position: 0:00:03.831859636, Queue level: 0:00:02.995374150 Pipeline position: 0:00:00.038213632, Queue level: 0:00:02.995374150 Pipeline position: 0:00:04.853537640, Queue level: 0:00:02.995374149 Pipeline position: 0:00:04.853537640, Queue level: 0:00:02.995374149 Pipeline position: 0:00:04.853537640, Queue level: 0:00:02.995374149 Pipeline position: 0:00:04.853537640, Queue level: 0:00:02.995374149 Pipeline position: 0:00:04.853537640, Queue level: 0:00:02.995374149 Notice have neither the queue level nor the position is increasing.
I get the same stalling behavior as you now.
What seems to be happening is that an allocation query is sent from the source after the second sink is plugged, and is pushed onto the queue's, er, queue. Normally, the queue's thread will push whatever's in the queue's queue if possible. If the first item is not a buffer or buffer list (for instance, if it is an allocation query), it will be sent. However, in this case, the allocation query is at the end of the queue's queue, which happens not to be its head too as there's close to 3 seconds' worth of buffers waiting there. One more buffer incoming would cause the queue to push again, but it's now waiting for the allocation query to be answered from upstream, which it won't since the push thread isn't pushing. I can't clear the queue, as it would drop those three seconds. Maybe I could slip the allocation query in front of the queue, which would work I think, but I'm not sure how best to select which set of events/queries to prepend instead of append. In general, we want to keep ordering between buffers and events. Worse, gst/gstquery.h shows the allocation query to be serialized. Another possibility would be to temporarily disregard the min-threshold when an allocation query (and maybe a set of other events/queries) is received, until this query (or other event/query) has been pushed by the queue's thread. This would seem to be like a good compromise, but (1) might upset whatever caused min-threshold to be used (unfluid playback ?), and (2) would also need to choose which set of events/queries would cause this temporary override. Any gst maintainer with an opinion on this ?
It looks like expected behaviour to me. Jesper, what are you trying to achieve here exactly?
I'm trying to do a "delayed" recording of a live source. Meaning that I want to keep x seconds of buffer such that I can start saving buffers to file where the first buffer saved would be from x seconds ago. What seems odd is that the queue is not getting fed with buffers from the live source. When the pipeline is first started, the queue is not forwarding buffers until it reaches the min-threshold. However, the queue is receiving buffers. If the sink is changed the queue no longer receives buffers, which means it never pushes buffers to the new sink. I currently workaround this by setting the min-threshold to 0 when the sink is changed, and then resetting the min-threshold to x seconds when the new sink reaches PLAYING. I guess this is basically the same Vincent suggests by temporarily disregarding the min-threshold.
It sounds like what you want is basically a 'backbuffer'. When you start recording, you want to include data from a few seconds before the record button was hit. http://people.freedesktop.org/~tpm/code/test-backlog-recording-h264.c Implements that using a different approach: it uses a leaky queue with a pad block. While the pad is blocked, old buffers are getting dropped. The same should happen to any allocation query in that case.
Thanks for the link. It seems to be a better approach than my current workaround. The current min-threshold behaviour still seems odd to me though, but at least I can work around it.
It still seems wrong to be that the queue hangs, as the reconfigure query is an implementation detail from the point of view of the min-threshold high level behavior.
The allocation query is serialised. That causes some problems, but also solves some other problems. In any case, that's how it is. I don't see what we can do here. (I also think we should deprecate that min-threshold property)
Created attachment 301030 [details] [review] deprecate min-threshold-* Here's a patch that deprecates those properties as you suggested. And then this can be closed as invalid.
More like WONTFIX than INVALID :) But I'd like to hear from more people before deprecating that property.