mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-03 15:06:34 +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>
|
||||
|
||||
* plugins/elements/gstfilesink.c:
|
||||
|
|
|
@ -1,10 +1,24 @@
|
|||
Negotiation
|
||||
-----------
|
||||
|
||||
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.
|
||||
Capabilities negotiation is the process of deciding on an adequate
|
||||
format for dataflow within a GStreamer pipeline. Ideally, negotiation
|
||||
(also known as "capsnego") transfers information from those parts of the
|
||||
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
|
||||
another data format from an upstream element. This is called upstream
|
||||
|
@ -152,4 +166,75 @@ videotestsrc ! queue ! xvimagesink
|
|||
- 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:
|
||||
* @srcpad: a #GstPad, it must a a source pad.
|
||||
* @pad: a #GstPad.
|
||||
*
|
||||
* Gets the capabilities of the allowed media types that can flow through
|
||||
* @srcpad and its peer. The pad must be a source pad.
|
||||
* The caller must free the resulting caps.
|
||||
* @pad and its peer.
|
||||
*
|
||||
* Returns: the allowed #GstCaps of the pad link. Free the caps when
|
||||
* you no longer need it. This function returns NULL when the @srcpad has no
|
||||
* peer.
|
||||
* The allowed capabilities is calculated as the intersection of the results of
|
||||
* calling gst_pad_get_caps() on @pad and its peer. The caller owns a reference
|
||||
* 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.
|
||||
*/
|
||||
GstCaps *
|
||||
gst_pad_get_allowed_caps (GstPad * srcpad)
|
||||
gst_pad_get_allowed_caps (GstPad * pad)
|
||||
{
|
||||
GstCaps *mycaps;
|
||||
GstCaps *caps;
|
||||
GstCaps *peercaps;
|
||||
GstPad *peer;
|
||||
|
||||
g_return_val_if_fail (GST_IS_PAD (srcpad), NULL);
|
||||
g_return_val_if_fail (GST_PAD_IS_SRC (srcpad), NULL);
|
||||
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
|
||||
|
||||
GST_OBJECT_LOCK (srcpad);
|
||||
GST_OBJECT_LOCK (pad);
|
||||
|
||||
peer = GST_PAD_PEER (srcpad);
|
||||
peer = GST_PAD_PEER (pad);
|
||||
if (G_UNLIKELY (peer == NULL))
|
||||
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_UNLOCK (srcpad);
|
||||
mycaps = gst_pad_get_caps (srcpad);
|
||||
GST_OBJECT_UNLOCK (pad);
|
||||
mycaps = gst_pad_get_caps (pad);
|
||||
|
||||
peercaps = gst_pad_get_caps (peer);
|
||||
gst_object_unref (peer);
|
||||
|
@ -2517,15 +2518,15 @@ gst_pad_get_allowed_caps (GstPad * srcpad)
|
|||
gst_caps_unref (peercaps);
|
||||
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);
|
||||
|
||||
return caps;
|
||||
|
||||
no_peer:
|
||||
{
|
||||
GST_CAT_DEBUG_OBJECT (GST_CAT_PROPERTIES, srcpad, "no peer");
|
||||
GST_OBJECT_UNLOCK (srcpad);
|
||||
GST_CAT_DEBUG_OBJECT (GST_CAT_PROPERTIES, pad, "no peer");
|
||||
GST_OBJECT_UNLOCK (pad);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -825,7 +825,7 @@ GstCaps * gst_pad_peer_get_caps (GstPad * pad);
|
|||
gboolean gst_pad_peer_accept_caps (GstPad * pad, GstCaps *caps);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* data passing functions to peer */
|
||||
|
|
Loading…
Reference in a new issue