mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 02:01:12 +00:00
docs/design/part-negotiation.txt: Update with, um, one way that pull-mode negotiation might work?
Original commit message from CVS: 2007-01-10 Andy Wingo <wingo@pobox.com> * docs/design/part-negotiation.txt: Update with, um, one way that pull-mode negotiation might work? * gst/gstpad.h: * gst/gstpad.c (gst_pad_get_allowed_caps): Remove the restriction that the pad must be a src pad; makes sense to call it the other way in pull mode, and the logic is symmetric anyway.
This commit is contained in:
parent
a18f048fb2
commit
7ef6acd8cd
4 changed files with 118 additions and 22 deletions
10
ChangeLog
10
ChangeLog
|
@ -1,3 +1,13 @@
|
||||||
|
2007-01-10 Andy Wingo <wingo@pobox.com>
|
||||||
|
|
||||||
|
* docs/design/part-negotiation.txt: Update with, um, one way that
|
||||||
|
pull-mode negotiation might work?
|
||||||
|
|
||||||
|
* gst/gstpad.h:
|
||||||
|
* gst/gstpad.c (gst_pad_get_allowed_caps): Remove the restriction
|
||||||
|
that the pad must be a src pad; makes sense to call it the other
|
||||||
|
way in pull mode, and the logic is symmetric anyway.
|
||||||
|
|
||||||
2007-01-10 Tim-Philipp Müller <tim at centricular dot net>
|
2007-01-10 Tim-Philipp Müller <tim at centricular dot net>
|
||||||
|
|
||||||
* plugins/elements/gstfilesink.c:
|
* plugins/elements/gstfilesink.c:
|
||||||
|
|
|
@ -1,10 +1,24 @@
|
||||||
Negotiation
|
Negotiation
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
Negotiation happens when elements want to push buffers and need to decide
|
Capabilities negotiation is the process of deciding on an adequate
|
||||||
on the format. This is called downstream negotiation because the upstream
|
format for dataflow within a GStreamer pipeline. Ideally, negotiation
|
||||||
element decides the format for the downstream element. This is the most
|
(also known as "capsnego") transfers information from those parts of the
|
||||||
common case.
|
pipeline that have information to those parts of the pipeline that are
|
||||||
|
flexible, constrained by those parts of the pipeline that are not
|
||||||
|
flexible.
|
||||||
|
|
||||||
|
GStreamer's two scheduling modes, push mode and pull mode, lend
|
||||||
|
themselves to different mechanisms to acheive this goal. As it is more
|
||||||
|
common we describe push mode negotiation first.
|
||||||
|
|
||||||
|
Push-mode negotiation
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
Pussh-mode negotiation happens when elements want to push buffers and
|
||||||
|
need to decide on the format. This is called downstream negotiation
|
||||||
|
because the upstream element decides the format for the downstream
|
||||||
|
element. This is the most common case.
|
||||||
|
|
||||||
Negotiation can also happen when a downstream element wants to receive
|
Negotiation can also happen when a downstream element wants to receive
|
||||||
another data format from an upstream element. This is called upstream
|
another data format from an upstream element. This is called upstream
|
||||||
|
@ -152,4 +166,75 @@ videotestsrc ! queue ! xvimagesink
|
||||||
- queue contains buffers with different types.
|
- queue contains buffers with different types.
|
||||||
|
|
||||||
|
|
||||||
|
Pull-mode negotiation
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
A pipeline in pull mode has different negotiation needs than one
|
||||||
|
activated in push mode. Push mode is optimized for two use cases:
|
||||||
|
|
||||||
|
* Playback of media files, in which the demuxers and the decoders are
|
||||||
|
the points from which format information should disseminate to the
|
||||||
|
rest of the pipeline; and
|
||||||
|
|
||||||
|
* Recording from live sources, in which users are accustomed to putting
|
||||||
|
a capsfilter directly after the source element; thus the caps
|
||||||
|
information flow proceeds from the user, through the potential caps
|
||||||
|
of the source, to the sinks of the pipeline.
|
||||||
|
|
||||||
|
In contrast, pull mode has other typical use cases:
|
||||||
|
|
||||||
|
* Playback from a lossy source, such as RTP, in which more knowledge
|
||||||
|
about the latency of the pipeline can increase quality; or
|
||||||
|
|
||||||
|
* Audio synthesis, in which audio APIs are tuned to producing only the
|
||||||
|
necessary number of samples, typically driven by a hardware interrupt
|
||||||
|
to fill a DMA buffer or a Jack[0] port buffer.
|
||||||
|
|
||||||
|
* Low-latency effects processing, whereby filters should be applied as
|
||||||
|
data is transferred from a ring buffer to a sink instead of
|
||||||
|
beforehand. For example, instead of using the internal alsasink
|
||||||
|
ringbuffer thread in push-mode wavsrc ! volume ! alsasink, placing
|
||||||
|
the volume inside the sound card writer thread via wavsrc !
|
||||||
|
audioringbuffer ! volume ! alsasink.
|
||||||
|
|
||||||
|
[0] http://jackit.sf.net
|
||||||
|
|
||||||
|
The problem with push mode is that the sink has to know the format in
|
||||||
|
order to know how many bytes to pull via gst_pad_pull_range(). This
|
||||||
|
means that before pulling, the sink must initiate negotation to decide
|
||||||
|
on a format.
|
||||||
|
|
||||||
|
Recalling the principles of capsnego, whereby information must flow from
|
||||||
|
those that have it to those that do not, we see that the two named use
|
||||||
|
cases have different negotiation requirements:
|
||||||
|
|
||||||
|
* RTP and low-latency playback are both like the normal playback case,
|
||||||
|
in which information flows downstream.
|
||||||
|
|
||||||
|
* In audio synthesis, the part of the pipeline that has the most
|
||||||
|
information is the sink, constrained by the capabilities of the graph
|
||||||
|
that feeds it. However the caps are not completely specified; at some
|
||||||
|
point the user has to intervene to choose the sample rate, at least.
|
||||||
|
This can be done externally to gstreamer, as in the jack elements, or
|
||||||
|
internally via a capsnego, as is customary with live sources.
|
||||||
|
|
||||||
|
Given that sinks potentially need the input of sources, as in the RTP
|
||||||
|
case and at least as a filter in the synthesis case, there must be a
|
||||||
|
negotiation phase before the pull thread is activated.
|
||||||
|
|
||||||
|
[ok at this point i'm a bit at a loss about how it should go]
|
||||||
|
|
||||||
|
This negotiation phase is initiated by the sink, after it succeeds in
|
||||||
|
calling gst_pad_activate_pull(), but before it spawns a thread to start
|
||||||
|
pulling. The sink will call gst_pad_get_allowed_caps() on the its sink
|
||||||
|
pad and fixate if necessary to determine the flow caps. It then calls
|
||||||
|
gst_pad_set_caps on its sink pad's peer, to configure the upstream
|
||||||
|
elements.
|
||||||
|
|
||||||
|
A typical element will implement a setcaps() function on its src pads
|
||||||
|
that proxies the setcaps() to all peers of its sink pads. This way, when
|
||||||
|
getrange() is called on a pad, it knows what format it is being asked to
|
||||||
|
produce.
|
||||||
|
|
||||||
|
If the sink element could not set caps on its peer(s), it should post an
|
||||||
|
error message on the bus indicating that negotiation was not possible.
|
||||||
|
|
35
gst/gstpad.c
35
gst/gstpad.c
|
@ -2475,40 +2475,41 @@ gst_pad_get_peer (GstPad * pad)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_pad_get_allowed_caps:
|
* gst_pad_get_allowed_caps:
|
||||||
* @srcpad: a #GstPad, it must a a source pad.
|
* @pad: a #GstPad.
|
||||||
*
|
*
|
||||||
* Gets the capabilities of the allowed media types that can flow through
|
* Gets the capabilities of the allowed media types that can flow through
|
||||||
* @srcpad and its peer. The pad must be a source pad.
|
* @pad and its peer.
|
||||||
* The caller must free the resulting caps.
|
|
||||||
*
|
*
|
||||||
* Returns: the allowed #GstCaps of the pad link. Free the caps when
|
* The allowed capabilities is calculated as the intersection of the results of
|
||||||
* you no longer need it. This function returns NULL when the @srcpad has no
|
* calling gst_pad_get_caps() on @pad and its peer. The caller owns a reference
|
||||||
* peer.
|
* on the resulting caps.
|
||||||
|
*
|
||||||
|
* Returns: the allowed #GstCaps of the pad link. Unref the caps when you no
|
||||||
|
* longer need it. This function returns NULL when @pad has no peer.
|
||||||
*
|
*
|
||||||
* MT safe.
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
GstCaps *
|
GstCaps *
|
||||||
gst_pad_get_allowed_caps (GstPad * srcpad)
|
gst_pad_get_allowed_caps (GstPad * pad)
|
||||||
{
|
{
|
||||||
GstCaps *mycaps;
|
GstCaps *mycaps;
|
||||||
GstCaps *caps;
|
GstCaps *caps;
|
||||||
GstCaps *peercaps;
|
GstCaps *peercaps;
|
||||||
GstPad *peer;
|
GstPad *peer;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_PAD (srcpad), NULL);
|
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
|
||||||
g_return_val_if_fail (GST_PAD_IS_SRC (srcpad), NULL);
|
|
||||||
|
|
||||||
GST_OBJECT_LOCK (srcpad);
|
GST_OBJECT_LOCK (pad);
|
||||||
|
|
||||||
peer = GST_PAD_PEER (srcpad);
|
peer = GST_PAD_PEER (pad);
|
||||||
if (G_UNLIKELY (peer == NULL))
|
if (G_UNLIKELY (peer == NULL))
|
||||||
goto no_peer;
|
goto no_peer;
|
||||||
|
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_PROPERTIES, srcpad, "getting allowed caps");
|
GST_CAT_DEBUG_OBJECT (GST_CAT_PROPERTIES, pad, "getting allowed caps");
|
||||||
|
|
||||||
gst_object_ref (peer);
|
gst_object_ref (peer);
|
||||||
GST_OBJECT_UNLOCK (srcpad);
|
GST_OBJECT_UNLOCK (pad);
|
||||||
mycaps = gst_pad_get_caps (srcpad);
|
mycaps = gst_pad_get_caps (pad);
|
||||||
|
|
||||||
peercaps = gst_pad_get_caps (peer);
|
peercaps = gst_pad_get_caps (peer);
|
||||||
gst_object_unref (peer);
|
gst_object_unref (peer);
|
||||||
|
@ -2517,15 +2518,15 @@ gst_pad_get_allowed_caps (GstPad * srcpad)
|
||||||
gst_caps_unref (peercaps);
|
gst_caps_unref (peercaps);
|
||||||
gst_caps_unref (mycaps);
|
gst_caps_unref (mycaps);
|
||||||
|
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, srcpad, "allowed caps %" GST_PTR_FORMAT,
|
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "allowed caps %" GST_PTR_FORMAT,
|
||||||
caps);
|
caps);
|
||||||
|
|
||||||
return caps;
|
return caps;
|
||||||
|
|
||||||
no_peer:
|
no_peer:
|
||||||
{
|
{
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_PROPERTIES, srcpad, "no peer");
|
GST_CAT_DEBUG_OBJECT (GST_CAT_PROPERTIES, pad, "no peer");
|
||||||
GST_OBJECT_UNLOCK (srcpad);
|
GST_OBJECT_UNLOCK (pad);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -825,7 +825,7 @@ GstCaps * gst_pad_peer_get_caps (GstPad * pad);
|
||||||
gboolean gst_pad_peer_accept_caps (GstPad * pad, GstCaps *caps);
|
gboolean gst_pad_peer_accept_caps (GstPad * pad, GstCaps *caps);
|
||||||
|
|
||||||
/* capsnego for connected pads */
|
/* capsnego for connected pads */
|
||||||
GstCaps * gst_pad_get_allowed_caps (GstPad * srcpad);
|
GstCaps * gst_pad_get_allowed_caps (GstPad * pad);
|
||||||
GstCaps * gst_pad_get_negotiated_caps (GstPad * pad);
|
GstCaps * gst_pad_get_negotiated_caps (GstPad * pad);
|
||||||
|
|
||||||
/* data passing functions to peer */
|
/* data passing functions to peer */
|
||||||
|
|
Loading…
Reference in a new issue