consitencychecker: add handling for sink-pads
authorStefan Sauer <ensonic@users.sf.net>
Wed, 29 Feb 2012 20:57:00 +0000 (21:57 +0100)
committerStefan Sauer <ensonic@users.sf.net>
Wed, 29 Feb 2012 21:00:16 +0000 (22:00 +0100)
Add a pad-probe for sink-pads. One can now add extra pads (belonging to the same
element) to a checker. This allows us to extend the checks.

libs/gst/check/gstconsistencychecker.c
libs/gst/check/gstconsistencychecker.h

index 94e665e..d916ef1 100644 (file)
@@ -3,6 +3,7 @@
  * unit testing helper lib
  *
  * Copyright (C) 2009 Edward Hervey <bilboed@bilboed.com>
+ * Copyright (C) 2012 Stefan Sauer <ensonic@users.sf.net>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
 
 struct _GstStreamConsistency
 {
-  gboolean flushing;
-  gboolean newsegment;
-  gboolean eos;
-  gulong probeid;
-  GstPad *pad;
+  /* FIXME: do we want to track some states per pad? */
+  volatile gboolean flushing;
+  volatile gboolean newsegment;
+  volatile gboolean eos;
+  volatile gboolean expect_flush;
+  GstObject *parent;
+  GList *pads;
 };
 
+typedef struct _GstStreamConsistencyProbe
+{
+  GstPad *pad;
+  gulong probeid;
+} GstStreamConsistencyProbe;
+
+
 static gboolean
 source_pad_data_cb (GstPad * pad, GstMiniObject * data,
     GstStreamConsistency * consist)
 {
+  GST_DEBUG_OBJECT (pad, "%p: %d %d %d %d", consist, consist->flushing,
+      consist->newsegment, consist->eos, consist->expect_flush);
+
   if (GST_IS_BUFFER (data)) {
     GST_DEBUG_OBJECT (pad, "Buffer %" GST_TIME_FORMAT,
         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (GST_BUFFER (data))));
@@ -68,9 +81,11 @@ source_pad_data_cb (GstPad * pad, GstMiniObject * data,
         fail_unless (consist->flushing,
             "Received a FLUSH_STOP without a FLUSH_START");
         fail_if (consist->eos, "Received a FLUSH_STOP after an EOS");
-        consist->flushing = FALSE;
+        consist->flushing = consist->expect_flush = FALSE;
         break;
       case GST_EVENT_NEWSEGMENT:
+        fail_if ((consist->expect_flush && consist->flushing),
+            "Received NEWSEGMENT while in a flushing seek");
         consist->newsegment = TRUE;
         consist->eos = FALSE;
         break;
@@ -96,6 +111,69 @@ source_pad_data_cb (GstPad * pad, GstMiniObject * data,
   return TRUE;
 }
 
+static gboolean
+sink_pad_data_cb (GstPad * pad, GstMiniObject * data,
+    GstStreamConsistency * consist)
+{
+  GST_DEBUG_OBJECT (pad, "%p: %d %d %d %d", consist, consist->flushing,
+      consist->newsegment, consist->eos, consist->expect_flush);
+
+  if (GST_IS_BUFFER (data)) {
+    GST_DEBUG_OBJECT (pad, "Buffer %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (GST_BUFFER (data))));
+    /* If an EOS went through, a buffer would be invalid */
+    fail_if (consist->eos, "Buffer received after EOS");
+    /* Buffers need to be preceded by a newsegment event */
+    fail_unless (consist->newsegment, "Buffer received without newsegment");
+  } else if (GST_IS_EVENT (data)) {
+    GstEvent *event = (GstEvent *) data;
+
+    GST_DEBUG_OBJECT (pad, "%s", GST_EVENT_TYPE_NAME (event));
+    switch (GST_EVENT_TYPE (event)) {
+      case GST_EVENT_SEEK:
+      {
+        GstSeekFlags flags;
+
+        gst_event_parse_seek (event, NULL, NULL, &flags, NULL, NULL, NULL,
+            NULL);
+        consist->expect_flush =
+            ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
+        break;
+      }
+      case GST_EVENT_NEWSEGMENT:
+        fail_if ((consist->expect_flush && consist->flushing),
+            "Received NEWSEGMENT while in a flushing seek");
+        consist->newsegment = TRUE;
+        consist->eos = FALSE;
+        break;
+      default:
+        /* FIXME : Figure out what to do for other events */
+        break;
+    }
+  }
+
+  return TRUE;
+}
+
+static void
+add_pad (GstStreamConsistency * consist, GstPad * pad)
+{
+  GstStreamConsistencyProbe *p;
+  GstPadDirection dir;
+
+  p = g_new0 (GstStreamConsistencyProbe, 1);
+  p->pad = g_object_ref (pad);
+  dir = gst_pad_get_direction (pad);
+  if (dir == GST_PAD_SRC) {
+    p->probeid =
+        gst_pad_add_data_probe (pad, (GCallback) source_pad_data_cb, consist);
+  } else if (dir == GST_PAD_SINK) {
+    p->probeid =
+        gst_pad_add_data_probe (pad, (GCallback) sink_pad_data_cb, consist);
+  }
+  consist->pads = g_list_prepend (consist->pads, p);
+}
+
 /**
  * gst_consistency_checker_new:
  * @pad: The #GstPad on which the dataflow will be checked.
@@ -103,13 +181,10 @@ source_pad_data_cb (GstPad * pad, GstMiniObject * data,
  * Sets up a data probe on the given pad which will raise assertions if the
  * data flow is inconsistent.
  *
- * Currently only works for source pads.
- *
  * Returns: A #GstStreamConsistency structure used to track data flow.
  *
  * Since: 0.10.24
  */
-
 GstStreamConsistency *
 gst_consistency_checker_new (GstPad * pad)
 {
@@ -118,14 +193,38 @@ gst_consistency_checker_new (GstPad * pad)
   g_return_val_if_fail (pad != NULL, NULL);
 
   consist = g_new0 (GstStreamConsistency, 1);
-  consist->pad = g_object_ref (pad);
-  consist->probeid =
-      gst_pad_add_data_probe (pad, (GCallback) source_pad_data_cb, consist);
 
+  if (!consist->pads) {
+    consist->parent = GST_OBJECT_PARENT (pad);
+  }
+  add_pad (consist, pad);
   return consist;
 }
 
 /**
+ * gst_consistency_checker_add_pad:
+ * @consist: The #GstStreamConsistency handle
+ * @pad: The #GstPad on which the dataflow will be checked.
+ *
+ * Sets up a data probe on the given pad which will raise assertions if the
+ * data flow is inconsistent.
+ *
+ * Returns: %TRUE if the pad was added
+ *
+ * Since: 0.10.37
+ */
+gboolean
+gst_consistency_checker_add_pad (GstStreamConsistency * consist, GstPad * pad)
+{
+  g_return_val_if_fail (consist != NULL, FALSE);
+  g_return_val_if_fail (pad != NULL, FALSE);
+  g_return_val_if_fail (GST_OBJECT_PARENT (pad) == consist->parent, FALSE);
+
+  add_pad (consist, pad);
+  return TRUE;
+}
+
+/**
  * gst_consistency_checker_reset:
  * @consist: The #GstStreamConsistency to reset.
  *
@@ -146,7 +245,7 @@ gst_consistency_checker_reset (GstStreamConsistency * consist)
  * gst_consistency_checker_free:
  * @consist: The #GstStreamConsistency to free.
  *
- * Frees the allocated data and probe associated with @consist.
+ * Frees the allocated data and probes associated with @consist.
  *
  * Since: 0.10.24
  */
@@ -154,8 +253,16 @@ gst_consistency_checker_reset (GstStreamConsistency * consist)
 void
 gst_consistency_checker_free (GstStreamConsistency * consist)
 {
-  /* Remove the data probe */
-  gst_pad_remove_data_probe (consist->pad, consist->probeid);
-  g_object_unref (consist->pad);
+  GList *node;
+  GstStreamConsistencyProbe *p;
+
+  /* Remove the data probes */
+  for (node = consist->pads; node; node = g_list_next (node)) {
+    p = (GstStreamConsistencyProbe *) node->data;
+    gst_pad_remove_data_probe (p->pad, p->probeid);
+    g_object_unref (p->pad);
+    g_free (p);
+  }
+  g_list_free (consist->pads);
   g_free (consist);
 }
index ec88af7..4cbf3f8 100644 (file)
@@ -37,11 +37,13 @@ G_BEGIN_DECLS
 typedef struct _GstStreamConsistency GstStreamConsistency;
 
 
-GstStreamConsistency * gst_consistency_checker_new   (GstPad * pad);
+GstStreamConsistency * gst_consistency_checker_new     (GstPad * pad);
+gboolean               gst_consistency_checker_add_pad (GstStreamConsistency * consist,
+                                                        GstPad * pad);
 
-void                   gst_consistency_checker_reset (GstStreamConsistency * consist);
+void                   gst_consistency_checker_reset   (GstStreamConsistency * consist);
 
-void                   gst_consistency_checker_free  (GstStreamConsistency * consist);
+void                   gst_consistency_checker_free    (GstStreamConsistency * consist);
 
 G_END_DECLS