From b68c7fc9549ed3e40d2526289327ddea06e34fae Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 27 Sep 2012 17:21:53 +0200 Subject: [PATCH] pwg: fix some negotiation to 1.0 --- docs/pwg/advanced-negotiation.xml | 171 ++++++++++++++++++++++---------------- 1 file changed, 99 insertions(+), 72 deletions(-) diff --git a/docs/pwg/advanced-negotiation.xml b/docs/pwg/advanced-negotiation.xml index 1bae8b2..f26e9be 100644 --- a/docs/pwg/advanced-negotiation.xml +++ b/docs/pwg/advanced-negotiation.xml @@ -57,22 +57,18 @@ In order for caps negotiation on non-fixed links to work correctly, - pads can optionally implement a function that tells peer elements what - formats it supports and/or prefers. When upstream renegotiation is + pads can optionally implement a query function that tells peer elements + what formats it supports and/or prefers. When upstream renegotiation is triggered, this becomes important. - Downstream elements are notified of a newly set caps only when data - is actually passing their pad. This is because caps is attached to - buffers during data flow. So when the vorbis decoder sets a caps on + Downstream elements are notified of a newly set caps with a + GST_EVENT_CAPS on the sinkpad. So when the vorbis decoder sets a caps on its source pad (to configure the output format), the converter will - not yet be notified. Instead, the converter will only be notified - when the decoder pushes a buffer over its source pad to the converter. - Right before calling the chain-function in the converter, &GStreamer; - will check whether the format that was previously negotiated still - applies to this buffer. If not, it first calls the setcaps-function - of the converter to configure it for the new format. Only after that - will it call the chain function of the converter. + receive a caps event. + When an element receives a buffer, it should check if it has received + all needed format information in a CAPS event previously. If it hasn't, + it should return an error from the chain function. @@ -87,7 +83,7 @@ [..] - pad = gst_pad_new_from_template (..); + pad = gst_pad_new_from_static_template (..); gst_pad_use_fixed_caps (pad); [..] @@ -99,7 +95,6 @@ [..] caps = gst_caps_new_simple ("audio/x-raw", "format", G_TYPE_STRING, GST_AUDIO_NE(F32), - "buffer-frames", G_TYPE_INT, <bytes-per-frame>, "rate", G_TYPE_INT, <samplerate>, "channels", G_TYPE_INT, <num-channels>, NULL); if (!gst_pad_set_caps (pad, caps)) { @@ -158,18 +153,17 @@ Many elements, particularly effects and converters, will be able to parse the format of the stream from their input caps, and decide - the output format right at that time already. When renegotiation - takes place, some may merely need to "forward" the renegotiation - backwards upstream (more on that later). For those elements, all - (downstream) caps negotiation can be done in something that we - call the _setcaps () function. This function is - called when a buffer is pushed over a pad, but the format on this - buffer is not the same as the format that was previously negotiated - (or, similarly, no format was negotiated yet so far). + the output format right at that time already. For those elements, all + (downstream) caps negotiation can be done from the + _event () function when a GST_EVENT_CAPS is + received on the sinkpad. This CAPS event is received whenever the + format changes or when no format was negotiated yet. It will always + be called before you receive the buffer in the format specified in + the CAPS event. - In the _setcaps ()-function, the element can - forward the caps to the next element and, if that pad accepts the + In the _event ()-function, the element can + forward the CAPS event to the next element and, if that pad accepts the format too, the element can parse the relevant parameters from the caps and configure itself internally. The caps passed to this function is always a subset of the template caps, so @@ -187,22 +181,37 @@ gst_my_filter_getcaps (GstPad * pad) --> static gboolean -gst_my_filter_setcaps (GstPad *pad, - GstCaps *caps) +gst_my_filter_sink_event (GstPad *pad, + GstObject *parent, + GstEvent *event) { - GstMyFilter *filter = GST_MY_FILTER (GST_OBJECT_PARENT (pad)); - GstStructure *s; + gboolean ret; + GstMyFilter *filter = GST_MY_FILTER (parent); - /* forward-negotiate */ - if (!gst_pad_set_caps (filter->srcpad, caps)) - return FALSE; + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_CAPS: + { + GstCaps *caps; + GstStructure *s; - /* negotiation succeeded, so now configure ourselves */ - s = gst_caps_get_structure (caps, 0); - gst_structure_get_int (s, "rate", &filter->samplerate); - gst_structure_get_int (s, "channels", &filter->channels); + gst_event_parse_caps (event, &caps); - return TRUE; + /* forward-negotiate */ + ret = gst_pad_set_caps (filter->srcpad, caps); + if (!ret) + return FALSE; + + /* negotiation succeeded, so now configure ourselves */ + s = gst_caps_get_structure (caps, 0); + gst_structure_get_int (s, "rate", &filter->samplerate); + gst_structure_get_int (s, "channels", &filter->channels); + break; + } + default: + ret = gst_pad_event_default (pad, parent, event); + break; + } + return ret; } static gboolean -gst_my_filter_setcaps (GstPad *pad, +gst_my_filter_setcaps (GstMyFilter *filter, GstCaps *caps) { - GstMyFilter *filter = GST_MY_FILTER (GST_OBJECT_PARENT (pad)); - if (gst_pad_set_caps (filter->sinkpad, caps)) { filter->passthrough = TRUE; } else { @@ -282,11 +289,36 @@ gst_my_filter_setcaps (GstPad *pad, return TRUE; } +static gboolean +gst_my_filter_sink_event (GstPad *pad, + GstObject *parent, + GstEvent *event) +{ + gboolean ret; + GstMyFilter *filter = GST_MY_FILTER (parent); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_CAPS: + { + GstCaps *caps; + + gst_event_parse_caps (event, &caps); + ret = gst_my_filter_setcaps (filter, caps); + break; + } + default: + ret = gst_pad_event_default (pad, parent, event); + break; + } + return ret; +} + static GstFlowReturn gst_my_filter_chain (GstPad *pad, + GstObject *parent, GstBuffer *buf) { - GstMyFilter *filter = GST_MY_FILTER (GST_OBJECT_PARENT (pad)); + GstMyFilter *filter = GST_MY_FILTER (parent); GstBuffer *out; /* push on if in passthrough mode */ @@ -322,7 +354,7 @@ gst_my_filter_chain (GstPad *pad, Fortunately, the code required to do so is very similar to the last code example in , with the difference being that the caps is selected in the _chain - ()-function rather than in the _setcaps + ()-function rather than in the _event ()-function. The rest, as for getting all allowed caps from the source pad, fixating and such, is all the same. Re-negotiation, which will be handled in the next section, is very different for such @@ -341,13 +373,14 @@ gst_my_filter_chain (GstPad *pad, or because the audio channel configuration changed. - Upstream caps renegotiation is done in the gst_pad_alloc_buffer - ()-function. The idea here is that an element requesting a - buffer from downstream, has to specify the type of that buffer. If - renegotiation is to take place, this type will no longer apply, and the - downstream element will set a new caps on the provided buffer. The element - should then reconfigure itself to push buffers with the returned caps. The - source pad's setcaps will be called once the buffer is pushed. + Upstream caps renegotiation is requested by sending a GST_EVENT_RECONFIGURE + event upstream. The idea is that it will instruct the upstream element + to reconfigure its caps by doing a new query for the allowed caps and then + choosing a new caps. The element that sends out the RECONFIGURE event + would influence the selection of the new caps by returning the new + prefered caps from its GST_QUERY_CAPS query function. The RECONFIGURE + event will set the GST_PAD_FLAG_NEED_RECONFIGURE on all pads that it + travels over. It is important to note here that different elements actually have @@ -356,39 +389,33 @@ gst_my_filter_chain (GstPad *pad, - Elements should implement a padalloc-function in - order to be able to change format on renegotiation. This is also - true for filters and converters. - - - - - Elements should allocate new buffers using - gst_pad_alloc_buffer (). + Elements that can be reconfigured on the srcpad should check its + NEED_RECONFIGURE flag with + gst_pad_check_reconfigure () and it should + start renegotiation when the function returns TRUE. - Elements that are renegotiable should implement a - setcaps-function on their sourcepad as well. + Elements that want to propose a new format upstream need to send + a RECONFIGURE event and be prepared to answer the CAPS query with + the new prefered format. It should be noted that when there is no + upstream element that can (or wants) to renegotiate, the element + needs to deal with the currently configured format. - - Unfortunately, not all details here have been worked out yet, so this - documentation is incomplete. FIXME. - - - Implementing a getcaps function + + Implementing a CAPS query function - A _getcaps ()-function is called when a peer - element would like to know which formats this element supports, and - in what order of preference. The return value should be all formats - that this elements supports, taking into account limitations of peer - elements further downstream or upstream, sorted by order of preference, - highest preference first. + A _query ()-function with the GST_QUERY_CAPS query + type is called when a peer element would like to know which formats + this pad supports, and in what order of preference. The return value + should be all formats that this elements supports, taking into account + limitations of peer elements further downstream or upstream, sorted by + order of preference, highest preference first. -- 2.7.4