Merging gst-devtools
[platform/upstream/gstreamer.git] / validate / gst / validate / gst-validate-pad-monitor.c
index 9f8c532..7cf92fc 100644 (file)
 #include "gst-validate-internal.h"
 #include "gst-validate-pad-monitor.h"
 #include "gst-validate-element-monitor.h"
+#include "gst-validate-pipeline-monitor.h"
 #include "gst-validate-reporter.h"
+#include "gst-validate-utils.h"
+#include "validate.h"
 #include <string.h>
 #include <stdarg.h>
 
@@ -38,6 +41,8 @@
  *
  * TODO
  */
+#define _GET_PAD_MONITOR(p) g_object_get_qdata ((GObject*) p, _Q_VALIDATE_MONITOR)
+#define _SET_PAD_MONITOR(p,d) g_object_set_qdata ((GObject*) p, _Q_VALIDATE_MONITOR, d)
 
 static GstValidateInterceptionReturn
 gst_validate_pad_monitor_intercept_report (GstValidateReporter * reporter,
@@ -77,6 +82,12 @@ G_DEFINE_TYPE_WITH_CODE (GstValidatePadMonitor, gst_validate_pad_monitor,
             GST_VALIDATE_MONITOR_GET_PARENT(m)) : \
         FALSE)
 
+#define PAD_PARENT_IS_SINK(m) \
+    (GST_VALIDATE_MONITOR_GET_PARENT(m) ? \
+        GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_SINK ( \
+            GST_VALIDATE_MONITOR_GET_PARENT(m)) : \
+        FALSE)
+
 
 /*
  * Locking the parent should always be done before locking the
@@ -115,6 +126,17 @@ G_STMT_START {                                               \
   }                                                          \
 } G_STMT_END
 
+/* Structure used to store all seek-related information */
+struct _GstValidatePadSeekData
+{
+  guint32 seqnum;
+  gdouble rate;
+  GstFormat format;
+  GstSeekFlags flags;
+  GstSeekType start_type, stop_type;
+  gint64 start, stop;
+};
+
 typedef struct
 {
   GstClockTime timestamp;
@@ -122,23 +144,27 @@ typedef struct
 } SerializedEventData;
 
 static GstPad *
-_get_actual_pad (GstPad *pad)
+_get_actual_pad (GstPad * pad)
 {
-  GstPad *tmp_pad;
+  pad = gst_object_ref (pad);
 
-  gst_object_ref (pad);
+  while (GST_IS_PROXY_PAD (pad)) {
+    GstPad *next_pad;
 
-  /* We don't monitor ghost pads */
-  while (GST_IS_GHOST_PAD (pad)) {
-    tmp_pad = pad;
-    pad = gst_ghost_pad_get_target ((GstGhostPad *) pad);
-    gst_object_unref (tmp_pad);
-  }
+    if (GST_PAD_IS_SINK (pad)) {
+      if (GST_IS_GHOST_PAD (pad))
+        next_pad = gst_ghost_pad_get_target (GST_GHOST_PAD (pad));
+      else
+        next_pad = GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (pad)));
+    } else {
+      next_pad = gst_pad_get_peer (pad);
+    }
 
-  while (GST_IS_PROXY_PAD (pad)) {
-    tmp_pad = pad;
-    pad = gst_pad_get_peer (pad);
-    gst_object_unref (tmp_pad);
+    gst_object_unref (pad);
+    if (!next_pad)
+      return NULL;
+
+    pad = next_pad;
   }
 
   return pad;
@@ -150,10 +176,16 @@ _find_master_report_on_pad (GstPad * pad, GstValidateReport * report)
   GstValidatePadMonitor *pad_monitor;
   GstValidateReport *prev_report;
   gboolean result = FALSE;
+  GstPad *tmppad = pad;
 
   pad = _get_actual_pad (pad);
+  if (pad == NULL) {
+    GST_ERROR_OBJECT (tmppad, "Does not have a target yet");
 
-  pad_monitor = g_object_get_data ((GObject *) pad, "validate-monitor");
+    return FALSE;
+  }
+
+  pad_monitor = _GET_PAD_MONITOR (pad);
 
   /* For some reason this pad isn't monitored */
   if (pad_monitor == NULL)
@@ -182,8 +214,12 @@ _find_master_report_for_sink_pad (GstValidatePadMonitor * pad_monitor,
 {
   GstPad *peerpad;
   gboolean result = FALSE;
+  GstPad *pad =
+      GST_PAD_CAST (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
+          (pad_monitor)));
 
-  peerpad = gst_pad_get_peer (pad_monitor->pad);
+  peerpad = gst_pad_get_peer (pad);
+  gst_object_unref (pad);
 
   /* If the peer src pad already has a similar report no need to look
    * any further */
@@ -202,18 +238,19 @@ _find_master_report_for_src_pad (GstValidatePadMonitor * pad_monitor,
 {
   GstIterator *iter;
   gboolean done;
-  GstPad *pad;
   gboolean result = FALSE;
+  GstPad *target =
+      GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
+          (pad_monitor)));
 
-  iter =
-      gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
-      (pad_monitor));
+  iter = gst_pad_iterate_internal_links (target);
   done = FALSE;
   while (!done) {
     GValue value = { 0, };
     switch (gst_iterator_next (iter, &value)) {
       case GST_ITERATOR_OK:
-        pad = g_value_get_object (&value);
+      {
+        GstPad *pad = g_value_get_object (&value);
 
         if (_find_master_report_on_pad (pad, report)) {
           result = TRUE;
@@ -222,12 +259,12 @@ _find_master_report_for_src_pad (GstValidatePadMonitor * pad_monitor,
 
         g_value_reset (&value);
         break;
+      }
       case GST_ITERATOR_RESYNC:
         gst_iterator_resync (iter);
         break;
       case GST_ITERATOR_ERROR:
-        GST_WARNING_OBJECT (pad_monitor->pad,
-            "Internal links pad iteration error");
+        GST_WARNING_OBJECT (target, "Internal links pad iteration error");
         done = TRUE;
         break;
       case GST_ITERATOR_DONE:
@@ -235,6 +272,7 @@ _find_master_report_for_src_pad (GstValidatePadMonitor * pad_monitor,
         break;
     }
   }
+  gst_object_unref (target);
   gst_iterator_free (iter);
 
   return result;
@@ -244,13 +282,21 @@ static GstValidateInterceptionReturn
 _concatenate_issues (GstValidatePadMonitor * pad_monitor,
     GstValidateReport * report)
 {
-  if (GST_PAD_IS_SINK (pad_monitor->pad)
-      && _find_master_report_for_sink_pad (pad_monitor, report))
+  GstPad *pad =
+      GST_PAD_CAST (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
+          (pad_monitor)));
+
+  if (GST_PAD_IS_SINK (pad)
+      && _find_master_report_for_sink_pad (pad_monitor, report)) {
+    gst_object_unref (pad);
     return GST_VALIDATE_REPORTER_KEEP;
-  else if (GST_PAD_IS_SRC (pad_monitor->pad)
-      && _find_master_report_for_src_pad (pad_monitor, report))
+  } else if (GST_PAD_IS_SRC (pad)
+      && _find_master_report_for_src_pad (pad_monitor, report)) {
+    gst_object_unref (pad);
     return GST_VALIDATE_REPORTER_KEEP;
+  }
 
+  gst_object_unref (pad);
   return GST_VALIDATE_REPORTER_REPORT;
 }
 
@@ -260,7 +306,7 @@ gst_validate_pad_monitor_intercept_report (GstValidateReporter *
 {
   GstValidateReporterInterface *iface_class, *old_iface_class;
   GstValidatePadMonitor *pad_monitor = GST_VALIDATE_PAD_MONITOR (reporter);
-  GstValidateReportingLevel monitor_reporting_level;
+  GstValidateReportingDetails monitor_reporting_level;
   GstValidateInterceptionReturn ret;
 
   monitor_reporting_level =
@@ -274,10 +320,10 @@ gst_validate_pad_monitor_intercept_report (GstValidateReporter *
   old_iface_class->intercept_report (reporter, report);
 
   switch (monitor_reporting_level) {
-    case GST_VALIDATE_REPORTING_LEVEL_NONE:
+    case GST_VALIDATE_SHOW_NONE:
       ret = GST_VALIDATE_REPORTER_DROP;
       break;
-    case GST_VALIDATE_REPORTING_LEVEL_UNKNOWN:
+    case GST_VALIDATE_SHOW_UNKNOWN:
       ret = _concatenate_issues (pad_monitor, report);
       break;
     default:
@@ -370,7 +416,7 @@ _check_field_type (GstValidatePadMonitor * monitor,
     return;
   }
 
-  memset (rejected_types, 0, sizeof (rejected_types));
+  memset ((gchar **) rejected_types, 0, sizeof (rejected_types));
   va_start (var_args, field);
   while ((type = va_arg (var_args, GType)) != 0) {
     if (gst_structure_has_field_typed (structure, field, type)) {
@@ -434,7 +480,7 @@ gst_validate_pad_monitor_check_caps_complete (GstValidatePadMonitor * monitor,
   GstStructure *structure;
   gint i;
 
-  GST_DEBUG_OBJECT (monitor->pad, "Checking caps %" GST_PTR_FORMAT, caps);
+  GST_DEBUG_OBJECT (monitor, "Checking caps %" GST_PTR_FORMAT, caps);
 
   for (i = 0; i < gst_caps_get_size (caps); i++) {
     structure = gst_caps_get_structure (caps, i);
@@ -451,17 +497,19 @@ gst_validate_pad_monitor_check_caps_complete (GstValidatePadMonitor * monitor,
 }
 
 static GstCaps *
-gst_validate_pad_monitor_get_othercaps (GstValidatePadMonitor * monitor)
+gst_validate_pad_monitor_get_othercaps (GstValidatePadMonitor * monitor,
+    GstCaps * filter)
 {
   GstCaps *caps = gst_caps_new_empty ();
   GstIterator *iter;
   gboolean done;
   GstPad *otherpad;
   GstCaps *peercaps;
+  GstPad *pad =
+      GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
+          (monitor)));
 
-  iter =
-      gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
-      (monitor));
+  iter = gst_pad_iterate_internal_links (pad);
   done = FALSE;
   while (!done) {
     GValue value = { 0, };
@@ -471,7 +519,7 @@ gst_validate_pad_monitor_get_othercaps (GstValidatePadMonitor * monitor)
 
         /* TODO What would be the correct caps operation to merge the caps in
          * case one sink is internally linked to multiple srcs? */
-        peercaps = gst_pad_get_current_caps (otherpad);
+        peercaps = gst_pad_peer_query_caps (otherpad, filter);
         if (peercaps)
           caps = gst_caps_merge (caps, peercaps);
 
@@ -479,10 +527,11 @@ gst_validate_pad_monitor_get_othercaps (GstValidatePadMonitor * monitor)
         break;
       case GST_ITERATOR_RESYNC:
         gst_iterator_resync (iter);
-        gst_caps_replace (&caps, gst_caps_new_empty ());
+        gst_caps_unref (caps);
+        caps = gst_caps_new_empty ();
         break;
       case GST_ITERATOR_ERROR:
-        GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error");
+        GST_WARNING_OBJECT (pad, "Internal links pad iteration error");
         done = TRUE;
         break;
       case GST_ITERATOR_DONE:
@@ -490,9 +539,10 @@ gst_validate_pad_monitor_get_othercaps (GstValidatePadMonitor * monitor)
         break;
     }
   }
-  gst_iterator_free (iter);
+  GST_DEBUG_OBJECT (pad, "Otherpad caps: %" GST_PTR_FORMAT, caps);
 
-  GST_DEBUG_OBJECT (monitor->pad, "Otherpad caps: %" GST_PTR_FORMAT, caps);
+  gst_iterator_free (iter);
+  gst_object_unref (pad);
 
   return caps;
 }
@@ -503,7 +553,7 @@ _structure_is_video (GstStructure * structure)
   const gchar *name = gst_structure_get_name (structure);
 
   return g_strstr_len (name, 6, "video/")
-      && strcmp (name, "video/quicktime") != 0;
+      && g_strcmp0 (name, "video/quicktime") != 0;
 }
 
 static gboolean
@@ -524,8 +574,9 @@ gst_validate_pad_monitor_pad_should_proxy_othercaps (GstValidatePadMonitor *
     return FALSE;
 
   /* We only know how to handle othercaps checks for codecs so far */
-  return GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DECODER (parent) ||
-      GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_ENCODER (parent);
+  return (GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DECODER (parent) ||
+      GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_ENCODER (parent)) &&
+      !GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_CONVERTER (parent);
 }
 
 
@@ -610,18 +661,131 @@ _structures_field_is_contained (GstStructure * s1, GstStructure * s2,
 }
 
 static void
+_check_and_copy_structure_field (GstStructure * from, GstStructure * to,
+    const gchar * name)
+{
+  if (gst_structure_has_field (from, name)) {
+    gst_structure_set_value (to, name, gst_structure_get_value (from, name));
+  }
+}
+
+static GstCaps *
+gst_validate_pad_monitor_copy_caps_fields_into_caps (GstValidatePadMonitor *
+    monitor, GstCaps * from_caps, GstCaps * into_caps)
+{
+  gint i, j, into_size, from_size;
+  GstStructure *structure;
+  GstCaps *res = gst_caps_new_empty ();
+
+  into_size = gst_caps_get_size (into_caps);
+  from_size = gst_caps_get_size (from_caps);
+
+  for (i = 0; i < into_size; i++) {
+    GstStructure *s = gst_caps_get_structure (into_caps, i);
+
+    for (j = 0; j < from_size; j++) {
+      GstStructure *new_structure = gst_structure_copy (s);
+
+      structure = gst_caps_get_structure (from_caps, j);
+      if (_structure_is_video (structure)) {
+        _check_and_copy_structure_field (structure, new_structure, "width");
+        _check_and_copy_structure_field (structure, new_structure, "height");
+        _check_and_copy_structure_field (structure, new_structure, "framerate");
+        _check_and_copy_structure_field (structure, new_structure,
+            "pixel-aspect-ratio");
+      } else if (_structure_is_audio (s)) {
+        _check_and_copy_structure_field (structure, new_structure, "rate");
+        _check_and_copy_structure_field (structure, new_structure, "channels");
+      }
+
+      gst_caps_append_structure (res, new_structure);
+    }
+  }
+  return res;
+}
+
+static GstCaps *
+gst_validate_pad_monitor_transform_caps (GstValidatePadMonitor * monitor,
+    GstCaps * caps)
+{
+  GstCaps *othercaps;
+  GstCaps *new_caps;
+  GstIterator *iter;
+  gboolean done;
+  GstPad *otherpad;
+  GstCaps *template_caps;
+  GstPad *pad;
+
+
+  GST_DEBUG_OBJECT (monitor, "Transform caps %" GST_PTR_FORMAT, caps);
+
+  if (caps == NULL)
+    return NULL;
+
+  othercaps = gst_caps_new_empty ();
+
+  pad =
+      GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
+          (monitor)));
+  iter = gst_pad_iterate_internal_links (pad);
+  done = FALSE;
+  while (!done) {
+    GValue value = { 0, };
+    switch (gst_iterator_next (iter, &value)) {
+      case GST_ITERATOR_OK:
+        otherpad = g_value_get_object (&value);
+        template_caps = gst_pad_get_pad_template_caps (otherpad);
+
+        new_caps =
+            gst_validate_pad_monitor_copy_caps_fields_into_caps (monitor, caps,
+            template_caps);
+        if (!gst_caps_is_empty (new_caps))
+          gst_caps_append (othercaps, new_caps);
+        else
+          gst_caps_unref (new_caps);
+
+        gst_caps_unref (template_caps);
+        g_value_reset (&value);
+        break;
+      case GST_ITERATOR_RESYNC:
+        gst_iterator_resync (iter);
+        gst_caps_unref (othercaps);
+        othercaps = gst_caps_new_empty ();
+        break;
+      case GST_ITERATOR_ERROR:
+        GST_WARNING_OBJECT (pad, "Internal links pad iteration error");
+        done = TRUE;
+        break;
+      case GST_ITERATOR_DONE:
+        done = TRUE;
+        break;
+    }
+  }
+  gst_iterator_free (iter);
+
+  GST_DEBUG_OBJECT (pad, "Transformed caps: %" GST_PTR_FORMAT, othercaps);
+  gst_object_unref (pad);
+
+  return othercaps;
+}
+
+static void
 gst_validate_pad_monitor_check_caps_fields_proxied (GstValidatePadMonitor *
-    monitor, GstCaps * caps)
+    monitor, GstCaps * caps, GstCaps * filter)
 {
   GstStructure *structure;
   GstStructure *otherstructure;
   GstCaps *othercaps;
+  GstCaps *otherfilter;
   gint i, j;
 
   if (!gst_validate_pad_monitor_pad_should_proxy_othercaps (monitor))
     return;
 
-  othercaps = gst_validate_pad_monitor_get_othercaps (monitor);
+  otherfilter = gst_validate_pad_monitor_transform_caps (monitor, filter);
+  othercaps = gst_validate_pad_monitor_get_othercaps (monitor, otherfilter);
+  if (otherfilter)
+    gst_caps_unref (otherfilter);
 
   for (i = 0; i < gst_caps_get_size (othercaps); i++) {
     gboolean found = FALSE;
@@ -676,6 +840,8 @@ gst_validate_pad_monitor_check_caps_fields_proxied (GstValidatePadMonitor *
       g_free (caps_str);
     }
   }
+
+  gst_caps_unref (othercaps);
 }
 
 static void
@@ -683,28 +849,32 @@ gst_validate_pad_monitor_check_late_serialized_events (GstValidatePadMonitor *
     monitor, GstClockTime ts)
 {
   gint i;
+  GstPad *pad;
 
   if (!GST_CLOCK_TIME_IS_VALID (ts))
     return;
 
-  GST_DEBUG_OBJECT (monitor->pad, "Timestamp to check %" GST_TIME_FORMAT,
+  pad =
+      GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
+          (monitor)));
+
+  GST_DEBUG_OBJECT (pad, "Timestamp to check %" GST_TIME_FORMAT,
       GST_TIME_ARGS (ts));
 
   for (i = 0; i < monitor->serialized_events->len; i++) {
     SerializedEventData *data =
         g_ptr_array_index (monitor->serialized_events, i);
 
-    GST_DEBUG_OBJECT (monitor->pad, "Event #%d (%s) ts: %" GST_TIME_FORMAT,
+    GST_DEBUG_OBJECT (pad, "Event #%d (%s) ts: %" GST_TIME_FORMAT,
         i, GST_EVENT_TYPE_NAME (data->event), GST_TIME_ARGS (data->timestamp));
 
     if (GST_CLOCK_TIME_IS_VALID (data->timestamp) && data->timestamp < ts) {
       gchar *event_str = _get_event_string (data->event);
 
       GST_VALIDATE_REPORT (monitor, SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME,
-          "Serialized event %s wasn't pushed before expected " "timestamp %"
+          "Serialized event %s wasn't pushed before expected timestamp %"
           GST_TIME_FORMAT " on pad %s:%s", event_str,
-          GST_TIME_ARGS (data->timestamp),
-          GST_DEBUG_PAD_NAME (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor)));
+          GST_TIME_ARGS (data->timestamp), GST_DEBUG_PAD_NAME (pad));
 
       g_free (event_str);
     } else {
@@ -714,20 +884,45 @@ gst_validate_pad_monitor_check_late_serialized_events (GstValidatePadMonitor *
   }
 
   if (i) {
-    debug_pending_event (monitor->pad, monitor->serialized_events);
+    debug_pending_event (pad, monitor->serialized_events);
     g_ptr_array_remove_range (monitor->serialized_events, 0, i);
   }
+
+  gst_object_unref (pad);
+}
+
+static void
+seek_data_free (GstValidatePadSeekData * data)
+{
+  g_slice_free (GstValidatePadSeekData, data);
+}
+
+static GstValidatePadSeekData *
+seek_data_for_seqnum (GstValidatePadMonitor * monitor, guint32 seqnum)
+{
+  GList *tmp;
+
+  for (tmp = monitor->seeks; tmp; tmp = tmp->next) {
+    GstValidatePadSeekData *data = (GstValidatePadSeekData *) tmp->data;
+    if (data->seqnum == seqnum)
+      return data;
+  }
+
+  return NULL;
 }
 
 static void
 gst_validate_pad_monitor_dispose (GObject * object)
 {
   GstValidatePadMonitor *monitor = GST_VALIDATE_PAD_MONITOR_CAST (object);
-  GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor);
+  GstPad *pad =
+      GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
+          (monitor)));
 
   if (pad) {
     if (monitor->pad_probe_id)
       gst_pad_remove_probe (pad, monitor->pad_probe_id);
+    gst_object_unref (pad);
   }
 
   if (monitor->expected_segment)
@@ -736,6 +931,13 @@ gst_validate_pad_monitor_dispose (GObject * object)
   gst_structure_free (monitor->pending_setcaps_fields);
   g_ptr_array_unref (monitor->serialized_events);
   g_list_free_full (monitor->expired_events, (GDestroyNotify) gst_event_unref);
+  g_list_free_full (monitor->all_bufs, (GDestroyNotify) gst_buffer_unref);
+  gst_caps_replace (&monitor->last_caps, NULL);
+  gst_caps_replace (&monitor->last_query_res, NULL);
+  gst_caps_replace (&monitor->last_query_filter, NULL);
+  gst_caps_replace (&monitor->last_refused_caps, NULL);
+
+  g_list_free_full (monitor->seeks, (GDestroyNotify) seek_data_free);
 
   G_OBJECT_CLASS (parent_class)->dispose (object);
 }
@@ -755,25 +957,87 @@ gst_validate_pad_monitor_class_init (GstValidatePadMonitorClass * klass)
   monitor_klass->get_element = gst_validate_pad_monitor_get_element;
 }
 
+/* Called when a pad is being flushed */
 static void
-gst_validate_pad_monitor_init (GstValidatePadMonitor * pad_monitor)
+gst_validate_pad_monitor_flush (GstValidatePadMonitor * pad_monitor)
 {
+  /* Note: Keep in the same order as in the GstValidatePadMonitor structure */
+
+  gst_caps_replace (&pad_monitor->last_caps, NULL);
+  pad_monitor->caps_is_audio = pad_monitor->caps_is_video =
+      pad_monitor->caps_is_raw = FALSE;
+
+  pad_monitor->first_buffer = TRUE;
+
+  pad_monitor->has_segment = FALSE;
+  pad_monitor->is_eos = FALSE;
+
+  pad_monitor->pending_buffer_discont = TRUE;
+
+  gst_event_replace (&pad_monitor->expected_segment, NULL);
+  if (pad_monitor->serialized_events->len)
+    g_ptr_array_remove_range (pad_monitor->serialized_events, 0,
+        pad_monitor->serialized_events->len);
+  g_list_free_full (pad_monitor->expired_events,
+      (GDestroyNotify) gst_event_unref);
+  pad_monitor->expired_events = NULL;
+
+  gst_segment_init (&pad_monitor->segment, GST_FORMAT_BYTES);
+  pad_monitor->current_timestamp = GST_CLOCK_TIME_NONE;
+  pad_monitor->current_duration = GST_CLOCK_TIME_NONE;
+
+  pad_monitor->timestamp_range_start = GST_CLOCK_TIME_NONE;
+  pad_monitor->timestamp_range_end = GST_CLOCK_TIME_NONE;
+}
+
+/* Called when the pad monitor is initialized or when
+ * the pad is deactivated */
+static void
+gst_validate_pad_monitor_reset (GstValidatePadMonitor * pad_monitor)
+{
+  gst_validate_pad_monitor_flush (pad_monitor);
+
+  /* Note : For the entries that haven't been reset in _flush(), do
+   * it here and keep in the same order as the GstValidatePadMonitor
+   * structure */
+
+  pad_monitor->pending_flush_stop = FALSE;
+  pad_monitor->pending_newsegment_seqnum = GST_SEQNUM_INVALID;
+  pad_monitor->pending_eos_seqnum = GST_SEQNUM_INVALID;
+
+  if (pad_monitor->pending_setcaps_fields)
+    gst_structure_free (pad_monitor->pending_setcaps_fields);
   pad_monitor->pending_setcaps_fields =
       gst_structure_new_empty (PENDING_FIELDS);
+  if (pad_monitor->seeks)
+    g_list_free_full (pad_monitor->seeks, (GDestroyNotify) seek_data_free);
+  pad_monitor->current_seek = NULL;
+  pad_monitor->seeks = NULL;
+
+  /* FIXME : Why BYTES and not UNDEFINED ? */
+  gst_segment_init (&pad_monitor->segment, GST_FORMAT_BYTES);
+
+  pad_monitor->min_buf_freq = 0;
+  pad_monitor->buffers_pushed = 0;
+  pad_monitor->last_buffers_pushed = 0;
+  pad_monitor->min_buf_freq_interval_ts = GST_CLOCK_TIME_NONE;
+  pad_monitor->min_buf_freq_first_buffer_ts = GST_CLOCK_TIME_NONE;
+  pad_monitor->min_buf_freq_start = GST_CLOCK_TIME_NONE;
+}
+
+static void
+gst_validate_pad_monitor_init (GstValidatePadMonitor * pad_monitor)
+{
   pad_monitor->serialized_events =
       g_ptr_array_new_with_free_func ((GDestroyNotify)
       _serialized_event_data_free);
-  pad_monitor->expired_events = NULL;
-  gst_segment_init (&pad_monitor->segment, GST_FORMAT_BYTES);
-  pad_monitor->first_buffer = TRUE;
 
-  pad_monitor->timestamp_range_start = GST_CLOCK_TIME_NONE;
-  pad_monitor->timestamp_range_end = GST_CLOCK_TIME_NONE;
+  gst_validate_pad_monitor_reset (pad_monitor);
 }
 
 /**
  * gst_validate_pad_monitor_new:
- * @pad: (transfer-none): a #GstPad to run Validate on
+ * @pad: (transfer none): a #GstPad to run Validate on
  */
 GstValidatePadMonitor *
 gst_validate_pad_monitor_new (GstPad * pad, GstValidateRunner * runner,
@@ -782,20 +1046,29 @@ gst_validate_pad_monitor_new (GstPad * pad, GstValidateRunner * runner,
   GstValidatePadMonitor *monitor = g_object_new (GST_TYPE_VALIDATE_PAD_MONITOR,
       "object", pad, "validate-runner", runner, "validate-parent",
       parent, NULL);
+  GstObject *target =
+      gst_validate_monitor_get_target (GST_VALIDATE_MONITOR (monitor));
 
-  if (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor) == NULL) {
+  if (target == NULL) {
     g_object_unref (monitor);
     return NULL;
   }
+
+  gst_object_unref (target);
   return monitor;
 }
 
 static GstElement *
 gst_validate_pad_monitor_get_element (GstValidateMonitor * monitor)
 {
-  GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor);
+  GstPad *pad =
+      GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
+          (monitor)));
+  GstElement *parent = GST_ELEMENT (gst_pad_get_parent (pad));
 
-  return GST_PAD_PARENT (pad);
+  gst_object_unref (pad);
+
+  return parent;
 }
 
 static void
@@ -888,13 +1161,19 @@ static gboolean
 gst_validate_pad_monitor_timestamp_is_in_received_range (GstValidatePadMonitor *
     monitor, GstClockTime ts, GstClockTime tolerance)
 {
-  GST_DEBUG_OBJECT (monitor->pad, "Checking if timestamp %" GST_TIME_FORMAT
-      " is in range: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT " for pad "
+  GstPad *pad =
+      GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
+          (monitor)));
+
+  GST_DEBUG_OBJECT (pad,
+      "Checking if timestamp %" GST_TIME_FORMAT " is in range: %"
+      GST_TIME_FORMAT " - %" GST_TIME_FORMAT " for pad "
       "%s:%s with tolerance: %" GST_TIME_FORMAT, GST_TIME_ARGS (ts),
       GST_TIME_ARGS (monitor->timestamp_range_start),
-      GST_TIME_ARGS (monitor->timestamp_range_end),
-      GST_DEBUG_PAD_NAME (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor)),
+      GST_TIME_ARGS (monitor->timestamp_range_end), GST_DEBUG_PAD_NAME (pad),
       GST_TIME_ARGS (tolerance));
+  gst_object_unref (pad);
+
   return !GST_CLOCK_TIME_IS_VALID (monitor->timestamp_range_start) ||
       !GST_CLOCK_TIME_IS_VALID (monitor->timestamp_range_end) ||
       ((monitor->timestamp_range_start >= tolerance ?
@@ -918,25 +1197,26 @@ static void
   gboolean done;
   GstPad *otherpad;
   GstValidatePadMonitor *othermonitor;
+  GstPad *pad =
+      GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
+          (monitor)));
 
   if (!GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))
       || !GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) {
-    GST_DEBUG_OBJECT (monitor->pad,
+    GST_DEBUG_OBJECT (pad,
         "Can't check buffer timestamps range as "
         "buffer has no valid timestamp/duration");
-    return;
+    goto done;
   }
+
   ts = GST_BUFFER_TIMESTAMP (buffer);
   ts_end = ts + GST_BUFFER_DURATION (buffer);
 
-  iter =
-      gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
-      (monitor));
+  iter = gst_pad_iterate_internal_links (pad);
 
   if (iter == NULL) {
-    GST_WARNING_OBJECT (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor),
-        "No iterator available");
-    return;
+    GST_WARNING_OBJECT (pad, "No iterator available");
+    goto done;
   }
 
   done = FALSE;
@@ -945,10 +1225,12 @@ static void
     switch (gst_iterator_next (iter, &value)) {
       case GST_ITERATOR_OK:
         otherpad = g_value_get_object (&value);
-        GST_DEBUG_OBJECT (monitor->pad, "Checking pad %s:%s input timestamps",
+        GST_DEBUG_OBJECT (pad, "Checking pad %s:%s input timestamps",
             GST_DEBUG_PAD_NAME (otherpad));
-        othermonitor =
-            g_object_get_data ((GObject *) otherpad, "validate-monitor");
+        othermonitor = _GET_PAD_MONITOR (otherpad);
+        if (!othermonitor)
+          continue;
+
         GST_VALIDATE_MONITOR_LOCK (othermonitor);
         if (gst_validate_pad_monitor_timestamp_is_in_received_range
             (othermonitor, ts, tolerance)
@@ -968,7 +1250,7 @@ static void
         found = FALSE;
         break;
       case GST_ITERATOR_ERROR:
-        GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error");
+        GST_WARNING_OBJECT (pad, "Internal links pad iteration error");
         done = TRUE;
         break;
       case GST_ITERATOR_DONE:
@@ -979,9 +1261,9 @@ static void
   gst_iterator_free (iter);
 
   if (!has_one) {
-    GST_DEBUG_OBJECT (monitor->pad, "Skipping timestamp in range check as no "
+    GST_DEBUG_OBJECT (pad, "Skipping timestamp in range check as no "
         "internal linked pad was found");
-    return;
+    goto done;
   }
   if (!found) {
     GST_VALIDATE_REPORT (monitor, BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE,
@@ -989,38 +1271,47 @@ static void
         " is out of range of received input", GST_TIME_ARGS (ts),
         GST_TIME_ARGS (ts_end));
   }
+done:
+  if (pad)
+    gst_object_unref (pad);
+}
+
+static void
+gst_validate_pad_monitor_check_discont (GstValidatePadMonitor * pad_monitor,
+    GstBuffer * buffer)
+{
+  if (pad_monitor->pending_buffer_discont) {
+    if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT))
+      GST_VALIDATE_REPORT (pad_monitor, BUFFER_MISSING_DISCONT,
+          "Buffer is missing a DISCONT flag");
+    pad_monitor->pending_buffer_discont = FALSE;
+  }
 }
 
 static void
 gst_validate_pad_monitor_check_first_buffer (GstValidatePadMonitor *
     pad_monitor, GstBuffer * buffer)
 {
+  GstPad *pad =
+      GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
+          (pad_monitor)));
+
   if (G_UNLIKELY (pad_monitor->first_buffer)) {
     pad_monitor->first_buffer = FALSE;
 
-    if (!pad_monitor->has_segment
-        && PAD_IS_IN_PUSH_MODE (GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor)))
-    {
+    if (!pad_monitor->has_segment && PAD_IS_IN_PUSH_MODE (pad)) {
       GST_VALIDATE_REPORT (pad_monitor, BUFFER_BEFORE_SEGMENT,
           "Received buffer before Segment event");
     }
 
-    GST_DEBUG_OBJECT (pad_monitor->pad,
+    GST_DEBUG_OBJECT (pad,
         "Checking first buffer (pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
         ")", GST_TIME_ARGS (GST_BUFFER_PTS (buffer)),
         GST_TIME_ARGS (GST_BUFFER_DTS (buffer)));
 
-    if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) {
-      gint64 running_time = gst_segment_to_running_time (&pad_monitor->segment,
-          pad_monitor->segment.format, GST_BUFFER_TIMESTAMP (buffer));
-      /* Only check for in-segment buffers */
-      if (GST_CLOCK_TIME_IS_VALID (running_time) && running_time != 0) {
-        GST_VALIDATE_REPORT (pad_monitor, FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO,
-            "First buffer running time is not 0, it is: %" GST_TIME_FORMAT,
-            GST_TIME_ARGS (running_time));
-      }
-    }
   }
+
+  gst_object_unref (pad);
 }
 
 static void
@@ -1037,6 +1328,9 @@ static void
 gst_validate_pad_monitor_update_buffer_data (GstValidatePadMonitor *
     pad_monitor, GstBuffer * buffer)
 {
+  GstPad *pad =
+      GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
+          (pad_monitor)));
   pad_monitor->current_timestamp = GST_BUFFER_TIMESTAMP (buffer);
   pad_monitor->current_duration = GST_BUFFER_DURATION (buffer);
   if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) {
@@ -1059,10 +1353,12 @@ gst_validate_pad_monitor_update_buffer_data (GstValidatePadMonitor *
       }
     }
   }
-  GST_DEBUG_OBJECT (pad_monitor->pad, "Current stored range: %" GST_TIME_FORMAT
+  GST_DEBUG_OBJECT (pad, "Current stored range: %" GST_TIME_FORMAT
       " - %" GST_TIME_FORMAT,
       GST_TIME_ARGS (pad_monitor->timestamp_range_start),
       GST_TIME_ARGS (pad_monitor->timestamp_range_end));
+
+  gst_object_unref (pad);
 }
 
 static GstFlowReturn
@@ -1083,16 +1379,18 @@ _combine_flows (GstFlowReturn ret1, GstFlowReturn ret2)
 
 static void
 gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor *
-    monitor, GstFlowReturn ret)
+    monitor, GstObject * parent, GstFlowReturn ret)
 {
   GstIterator *iter;
   gboolean done;
   GstPad *otherpad;
   GstPad *peerpad;
-  GstValidatePadMonitor *othermonitor;
+  GstState state, pending;
   GstFlowReturn aggregated = GST_FLOW_NOT_LINKED;
   gboolean found_a_pad = FALSE;
-  GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor);
+  GstPad *pad =
+      GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
+          (monitor)));
 
   iter = gst_pad_iterate_internal_links (pad);
   done = FALSE;
@@ -1103,15 +1401,10 @@ gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor *
         otherpad = g_value_get_object (&value);
         peerpad = gst_pad_get_peer (otherpad);
         if (peerpad) {
-          othermonitor =
-              g_object_get_data ((GObject *) peerpad, "validate-monitor");
-          if (othermonitor) {
-            found_a_pad = TRUE;
-            GST_VALIDATE_MONITOR_LOCK (othermonitor);
-            aggregated =
-                _combine_flows (aggregated, othermonitor->last_flow_return);
-            GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
-          }
+          found_a_pad = TRUE;
+          aggregated =
+              _combine_flows (aggregated,
+              gst_pad_get_last_flow_return (peerpad));
 
           gst_object_unref (peerpad);
         }
@@ -1121,7 +1414,7 @@ gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor *
         gst_iterator_resync (iter);
         break;
       case GST_ITERATOR_ERROR:
-        GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error");
+        GST_WARNING_OBJECT (pad, "Internal links pad iteration error");
         done = TRUE;
         break;
       case GST_ITERATOR_DONE:
@@ -1132,24 +1425,42 @@ gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor *
   gst_iterator_free (iter);
   if (!found_a_pad) {
     /* no peer pad found, nothing to do */
-    return;
+    goto done;
   }
-  if (aggregated == GST_FLOW_OK || aggregated == GST_FLOW_EOS) {
-    /* those are acceptable situations */
 
+  if (aggregated == GST_FLOW_FLUSHING) {
+    gst_element_get_state (GST_ELEMENT (parent), &state, &pending, 0);
+    if (state < GST_STATE_PAUSED || pending < GST_STATE_PAUSED) {
+      /* Aggregated is flushing, we might have been aggregating a combination
+       * of pads that are not what was present on the element during the actual
+       * data flow combination (pads might have been removed meanwhile) */
+
+      goto done;
+    }
+  } else if (aggregated == GST_FLOW_OK || aggregated == GST_FLOW_EOS) {
+
+    /* those are acceptable situations */
     if (GST_PAD_IS_FLUSHING (pad) && ret == GST_FLOW_FLUSHING) {
       /* pad is flushing, always acceptable to return flushing */
-      return;
+      goto done;
+    }
+
+    gst_element_get_state (GST_ELEMENT (parent), &state, &pending, 0);
+    if (ret == GST_FLOW_FLUSHING && (state < GST_STATE_PAUSED
+            || pending < GST_STATE_PAUSED)) {
+      /* Element is being teared down, accept FLOW_FLUSHING */
+
+      goto done;
     }
 
     if (monitor->is_eos && ret == GST_FLOW_EOS) {
       /* this element received eos and returned eos */
-      return;
+      goto done;
     }
 
     if (PAD_PARENT_IS_DEMUXER (monitor) && ret == GST_FLOW_EOS) {
       /* a demuxer can return EOS when the samples end */
-      return;
+      goto done;
     }
   }
 
@@ -1159,6 +1470,9 @@ gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor *
         gst_flow_get_name (ret), ret, gst_flow_get_name (aggregated),
         aggregated);
   }
+
+done:
+  gst_object_unref (pad);
 }
 
 static void
@@ -1169,33 +1483,36 @@ static void
   gboolean done;
   GstPad *otherpad;
   GstValidatePadMonitor *othermonitor;
+  GstPad *pad;
+
 
   if (!GST_EVENT_IS_SERIALIZED (event))
     return;
 
-  iter =
-      gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
-      (monitor));
+  pad =
+      GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
+          (monitor)));
+  iter = gst_pad_iterate_internal_links (pad);
   if (iter == NULL) {
     /* inputselector will return NULL if the sinkpad is not the active one .... */
-    GST_FIXME_OBJECT (GST_VALIDATE_PAD_MONITOR_GET_PAD
-        (monitor), "No iterator");
+    GST_FIXME_OBJECT (pad, "No iterator");
+    gst_object_unref (pad);
     return;
   }
+
   done = FALSE;
   while (!done) {
     GValue value = { 0, };
     switch (gst_iterator_next (iter, &value)) {
       case GST_ITERATOR_OK:
         otherpad = g_value_get_object (&value);
-        othermonitor =
-            g_object_get_data ((GObject *) otherpad, "validate-monitor");
+        othermonitor = _GET_PAD_MONITOR (otherpad);
         if (othermonitor) {
           SerializedEventData *data = g_slice_new0 (SerializedEventData);
           data->timestamp = last_ts;
           data->event = gst_event_ref (event);
           GST_VALIDATE_MONITOR_LOCK (othermonitor);
-          GST_DEBUG_OBJECT (monitor->pad, "Storing for pad %s:%s event %p %s",
+          GST_DEBUG_OBJECT (pad, "Storing for pad %s:%s event %p %s",
               GST_DEBUG_PAD_NAME (otherpad), event,
               GST_EVENT_TYPE_NAME (event));
           g_ptr_array_add (othermonitor->serialized_events, data);
@@ -1208,7 +1525,7 @@ static void
         gst_iterator_resync (iter);
         break;
       case GST_ITERATOR_ERROR:
-        GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error");
+        GST_WARNING_OBJECT (pad, "Internal links pad iteration error");
         done = TRUE;
         break;
       case GST_ITERATOR_DONE:
@@ -1217,6 +1534,7 @@ static void
     }
   }
   gst_iterator_free (iter);
+  gst_object_unref (pad);
 }
 
 static void
@@ -1228,25 +1546,28 @@ gst_validate_pad_monitor_otherpad_add_pending_field (GstValidatePadMonitor *
   GstPad *otherpad;
   GstValidatePadMonitor *othermonitor;
   const GValue *v;
+  GstPad *pad;
 
   v = gst_structure_get_value (structure, field);
+  pad =
+      GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
+          (monitor)));
+
   if (v == NULL) {
-    GST_DEBUG_OBJECT (monitor->pad, "Not adding pending field %s as it isn't "
+    GST_DEBUG_OBJECT (pad, "Not adding pending field %s as it isn't "
         "present on structure %" GST_PTR_FORMAT, field, structure);
+    gst_object_unref (pad);
     return;
   }
 
-  iter =
-      gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
-      (monitor));
+  iter = gst_pad_iterate_internal_links (pad);
   done = FALSE;
   while (!done) {
     GValue value = { 0, };
     switch (gst_iterator_next (iter, &value)) {
       case GST_ITERATOR_OK:
         otherpad = g_value_get_object (&value);
-        othermonitor =
-            g_object_get_data ((GObject *) otherpad, "validate-monitor");
+        othermonitor = _GET_PAD_MONITOR (otherpad);
         if (othermonitor) {
           GST_VALIDATE_MONITOR_LOCK (othermonitor);
           g_assert (othermonitor->pending_setcaps_fields != NULL);
@@ -1260,7 +1581,7 @@ gst_validate_pad_monitor_otherpad_add_pending_field (GstValidatePadMonitor *
         gst_iterator_resync (iter);
         break;
       case GST_ITERATOR_ERROR:
-        GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error");
+        GST_WARNING_OBJECT (pad, "Internal links pad iteration error");
         done = TRUE;
         break;
       case GST_ITERATOR_DONE:
@@ -1269,6 +1590,7 @@ gst_validate_pad_monitor_otherpad_add_pending_field (GstValidatePadMonitor *
     }
   }
   gst_iterator_free (iter);
+  gst_object_unref (pad);
 }
 
 static void
@@ -1280,11 +1602,13 @@ gst_validate_pad_monitor_otherpad_clear_pending_fields (GstValidatePadMonitor *
   GstPad *otherpad;
   GstValidatePadMonitor *othermonitor;
 
-  iter =
-      gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
-      (monitor));
+  GstPad *pad =
+      GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
+          (monitor)));
 
+  iter = gst_pad_iterate_internal_links (pad);
   if (iter == NULL) {
+    gst_object_unref (pad);
     GST_DEBUG_OBJECT (monitor, "No internally linked pad");
 
     return;
@@ -1296,8 +1620,7 @@ gst_validate_pad_monitor_otherpad_clear_pending_fields (GstValidatePadMonitor *
     switch (gst_iterator_next (iter, &value)) {
       case GST_ITERATOR_OK:
         otherpad = g_value_get_object (&value);
-        othermonitor =
-            g_object_get_data ((GObject *) otherpad, "validate-monitor");
+        othermonitor = _GET_PAD_MONITOR (otherpad);
         if (othermonitor) {
           GST_VALIDATE_MONITOR_LOCK (othermonitor);
           g_assert (othermonitor->pending_setcaps_fields != NULL);
@@ -1312,7 +1635,7 @@ gst_validate_pad_monitor_otherpad_clear_pending_fields (GstValidatePadMonitor *
         gst_iterator_resync (iter);
         break;
       case GST_ITERATOR_ERROR:
-        GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error");
+        GST_WARNING_OBJECT (pad, "Internal links pad iteration error");
         done = TRUE;
         break;
       case GST_ITERATOR_DONE:
@@ -1320,6 +1643,7 @@ gst_validate_pad_monitor_otherpad_clear_pending_fields (GstValidatePadMonitor *
         break;
     }
   }
+  gst_object_unref (pad);
   gst_iterator_free (iter);
 }
 
@@ -1331,13 +1655,14 @@ gst_validate_pad_monitor_add_expected_newsegment (GstValidatePadMonitor *
   gboolean done;
   GstPad *otherpad;
   GstValidatePadMonitor *othermonitor;
+  GstPad *pad =
+      GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
+          (monitor)));
 
-  iter =
-      gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
-      (monitor));
-
+  iter = gst_pad_iterate_internal_links (pad);
   if (iter == NULL) {
     GST_DEBUG_OBJECT (monitor, "No internally linked pad");
+    gst_object_unref (pad);
     return;
   }
 
@@ -1347,10 +1672,17 @@ gst_validate_pad_monitor_add_expected_newsegment (GstValidatePadMonitor *
     switch (gst_iterator_next (iter, &value)) {
       case GST_ITERATOR_OK:
         otherpad = g_value_get_object (&value);
-        if (!otherpad)
+        if (!otherpad) {
+          g_value_reset (&value);
           continue;
-        othermonitor =
-            g_object_get_data ((GObject *) otherpad, "validate-monitor");
+        }
+
+        othermonitor = _GET_PAD_MONITOR (otherpad);
+        if (!othermonitor) {
+          g_value_reset (&value);
+          continue;
+        }
+
         GST_VALIDATE_MONITOR_LOCK (othermonitor);
         gst_event_replace (&othermonitor->expected_segment, event);
         GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
@@ -1360,7 +1692,7 @@ gst_validate_pad_monitor_add_expected_newsegment (GstValidatePadMonitor *
         gst_iterator_resync (iter);
         break;
       case GST_ITERATOR_ERROR:
-        GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error");
+        GST_WARNING_OBJECT (pad, "Internal links pad iteration error");
         done = TRUE;
         break;
       case GST_ITERATOR_DONE:
@@ -1369,29 +1701,7 @@ gst_validate_pad_monitor_add_expected_newsegment (GstValidatePadMonitor *
     }
   }
   gst_iterator_free (iter);
-}
-
-static void
-gst_validate_pad_monitor_flush (GstValidatePadMonitor * pad_monitor)
-{
-  pad_monitor->current_timestamp = GST_CLOCK_TIME_NONE;
-  pad_monitor->current_duration = GST_CLOCK_TIME_NONE;
-  pad_monitor->timestamp_range_start = GST_CLOCK_TIME_NONE;
-  pad_monitor->timestamp_range_end = GST_CLOCK_TIME_NONE;
-  pad_monitor->has_segment = FALSE;
-  pad_monitor->is_eos = FALSE;
-  pad_monitor->last_flow_return = GST_FLOW_OK;
-  gst_caps_replace (&pad_monitor->last_caps, NULL);
-  pad_monitor->caps_is_audio = pad_monitor->caps_is_video =
-      pad_monitor->caps_is_raw = FALSE;
-
-  g_list_free_full (pad_monitor->expired_events,
-      (GDestroyNotify) gst_event_unref);
-  pad_monitor->expired_events = NULL;
-
-  if (pad_monitor->serialized_events->len)
-    g_ptr_array_remove_range (pad_monitor->serialized_events, 0,
-        pad_monitor->serialized_events->len);
+  gst_object_unref (pad);
 }
 
 /* common checks for both sink and src event functions */
@@ -1401,38 +1711,50 @@ gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor *
 {
   guint32 seqnum = gst_event_get_seqnum (event);
 
+  if (seqnum == GST_SEQNUM_INVALID)
+    GST_VALIDATE_REPORT (pad_monitor, EVENT_INVALID_SEQNUM,
+        "Event %p (%s) has an invalid SEQNUM", event,
+        GST_EVENT_TYPE_NAME (event));
+
   switch (GST_EVENT_TYPE (event)) {
     case GST_EVENT_FLUSH_START:
     {
-      if (pad_monitor->pending_flush_start_seqnum) {
-        if (seqnum == pad_monitor->pending_flush_start_seqnum) {
-          pad_monitor->pending_flush_start_seqnum = 0;
-        } else {
-          GST_VALIDATE_REPORT (pad_monitor, EVENT_HAS_WRONG_SEQNUM,
-              "The expected flush-start seqnum should be the same as the "
-              "one from the event that caused it (probably a seek). Got: %u."
-              " Expected: %u", seqnum, pad_monitor->pending_flush_start_seqnum);
+      if (pad_monitor->seeks) {
+        GstValidatePadSeekData *seekdata =
+            seek_data_for_seqnum (pad_monitor, seqnum);
+
+        if (!seekdata)
+          GST_VALIDATE_REPORT (pad_monitor, FLUSH_START_HAS_WRONG_SEQNUM,
+              "Got: %" G_GUINT32_FORMAT " Expected: %" G_GUINT32_FORMAT, seqnum,
+              ((GstValidatePadSeekData *) pad_monitor->seeks->data)->seqnum);
+        else {
+          if (!(seekdata->flags & GST_SEEK_FLAG_FLUSH)) {
+            GST_VALIDATE_REPORT (pad_monitor, EVENT_FLUSH_START_UNEXPECTED,
+                "Received flush-start for a non-flushing seek");
+          }
         }
       }
 
       if (pad_monitor->pending_flush_stop) {
         GST_VALIDATE_REPORT (pad_monitor, EVENT_FLUSH_START_UNEXPECTED,
-            "Received flush-start from " " when flush-stop was expected");
+            "Received flush-start from when flush-stop was expected");
       }
       pad_monitor->pending_flush_stop = TRUE;
+      /* Remove the current segment seekdata */
+      if (pad_monitor->current_seek) {
+        pad_monitor->seeks =
+            g_list_remove (pad_monitor->seeks, pad_monitor->current_seek);
+        seek_data_free (pad_monitor->current_seek);
+        pad_monitor->current_seek = NULL;
+      }
     }
       break;
     case GST_EVENT_FLUSH_STOP:
     {
-      if (pad_monitor->pending_flush_stop_seqnum) {
-        if (seqnum == pad_monitor->pending_flush_stop_seqnum) {
-          pad_monitor->pending_flush_stop_seqnum = 0;
-        } else {
-          GST_VALIDATE_REPORT (pad_monitor, EVENT_HAS_WRONG_SEQNUM,
-              "The expected flush-stop seqnum should be the same as the "
-              "one from the event that caused it (probably a seek). Got: %u."
-              " Expected: %u", seqnum, pad_monitor->pending_flush_stop_seqnum);
-        }
+      if (pad_monitor->seeks && !seek_data_for_seqnum (pad_monitor, seqnum)) {
+        GST_VALIDATE_REPORT (pad_monitor, FLUSH_STOP_HAS_WRONG_SEQNUM,
+            "Got: %" G_GUINT32_FORMAT " Expected: %" G_GUINT32_FORMAT, seqnum,
+            ((GstValidatePadSeekData *) pad_monitor->seeks->data)->seqnum);
       }
 
       pad_monitor->pending_newsegment_seqnum = seqnum;
@@ -1447,6 +1769,9 @@ gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor *
       }
       pad_monitor->pending_flush_stop = FALSE;
 
+      /* Buffers following a FLUSH should have the DISCONT flag set */
+      pad_monitor->pending_buffer_discont = TRUE;
+
       /* cleanup our data */
       gst_validate_pad_monitor_flush (pad_monitor);
     }
@@ -1457,16 +1782,20 @@ gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor *
 }
 
 static void
-mark_pads_eos (GstValidatePadMonitor *pad_monitor)
+mark_pads_eos (GstValidatePadMonitor * pad_monitor)
 {
   GstValidatePadMonitor *peer_monitor;
-  GstPad *peer = gst_pad_get_peer (pad_monitor->pad);
   GstPad *real_peer;
+  GstPad *pad =
+      GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
+          (pad_monitor)));
+  GstPad *peer = gst_pad_get_peer (pad);
 
+  gst_object_unref (pad);
   pad_monitor->is_eos = TRUE;
   if (peer) {
     real_peer = _get_actual_pad (peer);
-    peer_monitor = g_object_get_data ((GObject *) real_peer, "validate-monitor");
+    peer_monitor = _GET_PAD_MONITOR (real_peer);
     if (peer_monitor)
       peer_monitor->is_eos = TRUE;
     gst_object_unref (peer);
@@ -1478,7 +1807,9 @@ static inline gboolean
 _should_check_buffers (GstValidatePadMonitor * pad_monitor,
     gboolean force_checks)
 {
-  GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor);
+  GstPad *pad =
+      GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
+          (pad_monitor)));
   GstValidateMonitor *monitor = GST_VALIDATE_MONITOR (pad_monitor);
 
   if (pad_monitor->first_buffer || force_checks) {
@@ -1503,13 +1834,14 @@ _should_check_buffers (GstValidatePadMonitor * pad_monitor,
       GST_DEBUG_OBJECT (pad, "No media_descriptor set => no buffer checking");
 
       pad_monitor->check_buffers = FALSE;
-    } else if (!gst_media_descriptor_detects_frames (monitor->media_descriptor)) {
-      GST_DEBUG_OBJECT (pad, "No frame detection media descriptor "
-          "=> not buffer checking");
+    } else if (!gst_validate_media_descriptor_detects_frames
+        (monitor->media_descriptor)) {
+      GST_DEBUG_OBJECT (pad,
+          "No frame detection media descriptor => no buffer checking");
       pad_monitor->check_buffers = FALSE;
     } else if (pad_monitor->all_bufs == NULL &&
-        !gst_media_descriptor_get_buffers (monitor->media_descriptor, pad, NULL,
-            &pad_monitor->all_bufs)) {
+        !gst_validate_media_descriptor_get_buffers (monitor->media_descriptor,
+            pad, NULL, &pad_monitor->all_bufs)) {
 
       GST_INFO_OBJECT (monitor,
           "The MediaInfo is marked as detecting frame, but getting frames"
@@ -1523,6 +1855,7 @@ _should_check_buffers (GstValidatePadMonitor * pad_monitor,
       pad_monitor->check_buffers = TRUE;
     }
   }
+  gst_object_unref (pad);
 
   return pad_monitor->check_buffers;
 }
@@ -1537,7 +1870,7 @@ gst_validate_monitor_find_next_buffer (GstValidatePadMonitor * pad_monitor)
     return;
 
   for (tmp = g_list_last (pad_monitor->all_bufs); tmp; tmp = tmp->prev) {
-    GstBuffer *cbuf = tmp->data;
+    GstBuffer *cbuf = (GstBuffer *) tmp->data;
     GstClockTime ts =
         GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DTS (cbuf)) ? GST_BUFFER_DTS (cbuf)
         : GST_BUFFER_PTS (cbuf);
@@ -1562,35 +1895,113 @@ gst_validate_monitor_find_next_buffer (GstValidatePadMonitor * pad_monitor)
     pad_monitor->current_buf = tmp;
 }
 
+static void
+post_segment_message (GstValidatePadMonitor * pad_monitor, GstPad * pad,
+    const GstSegment * segment, guint32 seqnum)
+{
+  GstValidateMonitor *element_monitor =
+      GST_VALIDATE_MONITOR_GET_PARENT (pad_monitor);
+  GstElement *element;
+  GstStructure *structure;
+  GstMessage *msg;
+
+  if (element_monitor == NULL)
+    return;
+
+  element = gst_validate_monitor_get_element (element_monitor);
+  if (element == NULL)
+    return;
+
+  GST_DEBUG_OBJECT (pad,
+      "Posting application message for seqnum:%" G_GUINT32_FORMAT " %"
+      GST_SEGMENT_FORMAT, seqnum, segment);
+
+  structure =
+      gst_structure_new ("validate-segment", "segment", GST_TYPE_SEGMENT,
+      segment, NULL);
+  msg = gst_message_new_application ((GstObject *) element, structure);
+  gst_message_set_seqnum (msg, seqnum);
+  gst_element_post_message (element, msg);
+
+  gst_object_unref (element);
+
+  return;
+}
+
+/* Checks whether a segment is just an update of another,
+ * That is to say that only the base and offset field differ and all
+ * other fields are identical */
 static gboolean
+is_segment_update (GstSegment * a, const GstSegment * b)
+{
+  /* Note : We never care about the position field, it is only
+   * used for internal usage by elements */
+  if (a->rate == b->rate &&
+      a->applied_rate == b->applied_rate &&
+      a->format == b->format && a->time == b->time) {
+    /* Changes in base/offset are considered updates */
+    /* Updating the end position of a segment is an update */
+    /* Updating the duration of a segment is an update */
+    if (a->rate > 0.0) {
+      if (a->start == b->start)
+        return TRUE;
+    } else {
+      if (a->stop == b->stop)
+        return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+static GstFlowReturn
 gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor *
     pad_monitor, GstObject * parent, GstEvent * event,
     GstPadEventFunction handler)
 {
-  gboolean ret = TRUE;
+  GstFlowReturn ret = GST_FLOW_OK;
   const GstSegment *segment;
   guint32 seqnum = gst_event_get_seqnum (event);
-  GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor);
+  GstPad *pad =
+      GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
+          (pad_monitor)));
 
   gst_validate_pad_monitor_common_event_check (pad_monitor, event);
 
   /* pre checks */
   switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_STREAM_START:
+      /* Buffers following a STREAM_START should have the DISCONT flag set */
+      pad_monitor->pending_buffer_discont = TRUE;
+      break;
     case GST_EVENT_SEGMENT:
+    {
+      GstValidatePadSeekData *seekdata =
+          seek_data_for_seqnum (pad_monitor, seqnum);
+
       /* parse segment data to be used if event is handled */
       gst_event_parse_segment (event, &segment);
 
-      GST_DEBUG_OBJECT (pad_monitor->pad, "Got segment %" GST_SEGMENT_FORMAT,
-          segment);
-
-      if (pad_monitor->pending_newsegment_seqnum) {
-        if (pad_monitor->pending_newsegment_seqnum == seqnum) {
-          pad_monitor->pending_newsegment_seqnum = 0;
-        } else {
-          GST_VALIDATE_REPORT (pad_monitor, EVENT_HAS_WRONG_SEQNUM,
-              "The expected segment seqnum should be the same as the "
-              "one from the seek that caused it. Got: %u."
-              " Expected: %u", seqnum, pad_monitor->pending_eos_seqnum);
+      GST_DEBUG_OBJECT (pad,
+          "Got segment seqnum:%" G_GUINT32_FORMAT " %" GST_SEGMENT_FORMAT,
+          seqnum, segment);
+
+      if (pad_monitor->pending_newsegment_seqnum != GST_SEQNUM_INVALID) {
+        /* FIXME: Convert to more robust checks */
+        if (pad_monitor->pending_newsegment_seqnum != seqnum) {
+          GST_VALIDATE_REPORT (pad_monitor, SEGMENT_HAS_WRONG_SEQNUM,
+              "Got: %u Expected: %u", seqnum,
+              pad_monitor->pending_newsegment_seqnum);
+        }
+      }
+
+      if (seekdata && seekdata != pad_monitor->current_seek) {
+        /* Check for accurate seeks */
+        if (seekdata->flags & GST_SEEK_FLAG_ACCURATE) {
+          if (segment->time != seekdata->start)
+            GST_VALIDATE_REPORT (pad_monitor, SEGMENT_HAS_WRONG_START,
+                "After an accurate seek, got: %" GST_TIME_FORMAT
+                " Expected: %" GST_TIME_FORMAT, GST_TIME_ARGS (segment->time),
+                GST_TIME_ARGS (seekdata->start));
         }
       }
 
@@ -1608,18 +2019,44 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor *
                 &exp_segment);
             if (segment->format == exp_segment->format) {
               if ((exp_segment->rate * exp_segment->applied_rate !=
-                      segment->rate * segment->applied_rate)
-                  || exp_segment->start != segment->start
-                  || exp_segment->stop != segment->stop
-                  || exp_segment->position != segment->position) {
+                      segment->rate * segment->applied_rate))
+                GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH,
+                    "Rate * applied_rate %f != expected %f",
+                    segment->rate * segment->applied_rate,
+                    exp_segment->rate * exp_segment->applied_rate);
+              if (exp_segment->start != segment->start)
+                GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH,
+                    "Start %" GST_TIME_FORMAT " != expected %" GST_TIME_FORMAT,
+                    GST_TIME_ARGS (segment->start),
+                    GST_TIME_ARGS (exp_segment->start));
+              if (exp_segment->stop != segment->stop)
+                GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH,
+                    "Stop %" GST_TIME_FORMAT " != expected %" GST_TIME_FORMAT,
+                    GST_TIME_ARGS (segment->stop),
+                    GST_TIME_ARGS (exp_segment->stop));
+              if (exp_segment->position != segment->position)
                 GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH,
-                    "Expected segment didn't match received segment event");
-              }
+                    "Position %" GST_TIME_FORMAT " != expected %"
+                    GST_TIME_FORMAT, GST_TIME_ARGS (segment->position),
+                    GST_TIME_ARGS (exp_segment->position));
             }
           }
           gst_event_replace (&pad_monitor->expected_segment, NULL);
         }
       }
+
+      /* Drop all expected seekdata from before this segment */
+      if (seekdata) {
+        while (pad_monitor->seeks && pad_monitor->seeks->data != seekdata) {
+          GstValidatePadSeekData *tmp =
+              (GstValidatePadSeekData *) pad_monitor->seeks->data;
+          pad_monitor->seeks =
+              g_list_delete_link (pad_monitor->seeks, pad_monitor->seeks);
+          seek_data_free (tmp);
+        }
+      }
+      pad_monitor->current_seek = seekdata;
+    }
       break;
     case GST_EVENT_CAPS:{
       GstCaps *caps;
@@ -1630,15 +2067,14 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor *
     }
     case GST_EVENT_EOS:
       pad_monitor->is_eos = TRUE;
-      if (pad_monitor->pending_eos_seqnum == 0) {
+      /* FIXME : This feels and looks wrong ... */
+      if (pad_monitor->pending_eos_seqnum == GST_SEQNUM_INVALID) {
         GST_VALIDATE_REPORT (pad_monitor, EVENT_EOS_WITHOUT_SEGMENT,
             "EOS %" GST_PTR_FORMAT " received before a segment was received",
             event);
       } else if (pad_monitor->pending_eos_seqnum != seqnum) {
-        GST_VALIDATE_REPORT (pad_monitor, EVENT_HAS_WRONG_SEQNUM,
-            "The expected EOS seqnum should be the same as the "
-            "one from the seek that caused it. Got: %u."
-            " Expected: %u", seqnum, pad_monitor->pending_eos_seqnum);
+        GST_VALIDATE_REPORT (pad_monitor, EOS_HAS_WRONG_SEQNUM,
+            "Got: %u. Expected: %u", seqnum, pad_monitor->pending_eos_seqnum);
       }
 
       /*
@@ -1663,7 +2099,12 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor *
   gst_validate_pad_monitor_event_overrides (pad_monitor, event);
   if (handler) {
     gst_event_ref (event);
-    ret = pad_monitor->event_func (pad, parent, event);
+    if (pad_monitor->event_full_func)
+      ret = pad_monitor->event_full_func (pad, parent, event);
+    else if (pad_monitor->event_func (pad, parent, event))
+      ret = GST_FLOW_OK;
+    else
+      ret = GST_FLOW_ERROR;
   }
   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
@@ -1671,7 +2112,11 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor *
   /* post checks */
   switch (GST_EVENT_TYPE (event)) {
     case GST_EVENT_SEGMENT:
-      if (ret) {
+      if (ret == GST_FLOW_OK) {
+        /* If the new segment is not an update of the previous one, then
+         * the following buffer should have the DISCONT flag set */
+        if (!is_segment_update (&pad_monitor->segment, segment))
+          pad_monitor->pending_buffer_discont = TRUE;
         if (!pad_monitor->has_segment
             && pad_monitor->segment.format != segment->format) {
           gst_segment_init (&pad_monitor->segment, segment->format);
@@ -1679,13 +2124,16 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor *
         gst_segment_copy_into (segment, &pad_monitor->segment);
         pad_monitor->has_segment = TRUE;
         gst_validate_monitor_find_next_buffer (pad_monitor);
+        if (PAD_PARENT_IS_SINK (pad_monitor))
+          post_segment_message (pad_monitor, pad, segment, seqnum);
       }
       break;
     case GST_EVENT_CAPS:{
       GstCaps *caps;
 
       gst_event_parse_caps (event, &caps);
-      gst_validate_pad_monitor_setcaps_post (pad_monitor, caps, ret);
+      gst_validate_pad_monitor_setcaps_post (pad_monitor, caps,
+          ret == GST_FLOW_OK);
       break;
     }
     case GST_EVENT_FLUSH_START:
@@ -1699,84 +2147,57 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor *
 
   if (handler)
     gst_event_unref (event);
+  gst_object_unref (pad);
   return ret;
 }
 
+static GstValidatePadSeekData *
+_store_seek_event_data (GstValidatePadMonitor * pad_monitor, GstEvent * event)
+{
+  GstValidatePadSeekData *data = g_slice_new0 (GstValidatePadSeekData);
+
+  data->seqnum = gst_event_get_seqnum (event);
+  gst_event_parse_seek (event, &data->rate, &data->format, &data->flags,
+      &data->start_type, &data->start, &data->stop_type, &data->stop);
+
+  pad_monitor->seeks = g_list_append (pad_monitor->seeks, data);
+
+  return data;
+}
+
 static gboolean
 gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor,
     GstObject * parent, GstEvent * event, GstPadEventFunction handler)
 {
   gboolean ret = TRUE;
-  gdouble rate;
-  GstFormat format;
-  gint64 start, stop;
-  GstSeekFlags seek_flags;
-  GstSeekType start_type, stop_type;
-  guint32 seqnum = gst_event_get_seqnum (event);
-  GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor);
+  GstPad *pad =
+      GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
+          (pad_monitor)));
 
   gst_validate_pad_monitor_common_event_check (pad_monitor, event);
 
-  /* pre checks */
-  switch (GST_EVENT_TYPE (event)) {
-    case GST_EVENT_SEEK:
-    {
-      gst_event_parse_seek (event, &rate, &format, &seek_flags, &start_type,
-          &start, &stop_type, &stop);
-      /* upstream seek - store the seek event seqnum to check
-       * flushes and newsegments share the same */
-
-      /* TODO we might need to use a list as multiple seeks can be sent
-       * before the flushes arrive here */
-      if (seek_flags & GST_SEEK_FLAG_FLUSH) {
-        pad_monitor->pending_flush_start_seqnum = seqnum;
-        pad_monitor->pending_flush_stop_seqnum = seqnum;
-      }
-    }
-      break;
-      /* both flushes are handled by the common event handling function */
-    case GST_EVENT_FLUSH_START:
-    case GST_EVENT_FLUSH_STOP:
-    case GST_EVENT_NAVIGATION:
-    case GST_EVENT_LATENCY:
-    case GST_EVENT_STEP:
-    case GST_EVENT_QOS:
-    default:
-      break;
-  }
-
   if (handler) {
+    GstValidatePadSeekData *seekdata = NULL;
+
+    GST_DEBUG_OBJECT (pad, "event %" GST_PTR_FORMAT, event);
+
+    /* Safely store pending accurate seek values */
+    if (GST_EVENT_TYPE (event) == GST_EVENT_SEEK)
+      seekdata = _store_seek_event_data (pad_monitor, event);
     GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
-    gst_event_ref (event);
     ret = pad_monitor->event_func (pad, parent, event);
+
     GST_VALIDATE_MONITOR_LOCK (pad_monitor);
-  }
 
-  /* post checks */
-  switch (GST_EVENT_TYPE (event)) {
-    case GST_EVENT_FLUSH_START:
-    case GST_EVENT_FLUSH_STOP:
-    case GST_EVENT_QOS:
-    case GST_EVENT_SEEK:
-    {
-      if (ret == FALSE) {
-        /* do not expect any of these events anymore */
-        pad_monitor->pending_flush_start_seqnum = 0;
-        pad_monitor->pending_flush_stop_seqnum = 0;
-        pad_monitor->pending_newsegment_seqnum = 0;
-        pad_monitor->pending_eos_seqnum = 0;
-      }
+    if (seekdata && !ret) {
+      /* Remove failed seek from list */
+      GST_LOG_OBJECT (pad, "Failed seek, removing stored seek data");
+      pad_monitor->seeks = g_list_remove (pad_monitor->seeks, seekdata);
+      g_slice_free (GstValidatePadSeekData, seekdata);
     }
-      break;
-    case GST_EVENT_NAVIGATION:
-    case GST_EVENT_LATENCY:
-    case GST_EVENT_STEP:
-    default:
-      break;
   }
 
-  if (handler)
-    gst_event_unref (event);
+  gst_object_unref (pad);
   return ret;
 }
 
@@ -1789,13 +2210,18 @@ gst_validate_pad_monitor_check_right_buffer (GstValidatePadMonitor *
   GstMapInfo map, wanted_map;
 
   gboolean ret = TRUE;
-  GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor);
+  GstPad *pad;
+
 
   if (_should_check_buffers (pad_monitor, FALSE) == FALSE)
     return FALSE;
 
+  pad =
+      GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
+          (pad_monitor)));
   if (pad_monitor->current_buf == NULL) {
     GST_INFO_OBJECT (pad, "No current buffer one pad, Why?");
+    gst_object_unref (pad);
     return FALSE;
   }
 
@@ -1806,9 +2232,10 @@ gst_validate_pad_monitor_check_right_buffer (GstValidatePadMonitor *
       GST_BUFFER_PTS (wanted_buf) != GST_BUFFER_PTS (buffer)) {
 
     GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER,
-        "buffer %" GST_PTR_FORMAT " PTS %ld"
-        " different than expected: %ld", buffer,
-        GST_BUFFER_PTS (buffer), GST_BUFFER_PTS (wanted_buf));
+        "buffer %" GST_PTR_FORMAT " PTS %" GST_TIME_FORMAT
+        " different than expected: %" GST_TIME_FORMAT, buffer,
+        GST_TIME_ARGS (GST_BUFFER_PTS (buffer)),
+        GST_TIME_ARGS (GST_BUFFER_PTS (wanted_buf)));
 
     ret = FALSE;
   }
@@ -1858,23 +2285,52 @@ gst_validate_pad_monitor_check_right_buffer (GstValidatePadMonitor *
   gst_buffer_unmap (wanted_buf, &wanted_map);
   gst_buffer_unmap (buffer, &map);
   g_free (checksum);
+  gst_object_unref (pad);
 
   pad_monitor->current_buf = pad_monitor->current_buf->next;
 
   return ret;
 }
 
+static void
+gst_validate_pad_monitor_check_return (GstValidatePadMonitor * pad_monitor,
+    GstFlowReturn ret)
+{
+  GstValidateMonitor *parent = GST_VALIDATE_MONITOR (pad_monitor);
+
+  if (ret != GST_FLOW_ERROR)
+    return;
+
+  while (GST_VALIDATE_MONITOR_GET_PARENT (parent))
+    parent = GST_VALIDATE_MONITOR_GET_PARENT (parent);
+
+  if (GST_IS_VALIDATE_PIPELINE_MONITOR (parent)) {
+    GstValidatePipelineMonitor *m = GST_VALIDATE_PIPELINE_MONITOR (parent);
+
+    GST_VALIDATE_MONITOR_LOCK (m);
+    if (m->got_error == FALSE) {
+      GST_VALIDATE_REPORT (pad_monitor, FLOW_ERROR_WITHOUT_ERROR_MESSAGE,
+          "Pad return GST_FLOW_ERROR but no GST_MESSAGE_ERROR was received on"
+          " the bus");
+
+      /* Only report it the first time */
+      m->got_error = TRUE;
+    }
+    GST_VALIDATE_MONITOR_UNLOCK (m);
+  }
+}
+
 static GstFlowReturn
 gst_validate_pad_monitor_chain_func (GstPad * pad, GstObject * parent,
     GstBuffer * buffer)
 {
-  GstValidatePadMonitor *pad_monitor =
-      g_object_get_data ((GObject *) pad, "validate-monitor");
+  GstValidatePadMonitor *pad_monitor = _GET_PAD_MONITOR (pad);
   GstFlowReturn ret;
 
   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
 
+  gst_validate_pad_monitor_check_discont (pad_monitor, buffer);
   gst_validate_pad_monitor_check_right_buffer (pad_monitor, buffer);
   gst_validate_pad_monitor_check_first_buffer (pad_monitor, buffer);
   gst_validate_pad_monitor_update_buffer_data (pad_monitor, buffer);
@@ -1887,15 +2343,16 @@ gst_validate_pad_monitor_chain_func (GstPad * pad, GstObject * parent,
 
   ret = pad_monitor->chain_func (pad, parent, buffer);
 
+  gst_validate_pad_monitor_check_return (pad_monitor, ret);
+
   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
 
-  pad_monitor->last_flow_return = ret;
   if (ret == GST_FLOW_EOS) {
     mark_pads_eos (pad_monitor);
   }
   if (PAD_PARENT_IS_DEMUXER (pad_monitor))
-    gst_validate_pad_monitor_check_aggregated_return (pad_monitor, ret);
+    gst_validate_pad_monitor_check_aggregated_return (pad_monitor, parent, ret);
 
   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
@@ -1924,17 +2381,18 @@ gst_validate_pad_monitor_event_is_tracked (GstValidatePadMonitor * monitor,
   return TRUE;
 }
 
-static gboolean
-gst_validate_pad_monitor_sink_event_func (GstPad * pad, GstObject * parent,
+static GstFlowReturn
+gst_validate_pad_monitor_sink_event_full_func (GstPad * pad, GstObject * parent,
     GstEvent * event)
 {
-  GstValidatePadMonitor *pad_monitor =
-      g_object_get_data ((GObject *) pad, "validate-monitor");
-  gboolean ret;
+  GstValidatePadMonitor *pad_monitor = _GET_PAD_MONITOR (pad);
+  GstFlowReturn ret;
 
   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
 
+  GST_DEBUG_OBJECT (pad, "event %p %s", event, GST_EVENT_TYPE_NAME (event));
+
   if (gst_validate_pad_monitor_event_is_tracked (pad_monitor, event)) {
     GstClockTime last_ts = GST_CLOCK_TIME_NONE;
     if (GST_CLOCK_TIME_IS_VALID (pad_monitor->current_timestamp)) {
@@ -1957,11 +2415,20 @@ gst_validate_pad_monitor_sink_event_func (GstPad * pad, GstObject * parent,
 }
 
 static gboolean
+gst_validate_pad_monitor_sink_event_func (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  if (gst_validate_pad_monitor_sink_event_full_func (pad, parent,
+          event) == GST_FLOW_OK)
+    return TRUE;
+  return FALSE;
+}
+
+static gboolean
 gst_validate_pad_monitor_src_event_func (GstPad * pad, GstObject * parent,
     GstEvent * event)
 {
-  GstValidatePadMonitor *pad_monitor =
-      g_object_get_data ((GObject *) pad, "validate-monitor");
+  GstValidatePadMonitor *pad_monitor = _GET_PAD_MONITOR (pad);
   gboolean ret;
 
   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
@@ -1975,25 +2442,51 @@ static gboolean
 gst_validate_pad_monitor_query_func (GstPad * pad, GstObject * parent,
     GstQuery * query)
 {
-  GstValidatePadMonitor *pad_monitor =
-      g_object_get_data ((GObject *) pad, "validate-monitor");
+  GstValidatePadMonitor *pad_monitor = _GET_PAD_MONITOR (pad);
   gboolean ret;
 
   gst_validate_pad_monitor_query_overrides (pad_monitor, query);
-
   ret = pad_monitor->query_func (pad, parent, query);
 
   if (ret) {
     switch (GST_QUERY_TYPE (query)) {
+      case GST_QUERY_ACCEPT_CAPS:
+      {
+        gboolean result;
+
+        gst_caps_replace (&pad_monitor->last_refused_caps, NULL);
+        gst_query_parse_accept_caps_result (query, &result);
+        if (!result) {
+          GstCaps *refused_caps;
+
+          gst_query_parse_accept_caps (query, &refused_caps);
+          pad_monitor->last_refused_caps = gst_caps_copy (refused_caps);
+
+        }
+
+        break;
+      }
       case GST_QUERY_CAPS:{
         GstCaps *res;
+        GstCaps *filter;
+
         /* We shouldn't need to lock the parent as this doesn't modify
          * other monitors, just does some peer_pad_caps */
         GST_VALIDATE_MONITOR_LOCK (pad_monitor);
 
+        gst_query_parse_caps (query, &filter);
         gst_query_parse_caps_result (query, &res);
+
+        gst_caps_replace (&pad_monitor->last_query_res, NULL);
+        gst_caps_replace (&pad_monitor->last_query_filter, NULL);
+        pad_monitor->last_query_res =
+            res ? gst_caps_copy (res) : gst_caps_ref (GST_CAPS_NONE);
+        pad_monitor->last_query_filter =
+            filter ? gst_caps_copy (filter) : gst_caps_ref (GST_CAPS_NONE);
+
         if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
-          gst_validate_pad_monitor_check_caps_fields_proxied (pad_monitor, res);
+          gst_validate_pad_monitor_check_caps_fields_proxied (pad_monitor, res,
+              filter);
         }
         GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
         break;
@@ -2010,43 +2503,128 @@ static gboolean
 gst_validate_pad_monitor_activatemode_func (GstPad * pad, GstObject * parent,
     GstPadMode mode, gboolean active)
 {
-  GstValidatePadMonitor *pad_monitor =
-      g_object_get_data ((GObject *) pad, "validate-monitor");
+  GstValidatePadMonitor *pad_monitor = _GET_PAD_MONITOR (pad);
   gboolean ret = TRUE;
 
   /* TODO add overrides for activate func */
+  GST_DEBUG_OBJECT (pad, "active:%d", active);
 
   if (pad_monitor->activatemode_func)
     ret = pad_monitor->activatemode_func (pad, parent, mode, active);
   if (ret && active == FALSE) {
     GST_VALIDATE_MONITOR_LOCK (pad_monitor);
-    gst_validate_pad_monitor_flush (pad_monitor);
+    gst_validate_pad_monitor_reset (pad_monitor);
     GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
   }
 
   return ret;
 }
 
-static gboolean
-gst_validate_pad_get_range_func (GstPad * pad, GstObject * parent,
-    guint64 offset, guint size, GstBuffer ** buffer)
+static GstFlowReturn
+gst_validate_pad_monitor_get_range_func (GstPad * pad, GstObject * parent,
+    guint64 offset, guint length, GstBuffer ** buffer)
+{
+  GstValidatePadMonitor *pad_monitor = _GET_PAD_MONITOR (pad);
+
+  if (pad_monitor->get_range_func) {
+    GstPad *peer = gst_pad_get_peer (pad);
+    GstTask *task = NULL;
+    GThread *thread = NULL;
+
+    if (peer) {
+      GST_OBJECT_LOCK (peer);
+      task = GST_PAD_TASK (peer);
+      if (task && GST_TASK_STATE (task) == GST_TASK_STARTED) {
+        GST_OBJECT_LOCK (task);
+        /* Only doing pointer comparison, no need to hold a ref */
+        thread = task->thread;
+        GST_OBJECT_UNLOCK (task);
+      }
+      GST_OBJECT_UNLOCK (peer);
+
+      if (thread && thread != g_thread_self ()) {
+        GST_VALIDATE_REPORT (pad_monitor, PULL_RANGE_FROM_WRONG_THREAD,
+            "Pulling from wrong thread, expected pad thread: %p, got %p",
+            task->thread, g_thread_self ());
+      }
+
+      gst_object_unref (peer);
+    }
+
+    return pad_monitor->get_range_func (pad, parent, offset, length, buffer);
+  }
+
+  return GST_FLOW_NOT_SUPPORTED;
+
+}
+
+/* The interval between two buffer frequency checks */
+#define BUF_FREQ_CHECK_INTERVAL (GST_SECOND)
+
+static void
+gst_validate_pad_monitor_check_buffer_freq (GstValidatePadMonitor * monitor,
+    GstPad * pad)
 {
-  GstValidatePadMonitor *pad_monitor =
-      g_object_get_data ((GObject *) pad, "validate-monitor");
-  gboolean ret;
-  ret = pad_monitor->getrange_func (pad, parent, offset, size, buffer);
-  return ret;
+  GstClockTime ts;
+
+  if (!GST_PAD_IS_SRC (pad))
+    return;
+
+  if (!monitor->min_buf_freq)
+    return;
+
+  ts = gst_util_get_timestamp ();
+  monitor->buffers_pushed++;
+
+  /* Same logic as in fpsdisplaysink to compute the buffer frequency */
+  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID
+          (monitor->min_buf_freq_first_buffer_ts))) {
+    monitor->min_buf_freq_first_buffer_ts = ts;
+    monitor->min_buf_freq_interval_ts = ts;
+    return;
+  }
+
+  if (GST_CLOCK_DIFF (monitor->min_buf_freq_interval_ts,
+          ts) > BUF_FREQ_CHECK_INTERVAL) {
+    guint time_diff;
+    gdouble fps;
+
+    time_diff = (gdouble) (ts - monitor->min_buf_freq_interval_ts) / GST_SECOND;
+    fps =
+        (gdouble) (monitor->buffers_pushed -
+        monitor->last_buffers_pushed) / time_diff;
+
+    if (fps < monitor->min_buf_freq) {
+      if (GST_CLOCK_TIME_IS_VALID (monitor->min_buf_freq_start) &&
+          GST_CLOCK_DIFF (monitor->min_buf_freq_first_buffer_ts,
+              ts) < monitor->min_buf_freq_start) {
+        GST_DEBUG_OBJECT (pad,
+            "buffer frequency is too low (%.2f) but ignore for now (buffer-frequency-start =%"
+            GST_TIME_FORMAT ")", fps,
+            GST_TIME_ARGS (monitor->min_buf_freq_start));
+      } else {
+        GST_VALIDATE_REPORT (monitor, CONFIG_BUFFER_FREQUENCY_TOO_LOW,
+            "Buffers are not pushed fast enough on this pad: %.2f/sec (minimum: %.2f)",
+            fps, monitor->min_buf_freq);
+      }
+    }
+
+    monitor->last_buffers_pushed = monitor->buffers_pushed;
+    monitor->min_buf_freq_interval_ts = ts;
+  }
 }
 
 static gboolean
 gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer,
-    gpointer udata)
+    gpointer udata, gboolean pull_mode)
 {
   GstValidatePadMonitor *monitor = udata;
 
   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor);
   GST_VALIDATE_MONITOR_LOCK (monitor);
 
+  if (!pull_mode)
+    gst_validate_pad_monitor_check_discont (monitor, buffer);
   gst_validate_pad_monitor_check_first_buffer (monitor, buffer);
   gst_validate_pad_monitor_update_buffer_data (monitor, buffer);
   gst_validate_pad_monitor_check_eos (monitor, buffer);
@@ -2083,7 +2661,7 @@ gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer,
       /* TODO is this a timestamp issue? */
       GST_VALIDATE_REPORT (monitor, BUFFER_IS_OUT_OF_SEGMENT,
           "buffer is out of segment and shouldn't be pushed. Timestamp: %"
-          GST_TIME_FORMAT " - duration: %" GST_TIME_FORMAT ". Range: %"
+          GST_TIME_FORMAT " - Duration: %" GST_TIME_FORMAT ". Range: %"
           GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
           GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
           GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)),
@@ -2092,23 +2670,26 @@ gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer,
     }
   }
 
+  gst_validate_pad_monitor_check_buffer_freq (monitor, pad);
+
   GST_VALIDATE_MONITOR_UNLOCK (monitor);
   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (monitor);
   gst_validate_pad_monitor_buffer_probe_overrides (monitor, buffer);
   return TRUE;
 }
 
-static gboolean
+static void
 gst_validate_pad_monitor_event_probe (GstPad * pad, GstEvent * event,
     gpointer udata)
 {
   GstValidatePadMonitor *monitor = GST_VALIDATE_PAD_MONITOR_CAST (udata);
-  gboolean ret;
+  guint32 seqnum = gst_event_get_seqnum (event);
 
   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor);
   GST_VALIDATE_MONITOR_LOCK (monitor);
 
-  GST_DEBUG_OBJECT (pad, "event %p %s", event, GST_EVENT_TYPE_NAME (event));
+  GST_DEBUG_OBJECT (pad, "event %p %s seqnum:%" G_GUINT32_FORMAT, event,
+      GST_EVENT_TYPE_NAME (event), seqnum);
 
   if (GST_EVENT_IS_SERIALIZED (event)) {
     gint i;
@@ -2192,13 +2773,9 @@ gst_validate_pad_monitor_event_probe (GstPad * pad, GstEvent * event,
 
   /* This so far is just like an event that is flowing downstream,
    * so we do the same checks as a sinkpad event handler */
-  ret =
-      gst_validate_pad_monitor_downstream_event_check (monitor, NULL, event,
-      NULL);
+  gst_validate_pad_monitor_downstream_event_check (monitor, NULL, event, NULL);
   GST_VALIDATE_MONITOR_UNLOCK (monitor);
   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (monitor);
-
-  return ret;
 }
 
 static GstPadProbeReturn
@@ -2206,7 +2783,8 @@ gst_validate_pad_monitor_pad_probe (GstPad * pad, GstPadProbeInfo * info,
     gpointer udata)
 {
   if (info->type & GST_PAD_PROBE_TYPE_BUFFER)
-    gst_validate_pad_monitor_buffer_probe (pad, info->data, udata);
+    gst_validate_pad_monitor_buffer_probe (pad, info->data, udata,
+        GST_PAD_PROBE_INFO_TYPE (info) & GST_PAD_PROBE_TYPE_PULL);
   else if (info->type & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM)
     gst_validate_pad_monitor_event_probe (pad, info->data, udata);
 
@@ -2244,12 +2822,14 @@ gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor,
     GstCaps * caps)
 {
   GstStructure *structure;
+  GstPad *pad =
+      GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
+          (pad_monitor)));
 
   /* Check if caps are identical to last caps and complain if so
    * Only checked for sink pads as src pads might push the same caps
    * multiple times during unlinked/autoplugging scenarios */
-  if (GST_PAD_IS_SINK (GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor)) &&
-      pad_monitor->last_caps
+  if (GST_PAD_IS_SINK (pad) && pad_monitor->last_caps
       && gst_caps_is_equal (caps, pad_monitor->last_caps)) {
     gchar *caps_str = gst_caps_to_string (caps);
 
@@ -2297,8 +2877,12 @@ gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor,
       }
     }
 
-    if (gst_validate_pad_monitor_pad_should_proxy_othercaps (pad_monitor)) {
+    if (GST_PAD_IS_SINK (pad) &&
+        gst_validate_pad_monitor_pad_should_proxy_othercaps (pad_monitor)) {
       if (_structure_is_video (structure)) {
+        GST_DEBUG_OBJECT (pad,
+            "Adding video common pending fields to other pad: %" GST_PTR_FORMAT,
+            structure);
         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
             structure, "width");
         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
@@ -2308,6 +2892,9 @@ gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor,
         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
             structure, "pixel-aspect-ratio");
       } else if (_structure_is_audio (structure)) {
+        GST_DEBUG_OBJECT (pad,
+            "Adding audio common pending fields to other pad: %" GST_PTR_FORMAT,
+            structure);
         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
             structure, "rate");
         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
@@ -2319,6 +2906,7 @@ gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor,
   gst_structure_free (pad_monitor->pending_setcaps_fields);
   pad_monitor->pending_setcaps_fields =
       gst_structure_new_empty (PENDING_FIELDS);
+  gst_object_unref (pad);
 
   gst_validate_pad_monitor_setcaps_overrides (pad_monitor, caps);
 }
@@ -2338,44 +2926,95 @@ gst_validate_pad_monitor_setcaps_post (GstValidatePadMonitor * pad_monitor,
   }
 }
 
+static void
+gst_validate_pad_monitor_get_min_buffer_frequency (GstValidatePadMonitor *
+    monitor, GstPad * pad)
+{
+  GList *config, *l;
+
+  if (!GST_PAD_IS_SRC (pad))
+    return;
+
+  config = gst_validate_plugin_get_config (NULL);
+  for (l = config; l != NULL; l = g_list_next (l)) {
+    GstStructure *s = l->data;
+    gdouble min_buf_freq;
+    const gchar *pad_name;
+    GstElement *element = NULL;
+
+    if (!gst_structure_get_double (s, "min-buffer-frequency", &min_buf_freq)) {
+      gint max_int;
+
+      if (!gst_structure_get_int (s, "min-buffer-frequency", &max_int))
+        goto next;
+
+      min_buf_freq = max_int;
+    }
+
+    pad_name = gst_structure_get_string (s, "name");
+    if (!pad_name)
+      pad_name = "src";
+
+    if (g_strcmp0 (GST_PAD_NAME (pad), pad_name))
+      goto next;
+
+    element = gst_pad_get_parent_element (pad);
+
+    if (!gst_validate_element_matches_target (element, s))
+      goto next;
+
+    monitor->min_buf_freq = min_buf_freq;
+
+    gst_validate_utils_get_clocktime (s, "buffer-frequency-start",
+        &monitor->min_buf_freq_start);
+
+    GST_DEBUG_OBJECT (pad, "pad has a minimum buffer frequency of %f",
+        min_buf_freq);
+  next:
+    g_clear_object (&element);
+  }
+}
+
 static gboolean
 gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor)
 {
   GstValidatePadMonitor *pad_monitor = GST_VALIDATE_PAD_MONITOR_CAST (monitor);
-  GstPad *pad;
-  if (!GST_IS_PAD (GST_VALIDATE_MONITOR_GET_OBJECT (monitor))) {
+  GstPad *pad = (gpointer) gst_validate_monitor_get_target (monitor);
+
+  if (!GST_IS_PAD (pad)) {
     GST_WARNING_OBJECT (monitor, "Trying to create pad monitor with other "
         "type of object");
+    gst_object_unref (pad);
     return FALSE;
   }
 
-  pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor);
-
-  if (g_object_get_data ((GObject *) pad, "validate-monitor")) {
+  if (_GET_PAD_MONITOR (pad)) {
     GST_WARNING_OBJECT (pad_monitor,
         "Pad already has a validate-monitor associated");
+    gst_object_unref (pad);
     return FALSE;
   }
 
-  g_object_set_data ((GObject *) pad, "validate-monitor", pad_monitor);
-
-  pad_monitor->pad = pad;
+  _SET_PAD_MONITOR (pad, pad_monitor);
 
   pad_monitor->event_func = GST_PAD_EVENTFUNC (pad);
+  pad_monitor->event_full_func = GST_PAD_EVENTFULLFUNC (pad);
   pad_monitor->query_func = GST_PAD_QUERYFUNC (pad);
   pad_monitor->activatemode_func = GST_PAD_ACTIVATEMODEFUNC (pad);
+  pad_monitor->get_range_func = GST_PAD_GETRANGEFUNC (pad);
   if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
 
     pad_monitor->chain_func = GST_PAD_CHAINFUNC (pad);
     if (pad_monitor->chain_func)
       gst_pad_set_chain_function (pad, gst_validate_pad_monitor_chain_func);
 
-    gst_pad_set_event_function (pad, gst_validate_pad_monitor_sink_event_func);
+    if (pad_monitor->event_full_func)
+      gst_pad_set_event_full_function (pad,
+          gst_validate_pad_monitor_sink_event_full_func);
+    else
+      gst_pad_set_event_function (pad,
+          gst_validate_pad_monitor_sink_event_func);
   } else {
-    pad_monitor->getrange_func = GST_PAD_GETRANGEFUNC (pad);
-    if (pad_monitor->getrange_func)
-      gst_pad_set_getrange_function (pad, gst_validate_pad_get_range_func);
-
     gst_pad_set_event_function (pad, gst_validate_pad_monitor_src_event_func);
 
     /* add buffer/event probes */
@@ -2390,11 +3029,19 @@ gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor)
   gst_pad_set_activatemode_function (pad,
       gst_validate_pad_monitor_activatemode_func);
 
+  if (GST_PAD_IS_SRC (pad)) {
+    gst_pad_set_getrange_function (pad,
+        gst_validate_pad_monitor_get_range_func);
+  }
+
   gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (monitor),
       g_strdup_printf ("%s:%s", GST_DEBUG_PAD_NAME (pad)));
 
   if (G_UNLIKELY (GST_PAD_PARENT (pad) == NULL))
     GST_FIXME ("Saw a pad not belonging to any object");
 
+  gst_validate_pad_monitor_get_min_buffer_frequency (pad_monitor, pad);
+
+  gst_object_unref (pad);
   return TRUE;
 }