pad: add pull mode probes
authorWim Taymans <wim.taymans@collabora.co.uk>
Tue, 8 Nov 2011 11:47:33 +0000 (12:47 +0100)
committerWim Taymans <wim.taymans@collabora.co.uk>
Tue, 8 Nov 2011 11:47:33 +0000 (12:47 +0100)
Allow probes to inspect the offset and size from a probe in pull mode and allow
the probe to modify the buffer.
Update design doc a little.

docs/design/part-probes.txt
gst/gstpad.c
gst/gstpad.h

index 7e01176..296f5bc 100644 (file)
@@ -45,20 +45,22 @@ Overview
   
     typedef enum
     {
-      GST_PAD_PROBE_TYPE_INVALID      = 0,
+      GST_PAD_PROBE_TYPE_INVALID          = 0,
 
       /* flags to control blocking */
-      GST_PAD_PROBE_TYPE_IDLE         = (1 << 0),
-      GST_PAD_PROBE_TYPE_BLOCK        = (1 << 1),
+      GST_PAD_PROBE_TYPE_IDLE             = (1 << 0),
+      GST_PAD_PROBE_TYPE_BLOCK            = (1 << 1),
 
       /* flags to select datatypes */
-      GST_PAD_PROBE_TYPE_BUFFER       = (1 << 2),
-      GST_PAD_PROBE_TYPE_BUFFER_LIST  = (1 << 3),
-      GST_PAD_PROBE_TYPE_EVENT        = (1 << 4),
+      GST_PAD_PROBE_TYPE_BUFFER           = (1 << 2),
+      GST_PAD_PROBE_TYPE_BUFFER_LIST      = (1 << 3),
+      GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM = (1 << 4),
+      GST_PAD_PROBE_TYPE_EVENT_UPSTREAM   = (1 << 5),
 
       /* flags to select scheduling mode */
-      GST_PAD_PROBE_TYPE_PUSH         = (1 << 5),
-      GST_PAD_PROBE_TYPE_PULL         = (1 << 6),
+      GST_PAD_PROBE_TYPE_PUSH             = (1 << 6),
+      GST_PAD_PROBE_TYPE_PULL             = (1 << 7),
+
     } GstPadProbeType;
 
  When adding a probe with the IDLE or BLOCK flag, the probe will become a
@@ -71,14 +73,13 @@ Overview
 
  The probe callback is defined as:
 
-   GstPadProbeReturn (*GstPadProbeCallback) (GstPad *pad, GstPadProbeType type,
-                                          gpointer type_data,
+   GstPadProbeReturn (*GstPadProbeCallback) (GstPad *pad, GstPadProbeInfo *info,
                                           gpointer user_data);
 
- The executing probe type is passed as an argument and is guaranteed to match
- the mask that was used to register the callback. type_data contains type
- specific data, which is usually the data item that is blocked or NULL when
- no data item is present.  
+ A probe info structure is passed as an argument and its type is guaranteed
+ to match the mask that was used to register the callback. The data item in the
+ info contains type specific data, which is usually the data item that is blocked
or NULL when no data item is present.  
  
  The probe can return any of the following return values:
 
@@ -111,8 +112,8 @@ Blocking probes
   thread.
 
   The IDLE probe in useful to perform dynamic linking, it allows to wait for for
-  a safe moment when an unlink/link operation can be done. Since the event is a
-  blocking event, it will also make sure that the pad stays idle until the probe
+  a safe moment when an unlink/link operation can be done. Since the probe is a
+  blocking probe, it will also make sure that the pad stays idle until the probe
   is removed.
 
   When the BLOCK flag is set, the probe callback will be called when new data
@@ -135,7 +136,7 @@ Non-Blocking probes
 Push dataflow
 -------------
 
-All probes have the GST_PAD_PROBE_TYPE_PUSH flag set in the callbacks.
+Push probes have the GST_PAD_PROBE_TYPE_PUSH flag set in the callbacks.
 
 In push based scheduling, the blocking probe is called first with the data item.
 Then the data probes are called before the peer pad chain or event function is
@@ -144,13 +145,13 @@ called.
 The data probes are called before the peer pad is checked. This allows for
 linking the pad in either the BLOCK or DATA probes on the pad.
 
-Before the peerpad chain or event function is called, the peer pad data probes
-are called.
+Before the peerpad chain or event function is called, the peer pad block and
+data probes are called.
 
 Finally, the IDLE probe is called on the pad after the data was sent to the
 peer pad.
 
-The push dataflow probe behavior is the same for buffers and biderectional events.
+The push dataflow probe behavior is the same for buffers and bidirectional events.
 
 
                      pad                           peerpad
@@ -191,19 +192,20 @@ The push dataflow probe behavior is the same for buffers and biderectional event
 Pull dataflow
 -------------
 
-All probes have the GST_PAD_PROBE_TYPE_PULL flag set in the callbacks.
+Pull probes have the GST_PAD_PROBE_TYPE_PULL flag set in the callbacks.
 
 The gst_pad_pull_range() call will first trigger the BLOCK probes without a DATA
-item. This allows the pad to be linked before the peer pad is resolved.
+item. This allows the pad to be linked before the peer pad is resolved. It also
+allows the callback to set a data item in the probe info.
 
-After the getrange function is called on the peer pad and there is a data item,
-the DATA probes are called.
+After the blocking probe and the getrange function is called on the peer pad
+and there is a data item, the DATA probes are called.
 
 When control returns to the sinkpad, the IDLE callbacks are called. The IDLE
 callback is called without a data item so that it will also be called when there
 was an error.
 
-It there is a valid DATA item, the DATA probes are called for the item.
+If there is a valid DATA item, the DATA probes are called for the item.
 
 
                  srcpad                          sinkpad
index 70eccb9..c421345 100644 (file)
@@ -3400,20 +3400,40 @@ no_match:
   }
 }
 
-#define PROBE_ND_FULL(pad,mask,label,defaultval)                \
+#define PROBE_PRE_PULL(pad,mask,data,offs,size,label,probed,defaultval)    \
   G_STMT_START {                                               \
     if (G_UNLIKELY (pad->num_probes)) {                                \
-      GstPadProbeInfo info = { mask, NULL };                   \
+      /* we start with passing NULL as the data item */         \
+      GstPadProbeInfo info = { mask, NULL, offs, size };        \
+      ret = do_probe_callbacks (pad, &info, defaultval);       \
+      /* store the possibly updated data item */                \
+      data = GST_PAD_PROBE_INFO_DATA (&info);                   \
+      /* if something went wrong, exit */                       \
+      if (G_UNLIKELY (ret != defaultval && ret != GST_FLOW_OK))        \
+        goto label;                                            \
+      /* otherwise check if the probe retured data */           \
+      if (G_UNLIKELY (data != NULL))                            \
+        goto probed;                                           \
+    }                                                          \
+  } G_STMT_END
+
+
+/* a probe that does not take or return any data */
+#define PROBE_NO_DATA(pad,mask,label,defaultval)                \
+  G_STMT_START {                                               \
+    if (G_UNLIKELY (pad->num_probes)) {                                \
+      /* pass NULL as the data item */                          \
+      GstPadProbeInfo info = { mask, NULL, 0, 0 };              \
       ret = do_probe_callbacks (pad, &info, defaultval);       \
       if (G_UNLIKELY (ret != defaultval && ret != GST_FLOW_OK))        \
         goto label;                                            \
     }                                                          \
   } G_STMT_END
 
-#define PROBE_FULL(pad,mask,data,label,defaultval)              \
+#define PROBE_FULL(pad,mask,data,offs,size,label,defaultval)    \
   G_STMT_START {                                               \
     if (G_UNLIKELY (pad->num_probes)) {                                \
-      GstPadProbeInfo info = { mask, data };                    \
+      GstPadProbeInfo info = { mask, data, offs, size };        \
       ret = do_probe_callbacks (pad, &info, defaultval);       \
       data = GST_PAD_PROBE_INFO_DATA (&info);                   \
       if (G_UNLIKELY (ret != defaultval && ret != GST_FLOW_OK))        \
@@ -3421,10 +3441,10 @@ no_match:
     }                                                          \
   } G_STMT_END
 
-#define PROBE(pad,mask,data,label)             \
-  PROBE_FULL(pad, mask, data, label, GST_FLOW_OK);
-#define PROBE_ND(pad,mask,label)               \
-  PROBE_ND_FULL(pad, mask, label, GST_FLOW_OK);
+#define PROBE_PUSH(pad,mask,data,label)                                \
+  PROBE_FULL(pad, mask, data, -1, -1, label, GST_FLOW_OK);
+#define PROBE_PULL(pad,mask,data,offs,size,label)              \
+  PROBE_FULL(pad, mask, data, offs, size, label, GST_FLOW_OK);
 
 static GstFlowReturn
 do_probe_callbacks (GstPad * pad, GstPadProbeInfo * info,
@@ -3637,9 +3657,9 @@ gst_pad_chain_data_unchecked (GstPad * pad, GstPadProbeType type, void *data)
       goto events_error;
   }
 
-  PROBE (pad, type | GST_PAD_PROBE_TYPE_BLOCK, data, probe_stopped);
+  PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_BLOCK, data, probe_stopped);
 
-  PROBE (pad, type, data, probe_stopped);
+  PROBE_PUSH (pad, type, data, probe_stopped);
 
   GST_OBJECT_UNLOCK (pad);
 
@@ -3844,10 +3864,10 @@ gst_pad_push_data (GstPad * pad, GstPadProbeType type, void *data)
     goto flushing;
 
   /* do block probes */
-  PROBE (pad, type | GST_PAD_PROBE_TYPE_BLOCK, data, probe_stopped);
+  PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_BLOCK, data, probe_stopped);
 
   /* do post-blocking probes */
-  PROBE (pad, type, data, probe_stopped);
+  PROBE_PUSH (pad, type, data, probe_stopped);
 
   if (G_UNLIKELY ((peer = GST_PAD_PEER (pad)) == NULL))
     goto not_linked;
@@ -3865,7 +3885,7 @@ gst_pad_push_data (GstPad * pad, GstPadProbeType type, void *data)
   pad->priv->using--;
   if (pad->priv->using == 0) {
     /* pad is not active anymore, trigger idle callbacks */
-    PROBE_ND_FULL (pad, GST_PAD_PROBE_TYPE_PUSH | GST_PAD_PROBE_TYPE_IDLE,
+    PROBE_NO_DATA (pad, GST_PAD_PROBE_TYPE_PUSH | GST_PAD_PROBE_TYPE_IDLE,
         probe_stopped, ret);
   }
   GST_OBJECT_UNLOCK (pad);
@@ -3991,8 +4011,10 @@ gst_pad_get_range_unchecked (GstPad * pad, guint64 offset, guint size,
   if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
     goto flushing;
 
-  PROBE_ND (pad, GST_PAD_PROBE_TYPE_PULL | GST_PAD_PROBE_TYPE_BLOCK,
-      probe_stopped);
+  /* when one of the probes returns a buffer, probed_data will be called and we
+   * skip calling the getrange function */
+  PROBE_PRE_PULL (pad, GST_PAD_PROBE_TYPE_PULL | GST_PAD_PROBE_TYPE_BLOCK,
+      *buffer, offset, size, probe_stopped, probed_data, GST_FLOW_OK);
   GST_OBJECT_UNLOCK (pad);
 
   if (G_UNLIKELY ((getrangefunc = GST_PAD_GETRANGEFUNC (pad)) == NULL))
@@ -4010,8 +4032,9 @@ gst_pad_get_range_unchecked (GstPad * pad, guint64 offset, guint size,
 
   /* can only fire the signal if we have a valid buffer */
   GST_OBJECT_LOCK (pad);
-  PROBE (pad, GST_PAD_PROBE_TYPE_PULL | GST_PAD_PROBE_TYPE_BUFFER, *buffer,
-      probe_stopped_unref);
+probed_data:
+  PROBE_PULL (pad, GST_PAD_PROBE_TYPE_PULL | GST_PAD_PROBE_TYPE_BUFFER,
+      *buffer, offset, size, probe_stopped_unref);
   GST_OBJECT_UNLOCK (pad);
 
   GST_PAD_STREAM_UNLOCK (pad);
@@ -4139,8 +4162,10 @@ gst_pad_pull_range (GstPad * pad, guint64 offset, guint size,
   if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
     goto flushing;
 
-  PROBE_ND (pad, GST_PAD_PROBE_TYPE_PULL | GST_PAD_PROBE_TYPE_BLOCK,
-      pre_probe_stopped);
+  /* when one of the probes returns a buffer, probed_data will be called and we
+   * skip calling the peer getrange function */
+  PROBE_PRE_PULL (pad, GST_PAD_PROBE_TYPE_PULL | GST_PAD_PROBE_TYPE_BLOCK,
+      *buffer, offset, size, pre_probe_stopped, probed_data, GST_FLOW_OK);
 
   if (G_UNLIKELY ((peer = GST_PAD_PEER (pad)) == NULL))
     goto not_linked;
@@ -4157,15 +4182,16 @@ gst_pad_pull_range (GstPad * pad, guint64 offset, guint size,
   pad->priv->using--;
   if (pad->priv->using == 0) {
     /* pad is not active anymore, trigger idle callbacks */
-    PROBE_ND (pad, GST_PAD_PROBE_TYPE_PULL | GST_PAD_PROBE_TYPE_IDLE,
-        post_probe_stopped);
+    PROBE_NO_DATA (pad, GST_PAD_PROBE_TYPE_PULL | GST_PAD_PROBE_TYPE_IDLE,
+        post_probe_stopped, ret);
   }
 
   if (G_UNLIKELY (ret != GST_FLOW_OK))
     goto pull_range_failed;
 
-  PROBE (pad, GST_PAD_PROBE_TYPE_PULL | GST_PAD_PROBE_TYPE_BUFFER, buffer,
-      post_probe_stopped);
+probed_data:
+  PROBE_PULL (pad, GST_PAD_PROBE_TYPE_PULL | GST_PAD_PROBE_TYPE_BUFFER,
+      *buffer, offset, size, post_probe_stopped);
 
   needs_events = GST_PAD_NEEDS_EVENTS (pad);
   if (G_UNLIKELY (needs_events)) {
@@ -4360,7 +4386,7 @@ gst_pad_push_event (GstPad * pad, GstEvent * event)
       if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
         goto flushed;
 
-      PROBE (pad, type | GST_PAD_PROBE_TYPE_PUSH |
+      PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_PUSH |
           GST_PAD_PROBE_TYPE_BLOCK, event, probe_stopped);
 
       break;
@@ -4368,7 +4394,7 @@ gst_pad_push_event (GstPad * pad, GstEvent * event)
   }
 
   /* send probes after modifying the events above */
-  PROBE (pad, type | GST_PAD_PROBE_TYPE_PUSH, event, probe_stopped);
+  PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_PUSH, event, probe_stopped);
 
   /* now check the peer pad */
   if (peerpad == NULL)
@@ -4395,8 +4421,8 @@ gst_pad_push_event (GstPad * pad, GstEvent * event)
   pad->priv->using--;
   if (pad->priv->using == 0) {
     /* pad is not active anymore, trigger idle callbacks */
-    PROBE_ND (pad, GST_PAD_PROBE_TYPE_PUSH | GST_PAD_PROBE_TYPE_IDLE,
-        probe_stopped);
+    PROBE_NO_DATA (pad, GST_PAD_PROBE_TYPE_PUSH | GST_PAD_PROBE_TYPE_IDLE,
+        probe_stopped, GST_FLOW_OK);
   }
   GST_OBJECT_UNLOCK (pad);
 
@@ -4574,11 +4600,11 @@ gst_pad_send_event (GstPad * pad, GstEvent * event)
       if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
         goto flushing;
 
-      PROBE (pad,
+      PROBE_PUSH (pad,
           type | GST_PAD_PROBE_TYPE_PUSH |
           GST_PAD_PROBE_TYPE_BLOCK, event, probe_stopped);
 
-      PROBE (pad, type | GST_PAD_PROBE_TYPE_PUSH, event, probe_stopped);
+      PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_PUSH, event, probe_stopped);
 
       break;
   }
index 6bfe070..344df07 100644 (file)
@@ -213,9 +213,9 @@ typedef enum {
 
 /**
  * GstPadActivateMode:
- * @GST_PAD_ACTIVATE_NONE:              Pad will not handle dataflow
- * @GST_PAD_ACTIVATE_PUSH:              Pad handles dataflow in downstream push mode
- * @GST_PAD_ACTIVATE_PULL:              Pad handles dataflow in upstream pull mode
+ * @GST_PAD_ACTIVATE_NONE: Pad will not handle dataflow
+ * @GST_PAD_ACTIVATE_PUSH: Pad handles dataflow in downstream push mode
+ * @GST_PAD_ACTIVATE_PULL: Pad handles dataflow in upstream pull mode
  *
  * The status of a GstPad. After activating a pad, which usually happens when the
  * parent element goes from READY to PAUSED, the GstPadActivateMode defines if the
@@ -531,7 +531,12 @@ typedef enum
 /**
  * GstPadProbeInfo:
  * @type: the current probe type
- * @data: type specific data
+ * @data: type specific data, check the @type field to know the datatype.
+ *    This field can be NULL.
+ * @offset: offset of pull probe, this field is valid when @type contains
+ *    #GST_PAD_PROBE_TYPE_PULL
+ * @size: size of pull probe, this field is valid when @type contains
+ *    #GST_PAD_PROBE_TYPE_PULL
  *
  * Info passed in the #GstPadProbeCallback.
  */
@@ -539,6 +544,8 @@ typedef struct
 {
   GstPadProbeType type;
   gpointer data;
+  guint64 offset;
+  guint size;
 } GstPadProbeInfo;
 
 #define GST_PAD_PROBE_INFO_TYPE(d)         ((d)->type)
@@ -548,6 +555,9 @@ typedef struct
 #define GST_PAD_PROBE_INFO_BUFFER_LIST(d)  GST_BUFFER_LIST_CAST(GST_PAD_PROBE_INFO_DATA(d))
 #define GST_PAD_PROBE_INFO_EVENT(d)        GST_EVENT_CAST(GST_PAD_PROBE_INFO_DATA(d))
 
+#define GST_PAD_PROBE_INFO_OFFSET(d)       ((d)->offset)
+#define GST_PAD_PROBE_INFO_SIZE(d)         ((d)->size)
+
 /**
  * GstPadProbeCallback
  * @pad: the #GstPad that is blocked
@@ -556,9 +566,11 @@ typedef struct
  *
  * Callback used by gst_pad_add_probe(). Gets called to notify about the current
  * blocking type.
+ *
+ * The callback is allowed to modify the data pointer in @info.
  */
-typedef GstPadProbeReturn      (*GstPadProbeCallback)              (GstPad *pad, GstPadProbeInfo *info,
-                                                                    gpointer user_data);
+typedef GstPadProbeReturn   (*GstPadProbeCallback)   (GstPad *pad, GstPadProbeInfo *info,
+                                                      gpointer user_data);
 
 /**
  * GstPadStickyEventsForeachFunction:
@@ -570,7 +582,8 @@ typedef GstPadProbeReturn      (*GstPadProbeCallback)              (GstPad *pad,
  *
  * Returns: GST_FLOW_OK if the iteration should continue
  */
-typedef GstFlowReturn           (*GstPadStickyEventsForeachFunction) (GstPad *pad, GstEvent *event, gpointer user_data);
+typedef GstFlowReturn       (*GstPadStickyEventsForeachFunction) (GstPad *pad, GstEvent *event,
+                                                                  gpointer user_data);
 
 /**
  * GstPadFlags: