After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 739010 - Move GstAggregator from -bad to gstreamer (core)
Move GstAggregator from -bad to gstreamer (core)
Status: RESOLVED FIXED
Product: GStreamer
Classification: Platform
Component: gstreamer (core)
git master
Other All
: Normal enhancement
: 1.13.1
Assigned To: GStreamer Maintainers
GStreamer Maintainers
: 532944 (view as bug list)
Depends on: 731301 741146 742684 760981
Blocks: 739011
 
 
Reported: 2014-10-22 14:57 UTC by Thibault Saunier
Modified: 2017-12-27 16:38 UTC
See Also:
GNOME target: ---
GNOME version: ---



Description Thibault Saunier 2014-10-22 14:57:55 UTC
The GstAggregator base class should be moved to GStreamer core.
Comment 1 Tim-Philipp Müller 2014-10-22 15:05:53 UTC
+1, but would like to do a quick API review first.
Comment 2 Olivier Crête 2014-10-31 14:37:18 UTC
TODO: Support GAP events
Comment 3 Olivier Crête 2014-11-12 22:30:05 UTC
API comment: I think the gst_element_add_pad() shouldn't be in the base class, as we want the subclass to be able to add things to the pad before it is exposed. Or are we expected all these things to be done in the GstAggregatorPad subclass ? Either way, either the code needs changing, or it should be documented.
Comment 4 Thibault Saunier 2014-11-12 22:44:33 UTC
(In reply to comment #3)
> API comment: I think the gst_element_add_pad() shouldn't be in the base class,
> as we want the subclass to be able to add things to the pad before it is
> exposed. Or are we expected all these things to be done in the GstAggregatorPad
> subclass ? Either way, either the code needs changing, or it should be
> documented.

Everything is supposed to be in subclasses of GstAggregatorPad, we should probably document that indeed.
Comment 5 Olivier Crête 2014-11-13 19:58:26 UTC
The timeout seems to be using the System clock, I think that's very wrong, it should be using the pipeline clock instead, ie GST_ELEMENT_CLOCK().
Comment 6 Olivier Crête 2014-11-13 22:48:58 UTC
The use of a GST_FLOW_EOS return value from the ->aggregate method to mean that that everything is OK, but we're at EOS is at best strange. Wouldn't it be better to have the GstAggregator base class check that if every pad is at EOS, then it can push EOS?
Comment 7 Olivier Crête 2014-11-13 23:47:55 UTC
I think the timeout functionality should also probably be based on the buffer timestamp, not just on the time where it happens to arrive into the aggregator based element.
Comment 8 Matthew Waters (ystreet00) 2014-11-14 01:03:09 UTC
(In reply to comment #5)
> The timeout seems to be using the System clock, I think that's very wrong, it
> should be using the pipeline clock instead, ie GST_ELEMENT_CLOCK().

If we were basing it off buffer timestamps then yes, the pipeline clock would be more suitable.

(In reply to comment #7)
> I think the timeout functionality should also probably be based on the buffer
> timestamp, not just on the time where it happens to arrive into the aggregator
> based element.

Why, what conceptual problem does that fix?

It's actually based on the time between when the buffer is consumed by the subclass to when the next upstream buffer arrives.  If the buffer has not arrived after the timeout, then the pad is unresponsive and we don't wait for it.  I thought of it as the time between data was here and the deadline when data needs to be here in order to continue processing.
Comment 9 Olivier Crête 2014-11-14 02:02:50 UTC
The unresponsive functionality should inform the subclass at which time it is now, according to the pipeline clock, that way, the subclass can fill in the right amount of "gap data", but not more. I guess this could also be used to process incoming GAP events and give them to the subclasses.
Comment 10 Olivier Crête 2014-11-14 02:09:11 UTC
(In reply to comment #8)
> (In reply to comment #5)
> > The timeout seems to be using the System clock, I think that's very wrong, it
> > should be using the pipeline clock instead, ie GST_ELEMENT_CLOCK().
> 
> If we were basing it off buffer timestamps then yes, the pipeline clock would
> be more suitable.

Because we want the timeouts to follow the speed at which it is displayed, which is based on the pipeline clock. We really have no guarantees that this clock has anything to do with the system clock. Also, you add it to the latency query, and you can only do that if you use the pipeline clock, you're comparing apples and oranges.

> (In reply to comment #7)
> > I think the timeout functionality should also probably be based on the buffer
> > timestamp, not just on the time where it happens to arrive into the aggregator
> > based element.
> 
> Why, what conceptual problem does that fix?
> 
> It's actually based on the time between when the buffer is consumed by the
> subclass to when the next upstream buffer arrives.  If the buffer has not
> arrived after the timeout, then the pad is unresponsive and we don't wait for
> it.  I thought of it as the time between data was here and the deadline when
> data needs to be here in order to continue processing.

I think it should work along the same lines as rtpjitterbuffer. So the variable we want to control is how long can useful data stay in the aggregator before it is pushed out. And that should be based on the oldest valid unit of data stuck in the aggregator.
Comment 11 Olivier Crête 2014-11-14 02:12:03 UTC
Basically, to fulfill the latency promise made in the response to the latency query, a buffer has to exit the element when the pipeline clock reaches buffer_in_running_time + element_latency + upstream_latency at the latest.
Comment 12 Olivier Crête 2014-11-14 05:39:28 UTC
Another thing, it's missing an API for subclasses to set the amount of latency they are adding.
Comment 13 Matthew Waters (ystreet00) 2014-11-14 11:30:01 UTC
(In reply to comment #9)
> The unresponsive functionality should inform the subclass at which time it is
> now, according to the pipeline clock, that way, the subclass can fill in the
> right amount of "gap data", but not more. I guess this could also be used to
> process incoming GAP events and give them to the subclasses.

That's handled elsewhere by the subclasses atm.  GstAggregator currently doesn't deal at all with how the data is matched against stream times.

(In reply to comment #10)
> Because we want the timeouts to follow the speed at which it is displayed,
> which is based on the pipeline clock. We really have no guarantees that this
> clock has anything to do with the system clock. Also, you add it to the latency
> query, and you can only do that if you use the pipeline clock, you're comparing
> apples and oranges.

The speed of what? display? Why would you dynamically adjust the timeout based on some speed?

I think that some small duration in two separate clocks will amount to a close enough elapsing of time that it does not make a difference.

> > (In reply to comment #7)
> I think it should work along the same lines as rtpjitterbuffer. So the variable
> we want to control is how long can useful data stay in the aggregator before it
> is pushed out. And that should be based on the oldest valid unit of data stuck
> in the aggregator.

Which is exactly the same as 'if a buffer does not occur on a pad after the timeout, ignore it and generate a frame anyway'.

ASCII diagram :)

b1, b2, b3 = buffer
f = generated frame
| = timeout occurences

----- running time ------>
. timeout |(b1)  timeout |(b2)|(b3)
b1- - - - - - - - - b3- - - - - -  -> to sink1
- - - - - - - b2- - - - - - - - -  -> to sink2
__________f__________f________f

As is visible from the great diagram, a frame is generated at most after the timeout has occured.

(In reply to comment #11)
> Basically, to fulfill the latency promise made in the response to the latency
> query, a buffer has to exit the element when the pipeline clock reaches
> buffer_in_running_time + element_latency + upstream_latency at the latest.

Which is upheld in the current code.

(In reply to comment #12)
> Another thing, it's missing an API for subclasses to set the amount of latency
> they are adding.

Subclasses can override the latency query where they call the base class and then add their own if they need.
Comment 14 Matthew Waters (ystreet00) 2014-11-14 11:38:11 UTC
Another consideration that was brought to my attention is that if you take a random pipeline clock it might only advance while the pipeline is playing and we do want to timeout a pad in paused so that we are not forever waiting to generate a buffer because of a buffer that's never going to arrive.
Comment 15 Sebastian Dröge (slomo) 2014-11-14 12:08:19 UTC
Also rtpjitterbuffer was mentioned here... but last time I checked it was using the system clock unconditionally.
Comment 16 Olivier Crête 2014-11-14 16:47:31 UTC
(In reply to comment #13)
> (In reply to comment #9)
> > The unresponsive functionality should inform the subclass at which time it is
> > now, according to the pipeline clock, that way, the subclass can fill in the
> > right amount of "gap data", but not more. I guess this could also be used to
> > process incoming GAP events and give them to the subclasses.
> 
> That's handled elsewhere by the subclasses atm.  GstAggregator currently
> doesn't deal at all with how the data is matched against stream times.

But knowing the deadline would be useful to the subclasses, I'm currently trying to implement a raw audio subclass based on the audiomixer code and porting interleave to us it as I need a synchronized interleave.

> (In reply to comment #10)
> > Because we want the timeouts to follow the speed at which it is displayed,
> > which is based on the pipeline clock. We really have no guarantees that this
> > clock has anything to do with the system clock. Also, you add it to the latency
> > query, and you can only do that if you use the pipeline clock, you're comparing
> > apples and oranges.
> 
> The speed of what? display? Why would you dynamically adjust the timeout based
> on some speed?

The speed of the clock. If the pipeline clock is a bit faster than the system clock, then every packet will arrive late at the sink.

> I think that some small duration in two separate clocks will amount to a close
> enough elapsing of time that it does not make a difference.

Most clocks go about the same speed, why do we even bother with having a pipeline clock then? If we want it in core, let's do it right.

> > > (In reply to comment #7)
> > I think it should work along the same lines as rtpjitterbuffer. So the variable
> > we want to control is how long can useful data stay in the aggregator before it
> > is pushed out. And that should be based on the oldest valid unit of data stuck
> > in the aggregator.
> 
> Which is exactly the same as 'if a buffer does not occur on a pad after the
> timeout, ignore it and generate a frame anyway'.
> 
> ASCII diagram :)
> 
> b1, b2, b3 = buffer
> f = generated frame
> | = timeout occurences
> 
> ----- running time ------>
> . timeout |(b1)  timeout |(b2)|(b3)
> b1- - - - - - - - - b3- - - - - -  -> to sink1
> - - - - - - - b2- - - - - - - - -  -> to sink2
> __________f__________f________f
> 
> As is visible from the great diagram, a frame is generated at most after the
> timeout has occured.

I think that the mistake you're making is assuming that the time where the buffer is entering the aggregator is a useful point to start from even though we have no idea if it's early or it's late. I think all of this should be based on the time when it should reach the sink (ie, the buffer timestamp).

> (In reply to comment #11)
> > Basically, to fulfill the latency promise made in the response to the latency
> > query, a buffer has to exit the element when the pipeline clock reaches
> > buffer_in_running_time + element_latency + upstream_latency at the latest.
> 
> Which is upheld in the current code.

It's not, you're waiting on a completely different clock which for all we know could go measurably slower.

> (In reply to comment #12)
> > Another thing, it's missing an API for subclasses to set the amount of latency
> > they are adding.
> 
> Subclasses can override the latency query where they call the base class and
> then add their own if they need.

They could, but it would be nice to a gst_aggregator_set_latency() like the encoder & decoder base classes, it's quite handy.


(In reply to comment #14)
> Another consideration that was brought to my attention is that if you take a
> random pipeline clock it might only advance while the pipeline is playing and
> we do want to timeout a pad in paused so that we are not forever waiting to
> generate a buffer because of a buffer that's never going to arrive.

The whole thing is really only for live sources. On a non-live sources, you can read more data or get a EOS, so this timeout doesn't apply. On a live stream, you won't get any buffers unless you're in playing anyway.

(In reply to comment #15)
> Also rtpjitterbuffer was mentioned here... but last time I checked it was using
> the system clock unconditionally.

That's just factually not true. rtpjitterbuffer proposes the system clock in case there is no other clock in the pipeline. You're probably confused with the optional usage of the system clock to produce the NTP times in rtpsession, but that's always compared to the pipeline clock.
Comment 17 Matthew Waters (ystreet00) 2014-11-14 23:29:36 UTC
(In reply to comment #16)
> But knowing the deadline would be useful to the subclasses, I'm currently
> trying to implement a raw audio subclass based on the audiomixer code and
> porting interleave to us it as I need a synchronized interleave.

So, at aggregate() time, each pad either has data or not with which your element deals with accordingly.  If a pad doesn't have data then it timed out at some point previously and you render black/silence/nothing/absence of something.

> > (In reply to comment #10)
> The speed of the clock. If the pipeline clock is a bit faster than the system
> clock, then every packet will arrive late at the sink.

So, just add the miniscule difference to the 'processing latency' and be done with it.  Besides the clock isn't going to wake you up at exactly the time you asked for anyway.

> > I think that some small duration in two separate clocks will amount to a close
> > enough elapsing of time that it does not make a difference.
> 
> Most clocks go about the same speed, why do we even bother with having a
> pipeline clock then? If we want it in core, let's do it right.

Because clocks drift over time.  For small timeouts/durations they are close enough.

> I think that the mistake you're making is assuming that the time where the
> buffer is entering the aggregator is a useful point to start from even though
> we have no idea if it's early or it's late. I think all of this should be based
> on the time when it should reach the sink (ie, the buffer timestamp).

No, it's the time that the buffer *leaves* the aggregator that is used for the start of the timeout.  The buffer entering only cancels the timeout.

> > (In reply to comment #11)
> It's not, you're waiting on a completely different clock which for all we know
> could go measurably slower.

See above.

> > (In reply to comment #12)
> They could, but it would be nice to a gst_aggregator_set_latency() like the
> encoder & decoder base classes, it's quite handy.

Sure :)

> (In reply to comment #14)
> > Another consideration that was brought to my attention is that if you take a
> > random pipeline clock it might only advance while the pipeline is playing and
> > we do want to timeout a pad in paused so that we are not forever waiting to
> > generate a buffer because of a buffer that's never going to arrive.
> 
> The whole thing is really only for live sources. On a non-live sources, you can
> read more data or get a EOS, so this timeout doesn't apply. On a live stream,
> you won't get any buffers unless you're in playing anyway.

It could also be useful for non-live sources to have a live mixer drop frames if they take too long to produce so the pipeline can still render other streams that arrive in time.  Say adding a new stream to an aggregator sink pad which could take a while to set up.
Comment 18 Olivier Crête 2014-11-15 05:14:33 UTC
Another question is why push the "mandatory events" inside gst_aggregator_set_src_caps() instead of waiting for the next call to gst_aggregator_finish_buffer(). In audiomixer, there has to be code to delay it anyway.
Comment 19 Matthew Waters (ystreet00) 2014-11-15 07:38:36 UTC
(In reply to comment #18)
> Another question is why push the "mandatory events" inside
> gst_aggregator_set_src_caps() instead of waiting for the next call to
> gst_aggregator_finish_buffer(). In audiomixer, there has to be code to delay it
> anyway.

So that subclasses can perform allocation queries which require caps to be set beforehand and propagated to the surrounding elements.
Comment 20 Olivier Crête 2014-11-15 17:26:25 UTC
gst_aggregator_iterate_sinkpads() should be renamed to gst_aggregate_sink_pads_foreach() or something like that. In python, the aggregator element will have a .iterate_sink_pads() which returns a GstIterator and a .iterate_sinkpads() which does the iteration. It should probably be name. Actually, this should probably be added to GstIterator, something like gst_iterator_foreach_once().
Comment 21 Olivier Crête 2014-11-15 18:59:03 UTC
(In reply to comment #19)
> So that subclasses can perform allocation queries which require caps to be set
> beforehand and propagated to the surrounding elements.

The base class should probably implement most of that logic and call a "decide_allocation" into the subclass, like GstBaseSrc is doing. That seems to be logic that would be the same in all subclasses .
Comment 22 Olivier Crête 2014-11-15 21:54:51 UTC
The locking requirements to access/modify the members of the object should be documented, is it the srcpad stream lock or the object lock ?
Comment 23 Olivier Crête 2014-11-15 21:56:27 UTC
The segment in the GstAggregator struct, what lock protects it?
Comment 24 Olivier Crête 2014-11-15 23:51:34 UTC
While I'm looking at the locking, it seems to be lacking. For example, priv->flow_return is unprotected too. I recommend documenting the lock, or why it's not needed, for each member variable, it will also help other people understand the code later.
Comment 25 Olivier Crête 2014-11-17 04:41:44 UTC
I've been giving the timeout thing a bit more thought, and I've come to believe that we're looking at it from the wrong side. Instead of declaring that a sink pad is unresponsive after a timeout, the srcpad should operate on a deadline. For example, with videomixer, we generally want to produce an output buffer every 1/x FPS, so when we push out a buffer, we know exactly when is the last possible moment to push out the next buffer. For the audiomixer, we also know this deadline. This deadline is then the time when we should wake up the srcpad task loop and call the aggregate function if enough data was not yet received. Obviously, if enough data was received, the GstAggregator should call aggregate earlier so as to push out the buffer as soon as possible. 
So instead of having a "unresponsive" flag on each pad, I'd just have a deadline-reached variable for the entire element, and then aggregate everything there at this point.

Also, to make this alternate design race-free, we'd need to add a queue inside the GstAggregatorPad that would buffer up to "timeout" buffers to make sure they're directly available when the deadline is reached.

To match other elements, we should rename "timeout" into "latency".

Lookinag at the QoS event handling (bug #739996), which I think should also be in the GstAggregator class which should export a gst_aggregator_get_earliest_time().
Comment 26 Olivier Crête 2014-11-19 02:57:07 UTC
Another bug I'm hitting.. what happens if all the pads become unresponsive at the same time. With the current design, the aggregate_func runs in a loop forever. I tried adding some code to stop the loop and wait for a buffer, but that means that some data can get stuck in the aggregator until enough data arrives on one pad.. As for audio, we may need multiple input buffers to fill an output buffer. A dead-line based approach wouldn't have that issue.
Comment 27 Olivier Crête 2014-11-19 21:28:12 UTC
Actually, right now if all pads are unresponsive, VideoAggregator goes into a loop and audiomixer just returns EOS and stops.
Comment 28 Sebastian Dröge (slomo) 2014-11-26 16:02:43 UTC
There should also be decide_allocation / propose_allocation vfuncs for ALLOCATION query handling I guess. Consistency with other base classes.

Might also make sense to check other base classes for other common vfuncs that people found useful :)
Comment 29 Olivier Crête 2014-11-26 19:00:12 UTC
I'm unsure if we should do a decide_allocation() like basesrc where one only modifies the GstQuery object, and then have the GstAggregator baseclass activate the pool & allocator, or just have a do_allocation() and leave more leeway to the subclasses on what to do.
Comment 30 Sebastian Dröge (slomo) 2014-12-04 17:12:37 UTC
After discussions on IRC, we should change this timeout stuff. First of all the property should be called "latency" instead. And then, whenever at least one upstream of aggregator is live, the srcpad thread of aggregator runs against a deadline. And it puts into the output buffer whatever frames are available at this time. The deadline would be based on the running time of the to be produced frame, the maximum upstream latency and the latency property, and would be according to the pipeline clock.

If none of the upstreams of aggregator is live, we can continue with what is currently done.
Comment 31 Thibault Saunier 2014-12-31 11:26:03 UTC
> After discussions on IRC, we should change this timeout stuff. First of all the
> property should be called "latency" instead. And then, whenever at least one
> upstream of aggregator is live, the srcpad thread of aggregator runs against a
> deadline. And it puts into the output buffer whatever frames are available at
> this time. The deadline would be based on the running time of the to be
> produced frame, the maximum upstream latency and the latency property, and
> would be according to the pipeline clock.
> 
> If none of the upstreams of aggregator is live, we can continue with what is
> currently done.

That has been implemented at: https://bugzilla.gnome.org/show_bug.cgi?id=741146

@tim: GstAggregator should be introspectable, I do not see what would be a problem for that. I think we should just make sure of that while we move the aggregator to core the introspection is happy so that we do not invent a new typelib in -bad for nothing. (In reply to comment #30)


What else should be done? I have the impression that all issues that were raised are now fixed.
Comment 32 Tim-Philipp Müller 2014-12-31 12:41:52 UTC
Thibault, I don't think I commented on introspectability anywhere? I just added a dependency on bug #731301 yesterday. I don't think it's going to be a problem, and I agree there's no point in adding a short-lived typelib in bad for nothing.

One thing I'm not so sure about is the GstAggregatorClass::sinkpads_type member: is this really a good idea? And good for bindings? It seems to be only used for creating a pad, why not just make a vfunc for that instead then?

What else needs to be done IMHO:

It would be good to move the sink pad iteration to core perhaps if we can agree on a reasonable API. I wouldn't mind adding something like gst_iterator_once_foreach_pad / gst_iterator_once_foreach_element (so the callback gets the real type pointer instead of a GValue), for example.

We should also try to port a muxer over. I started with oggmux yesterday.

Another minor thing I was wondering about: why is gint64 latency from the property in the public structure? I think it should be in the private structure. Nothing uses it and we would have to define access
Comment 33 Tim-Philipp Müller 2014-12-31 12:43:21 UTC
And I don't think all of Olivier's comments have been addressed, e.g. what about GAP event support?
Comment 34 Thibault Saunier 2014-12-31 14:11:44 UTC
(In reply to comment #32)
> Thibault, I don't think I commented on introspectability anywhere? I just added
> a dependency on bug #731301 yesterday. I don't think it's going to be a
> problem, and I agree there's no point in adding a short-lived typelib in bad
> for nothing.

Right, just wanted to make sure we are on the same page.

> One thing I'm not so sure about is the GstAggregatorClass::sinkpads_type
> member: is this really a good idea? And good for bindings? It seems to be only
> used for creating a pad, why not just make a vfunc for that instead then?

It should not be an issue for bindings, at least for python. The user can already override the request_new_pad vmethod from core and do everything himself, it is really just an helper where we handle padname and that kind of things.

> What else needs to be done IMHO:
> 
> It would be good to move the sink pad iteration to core perhaps if we can agree
> on a reasonable API. I wouldn't mind adding something like
> gst_iterator_once_foreach_pad / gst_iterator_once_foreach_element (so the
> callback gets the real type pointer instead of a GValue), for example.

I agree with that, opening a bug right now.

> We should also try to port a muxer over. I started with oggmux yesterday.

Cool, how is it going so far?

> Another minor thing I was wondering about: why is gint64 latency from the
> property in the public structure? I think it should be in the private
> structure. Nothing uses it and we would have to define access

No sure, slomo?

(In reply to comment #33)
> And I don't think all of Olivier's comments have been addressed, e.g. what
> about GAP event support?

That can be added later fmpov
Comment 35 Mark Nauwelaerts 2014-12-31 16:00:16 UTC
(In reply to comment #34)
> (In reply to comment #32)
> (In reply to comment #33)
> > And I don't think all of Olivier's comments have been addressed, e.g. what
> > about GAP event support?
> 
> That can be added later fmpov

This may be preaching to the choir, but anyway ...

It has taken quite some time and doing to get muxers to handle sparse streams (by means of GstCollectPads[2]), so I hope this "added later" is before muxers get ported to GstAggregator so as not to loose the sparse stream (subtitle) support along the way.
Comment 36 Sebastian Dröge (slomo) 2014-12-31 17:20:11 UTC
(In reply to comment #34)

> > One thing I'm not so sure about is the GstAggregatorClass::sinkpads_type
> > member: is this really a good idea? And good for bindings? It seems to be only
> > used for creating a pad, why not just make a vfunc for that instead then?
> 
> It should not be an issue for bindings, at least for python. The user can
> already override the request_new_pad vmethod from core and do everything
> himself, it is really just an helper where we handle padname and that kind of
> things.

This GType stuff is always a bit awkward for bindings, I would prefer a vfunc for it too that allows to use all the magic from GstAggregator to create a pad but allows the subclass to create a pad itself.

> > It would be good to move the sink pad iteration to core perhaps if we can agree
> > on a reasonable API. I wouldn't mind adding something like
> > gst_iterator_once_foreach_pad / gst_iterator_once_foreach_element (so the
> > callback gets the real type pointer instead of a GValue), for example.
> 
> I agree with that, opening a bug right now.

I think that should be convenience API in GstElement / GstBin, not stuff in GstIterator. Unless you make it a gst_iterator_foreach_once() that is independent of the type.

> > Another minor thing I was wondering about: why is gint64 latency from the
> > property in the public structure? I think it should be in the private
> > structure. Nothing uses it and we would have to define access
> 
> No sure, slomo?

No reason, move it. Everything should be moved to the private structures unless it's actually used by subclasses.
 
> (In reply to comment #33)
> > And I don't think all of Olivier's comments have been addressed, e.g. what
> > about GAP event support?
> 
> That can be added later fmpov

See Mark's comment. No GAP support and no support for sparse streams would be a blocker for this to be moved to core.
Comment 37 Tim-Philipp Müller 2015-01-01 17:37:26 UTC
*** Bug 532944 has been marked as a duplicate of this bug. ***
Comment 38 Tim-Philipp Müller 2015-01-04 12:52:25 UTC
oggmux port to GstAggregator can be found here:
http://cgit.freedesktop.org/~tpm/gst-plugins-base/log/?h=oggmux-aggregator

Couple of issues:

 - we need a replacement/equivalent for
    gst_collectpads_set_waiting() to handle
    sparse streams. I suspect this is not too
    difficult.

 - there seem to be some issues with passing
    the flow returns upstream, probably because
    there has so far been an assumption that every
    call to the ::aggregate() vfunc generates at least
    one output buffer. If that's not the case, and the
    aggregate vfunc returns FLOW_OK when there's
    nothing to do, then that might/will overwrite a
    "bad" flow return from a previous _finish_buffer()
    that had been stored in priv->flow_return.
    Possible solutions:
        1) add custom flow return to distinguish NO_CHANGE from OK
        2) just require sub-classes to track last_flow themselves in this
           case and return the latest and greatest from ::aggregate()
        3) never overwrite (fatal) non-FLOW_OK with FLOW_OK in GstAggregator

 - relatedly, shouldn't pads stuck in _pad_chain () be
    woken up in order to return upstream any non-OK
    flow return immediately? (The assumption seems
    to be that most if not all pads will see buffers popped
    off during aggregation, but that might not be true for
    a muxer or subtitle overlay, and not even for a mixer)

 - aggregator->priv->flow_return access is not thread-safe
   in general (e.g. in gst_aggregator_pad_chain)

 - do we need/want a GstAggregatorPad::reset() vmethod?
   (to reset pad state when shutting down, to make element re-usable)
   Or do we assume that flush == reset?

 - GST_EVENT_TAG handling looks bogus, stream tags
   are merged into one global tag list?! I'm not even sure
   if this makes sense for mixers, but muxers probably
   want access to per-stream tags. non-global tags should
   probably just be dropped and not merged.

 - Not sure I like the naming of
   gst_aggregator_pad_get_buffer() / _steal_buffer().
   This kind of naming is usually about ownership transfer
   and thus doesn't reflect the actually more important part
   of the calls, which is whether the buffer stays on the pad
   or is popped off. I would suggest:

      - gst_aggregator_pad_peek_buffer()
      - gst_aggregator_pad_pop_buffer() or _dequeue_buffer()

   and it's a bit counter-intuitive and inconvenient that get()/peek()
   returns a ref as well (though collectpads does that too). I think
   any caller to get/peek() holds a ref to the pad, so one could be
   sure that any buffer the pad owns is not going to go away while
   we'd be peeking at it.

 - it would be nice if we could incorporate queuing
   functionality on the input side. (Can be added later)

 - gst_aggregator_request_new_pad() should not insist
    on sink pad template name of "sink_%u" (could be
    audio_%u or somesuch too, etc.)

 - I think we should rather add the pad GType to
   GstPadTemplate, which would also be useful for
   gst-inspect.

 - I wonder if the "latency" property should not rather
   be called "extra-latency" ? Or perhaps I misunderstand
   it. The our_latency > data.max comparison in
   gst_aggregator_query_latency() doesn't look right if
   it's extra latency though.
Comment 39 Tim-Philipp Müller 2015-02-07 09:52:01 UTC
Let's punt this to 1.7 then.
Comment 40 Jan Schmidt 2015-03-15 19:12:04 UTC
One thing that GstCollectPads allowed which GstAggregator doesn't do nicely is elements that want to receive data on fixed static pads.

It would be nice to decouple the request pad template and naming from the actual function of GstAggregator. Perhaps a default request_pads implementation that
sub-classes can install on themselves, or use as a function call when creating their own request pads, and a separate function for 'enrolling' pads the sub-class created itself.

Also, I'm not sure about the idea of putting the GType in the GstPadTemplate. GstPadTemplates go into the registry. We could put the string name of the GType, but I don't know how useful that is as gst-inspect output.
Comment 41 Jian Li 2016-06-12 06:58:50 UTC
so any updates for this moving? I see in the trunk, GstAggregator is still in bad pacakge. What's the plan for moving it to core?
Comment 42 Olivier Crête 2017-05-21 17:15:54 UTC
I think we're more or less ready to move to -bad or even core. I think we answered most of Tim's comments already and the other ones are additions.


(In reply to Tim-Philipp Müller from comment #38)
>  - we need a replacement/equivalent for
>     gst_collectpads_set_waiting() to handle
>     sparse streams. I suspect this is not too
>     difficult.

Yep, we should add that, some kind of fnuction to add a static pad.
 
>  - there seem to be some issues with passing
>     the flow returns upstream, probably because
>     there has so far been an assumption that every
>     call to the ::aggregate() vfunc generates at least
>     one output buffer. If that's not the case, and the
>     aggregate vfunc returns FLOW_OK when there's
>     nothing to do, then that might/will overwrite a
>     "bad" flow return from a previous _finish_buffer()
>     that had been stored in priv->flow_return.
>     Possible solutions:
>         1) add custom flow return to distinguish NO_CHANGE from OK

There is now GST_AGGREGATOR_FLOW_NEED_DATA that does that, it will get called back later.


>         2) just require sub-classes to track last_flow themselves in this
>            case and return the latest and greatest from ::aggregate()
>         3) never overwrite (fatal) non-FLOW_OK with FLOW_OK in GstAggregator

>  - relatedly, shouldn't pads stuck in _pad_chain () be
>     woken up in order to return upstream any non-OK
>     flow return immediately? (The assumption seems
>     to be that most if not all pads will see buffers popped
>     off during aggregation, but that might not be true for
>     a muxer or subtitle overlay, and not even for a mixer)

It does that now (it called gst_aggregator_pad_set_flushing() on all pads on non-OK).
 
>  - aggregator->priv->flow_return access is not thread-safe
>    in general (e.g. in gst_aggregator_pad_chain)

all locked now

>  - do we need/want a GstAggregatorPad::reset() vmethod?
>    (to reset pad state when shutting down, to make element re-usable)
>    Or do we assume that flush == reset?

Good question, isnt that the same as ->start() and ->stop()

>  - GST_EVENT_TAG handling looks bogus, stream tags
>    are merged into one global tag list?! I'm not even sure
>    if this makes sense for mixers, but muxers probably
>    want access to per-stream tags. non-global tags should
>    probably just be dropped and not merged.

Muxer type subclasses probably just shouldnt chain up ?

>  - Not sure I like the naming of
>    gst_aggregator_pad_get_buffer() / _steal_buffer().
>    This kind of naming is usually about ownership transfer
>    and thus doesn't reflect the actually more important part
>    of the calls, which is whether the buffer stays on the pad
>    or is popped off. I would suggest:
> 
>       - gst_aggregator_pad_peek_buffer()
>       - gst_aggregator_pad_pop_buffer() or _dequeue_buffer()
> 
>    and it's a bit counter-intuitive and inconvenient that get()/peek()
>    returns a ref as well (though collectpads does that too). I think
>    any caller to get/peek() holds a ref to the pad, so one could be
>    sure that any buffer the pad owns is not going to go away while
>    we'd be peeking at it.

How about _get_buffer() and _pop_buffer() ? Although I'm fine with the current one, we have APIs named like that in GLib.

>  - it would be nice if we could incorporate queuing
>    functionality on the input side. (Can be added later)

There is that already, if the source is live and the latency property is set to > 0.

>  - gst_aggregator_request_new_pad() should not insist
>     on sink pad template name of "sink_%u" (could be
>     audio_%u or somesuch too, etc.)

Done

>  - I think we should rather add the pad GType to
>    GstPadTemplate, which would also be useful for
>    gst-inspect.

I agree with Jan that this is problematic

>  - I wonder if the "latency" property should not rather
>    be called "extra-latency" ? Or perhaps I misunderstand
>    it. The our_latency > data.max comparison in
>    gst_aggregator_query_latency() doesn't look right if
>    it's extra latency though.

This is really the input queue max lenght, the name could maybe be improved?


(In reply to Jan Schmidt from comment #40)
> One thing that GstCollectPads allowed which GstAggregator doesn't do nicely
> is elements that want to receive data on fixed static pads.
> 
> It would be nice to decouple the request pad template and naming from the
> actual function of GstAggregator. Perhaps a default request_pads
> implementation that
> sub-classes can install on themselves, or use as a function call when
> creating their own request pads, and a separate function for 'enrolling'
> pads the sub-class created itself.

I think we can easily add that later. Just add a gst_aggregate_add_static_pad() function of some kind ?
Comment 43 Tim-Philipp Müller 2017-05-22 11:22:39 UTC
> >  - I think we should rather add the pad GType to
> >    GstPadTemplate, which would also be useful for
> >    gst-inspect.
> 
> I agree with Jan that this is problematic

How is this problematic? It's fine to store the type name string in the registry, but not necessarily required. gst-inspect-1.0 will load the plugin anyway, because properties are not stored in the registry, so at that point the GType will always be available.
Comment 44 Mathieu Duponchelle 2017-10-16 16:22:21 UTC
I just gave a quick look at gstaggregator.h, and one point that I think needs discussing is whether we want subclasses to iterate sink pads through GstElement.sinkpads, or through some other mechanism. There is already a poorly-named foreach function for this purpose, gst_aggregator_iterate_sinkpads , with an associated FIXME:

/* API that should eventually land in GstElement itself (FIXME) */

Requiring subclasses to only aggregate pads explicitly listed as "aggregatable" could give us in the future the ability to exclude pads from aggregation for one reason or another, and could also simplify implementation, as the subclass would for example not need, as currently, to check whether a pad did have a buffer.

If we require that, we need to rename gst_aggregator_iterate_sinkpads to gst_aggregator_foreach_sinkpad, and provide an actual iterate function for the pads to aggregate.

If not, we will probably want to implement and expose a proper gst_element_foreach_pad method.
Comment 45 Mathieu Duponchelle 2017-10-16 16:24:19 UTC
> and provide an actual iterate function for the pads to aggregate.

or pass these in the call to ->aggregate
Comment 46 Thibault Saunier 2017-10-16 22:51:11 UTC
@Mathieu: https://bugzilla.gnome.org/show_bug.cgi?id=742152 :)
Comment 47 Thibault Saunier 2017-11-26 15:21:47 UTC
To me https://bugzilla.gnome.org/show_bug.cgi?id=760981 is not realy a blocker for that one, what would be missing now? (I checked quickly and I think we have done pretty much everything that was preventing on to move on with this one :))
Comment 48 rland 2017-12-04 07:49:53 UTC
BTW,
gstreamer-bad-base-1.0.pc should also be removed from gstreamer-1.0-osx-framework.recipe and gst-plugins-bad-1.0.recipe, otherwise upstream's cerbero code will fail to execute package command.:)
Comment 49 Tim-Philipp Müller 2017-12-04 09:23:19 UTC
Ah yes, I forgot the cerbero bit, thank you.
Comment 50 Tim-Philipp Müller 2017-12-04 11:58:53 UTC
1) Follow up bugs:

Bug #791201 - better support for static input pads
Bug #791202 - need gst_aggregator_pad_set_waiting() for sparse streams


2) I'm still very much inclined towards renaming

 gst_aggregator_pad_steal_buffer() -> gst_aggregator_pad_pop_buffer()
 gst_aggregator_pad_get_buffer() -> gst_aggregator_pad_peek_buffer()

It is true that get/steal is used elsewhere, but in a slightly different context. I think pop/peek describe what is done functionality-wise much better and avoid confusion about the return value ownership, e.g. with GValue _get() will not return a ref whereas _steal() will but here both do return a ref.


3) Tag handling is bogus. I think I will just remove it, don't think any of the current subclasses is using that at the moment, then we can figure out what to do once someone needs it and can't handle it via the usual vfuncs.


Otherwise this is done, so let's close it.
Comment 51 Tim-Philipp Müller 2017-12-04 12:19:50 UTC
Bug #791204 - rename pad_{get,steal}_buffer() to pad_{peek,pop}_buffer()
Comment 52 Stefan Sauer (gstreamer, gtkdoc dev) 2017-12-26 20:16:37 UTC
As discussed during the hackfest:
@@ -1858,12 +1872,13 @@ gst_aggregator_query_latency_unlocked (GstAggregator * self, GstQuery * query)
 
   gst_query_parse_latency (query, &live, &min, &max);
 
+  // FIXME: this is already done by gst_query_set_latency()
   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (min))) {
     GST_ERROR_OBJECT (self, "Invalid minimum latency %" GST_TIME_FORMAT
         ". Please file a bug at " PACKAGE_BUGREPORT ".", GST_TIME_ARGS (min));
     return FALSE;
   }
-
+  // FIXME: should this be done by gst_query_set_latency() too?
   if (min > max && GST_CLOCK_TIME_IS_VALID (max)) {
     GST_ELEMENT_WARNING (self, CORE, CLOCK, (NULL),
         ("Impossible to configure latency: max %" GST_TIME_FORMAT " < min %"
@@ -2001,6 +2016,7 @@ gst_aggregator_default_src_query (GstAggregator * self, GstQuery * query)
 
       /* don't pass it along as some (file)sink might claim it does
        * whereas with a collectpads in between that will not likely work */
+      // FIXME: wat?    ^^^^^^^^^^^
       gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
       gst_query_set_seeking (query, format, FALSE, 0, -1);
       res = TRUE;

This is the last undesired mentioning of collectpads. Ideally reword the comment to explain whats the matter here.
Comment 53 Olivier Crête 2017-12-27 16:38:44 UTC
(In reply to Stefan Sauer (gstreamer, gtkdoc dev) from comment #52)
> -
> +  // FIXME: should this be done by gst_query_set_latency() too?
>    if (min > max && GST_CLOCK_TIME_IS_VALID (max)) {
>      GST_ELEMENT_WARNING (self, CORE, CLOCK, (NULL),
>          ("Impossible to configure latency: max %" GST_TIME_FORMAT " < min %"
> @@ -2001,6 +2016,7 @@ gst_aggregator_default_src_query (GstAggregator *
> self, GstQuery * query)

I'm still unsure if min<=max in the latency query is always invalid in the general case (ie, general enough to put the check in gst_query_set_latency()).