docs/design/part-negotiation.txt: Update with, um, one way that pull-mode negotiation...
authorAndy Wingo <wingo@pobox.com>
Wed, 10 Jan 2007 21:15:08 +0000 (21:15 +0000)
committerAndy Wingo <wingo@pobox.com>
Wed, 10 Jan 2007 21:15:08 +0000 (21:15 +0000)
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.

ChangeLog
docs/design/part-negotiation.txt
gst/gstpad.c
gst/gstpad.h

index a5e4aaf..425a465 100644 (file)
--- a/ChangeLog
+++ b/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:
index 048e585..743892b 100644 (file)
@@ -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.
index 076321b..95c5caf 100644 (file)
@@ -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.
+ *
+ * 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.  Free the caps when
- * you no longer need it. This function returns NULL when the @srcpad has no
- * peer.
+ * 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;
   }
index 87c866d..f9091a1 100644 (file)
@@ -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 */