Merging gst-devtools
[platform/upstream/gstreamer.git] / validate / gst / validate / gst-validate-pad-monitor.c
index 2f5ff21..7cf92fc 100644 (file)
@@ -82,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
@@ -120,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;
@@ -129,21 +146,25 @@ typedef struct
 static GstPad *
 _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;
@@ -871,6 +892,26 @@ gst_validate_pad_monitor_check_late_serialized_events (GstValidatePadMonitor *
 }
 
 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);
@@ -894,6 +935,9 @@ gst_validate_pad_monitor_dispose (GObject * object)
   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);
 }
@@ -942,8 +986,6 @@ 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->last_flow_return = GST_FLOW_OK;
-
   pad_monitor->timestamp_range_start = GST_CLOCK_TIME_NONE;
   pad_monitor->timestamp_range_end = GST_CLOCK_TIME_NONE;
 }
@@ -955,7 +997,7 @@ gst_validate_pad_monitor_reset (GstValidatePadMonitor * pad_monitor)
 {
   gst_validate_pad_monitor_flush (pad_monitor);
 
-  /* Note : For the entries that haven't been resetted in _flush(), do
+  /* Note : For the entries that haven't been reset in _flush(), do
    * it here and keep in the same order as the GstValidatePadMonitor
    * structure */
 
@@ -963,12 +1005,14 @@ gst_validate_pad_monitor_reset (GstValidatePadMonitor * pad_monitor)
   pad_monitor->pending_newsegment_seqnum = GST_SEQNUM_INVALID;
   pad_monitor->pending_eos_seqnum = GST_SEQNUM_INVALID;
 
-  pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE;
-
   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);
@@ -1184,6 +1228,9 @@ static void
         GST_DEBUG_OBJECT (pad, "Checking pad %s:%s input timestamps",
             GST_DEBUG_PAD_NAME (otherpad));
         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)
@@ -1338,7 +1385,7 @@ gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor *
   gboolean done;
   GstPad *otherpad;
   GstPad *peerpad;
-  GstValidatePadMonitor *othermonitor;
+  GstState state, pending;
   GstFlowReturn aggregated = GST_FLOW_NOT_LINKED;
   gboolean found_a_pad = FALSE;
   GstPad *pad =
@@ -1354,14 +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 = _GET_PAD_MONITOR (peerpad);
-          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);
         }
@@ -1384,8 +1427,17 @@ gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor *
     /* no peer pad found, nothing to do */
     goto done;
   }
-  if (aggregated == GST_FLOW_OK || aggregated == GST_FLOW_EOS) {
-    GstState state, pending;
+
+  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) {
@@ -1620,9 +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 = _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);
@@ -1659,13 +1719,19 @@ gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor *
   switch (GST_EVENT_TYPE (event)) {
     case GST_EVENT_FLUSH_START:
     {
-      if (pad_monitor->pending_flush_start_seqnum != GST_SEQNUM_INVALID) {
-        if (seqnum == pad_monitor->pending_flush_start_seqnum) {
-          pad_monitor->pending_flush_start_seqnum = GST_SEQNUM_INVALID;
-        } else {
+      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: %u Expected: %u", seqnum,
-              pad_monitor->pending_flush_start_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");
+          }
         }
       }
 
@@ -1674,18 +1740,21 @@ gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor *
             "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 != GST_SEQNUM_INVALID) {
-        if (seqnum == pad_monitor->pending_flush_stop_seqnum) {
-          pad_monitor->pending_flush_stop_seqnum = GST_SEQNUM_INVALID;
-        } else {
-          GST_VALIDATE_REPORT (pad_monitor, FLUSH_STOP_HAS_WRONG_SEQNUM,
-              "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;
@@ -1826,6 +1895,39 @@ 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 */
@@ -1872,31 +1974,34 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor *
       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, "Got segment %" GST_SEGMENT_FORMAT, segment);
-
-      /* Reset expected flush start/stop values, we have a segment */
-      pad_monitor->pending_flush_start_seqnum = GST_SEQNUM_INVALID;
-      pad_monitor->pending_flush_stop_seqnum = GST_SEQNUM_INVALID;
+      GST_DEBUG_OBJECT (pad,
+          "Got segment seqnum:%" G_GUINT32_FORMAT " %" GST_SEGMENT_FORMAT,
+          seqnum, segment);
 
       if (pad_monitor->pending_newsegment_seqnum != GST_SEQNUM_INVALID) {
-        if (pad_monitor->pending_newsegment_seqnum == seqnum) {
-          pad_monitor->pending_newsegment_seqnum = GST_SEQNUM_INVALID;
-          if (GST_CLOCK_TIME_IS_VALID (pad_monitor->pending_seek_accurate_time)) {
-            if (segment->time == pad_monitor->pending_seek_accurate_time) {
-              pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE;
-            } else {
-              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 (pad_monitor->pending_seek_accurate_time));
-            }
-          }
-        } else {
+        /* 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_eos_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));
         }
       }
 
@@ -1939,6 +2044,19 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor *
           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;
@@ -2006,6 +2124,8 @@ 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:{
@@ -2031,100 +2151,52 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor *
   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_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 */
-    }
-      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) {
-    GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
-    /* Safely store pending accurate seek values */
-    if (GST_EVENT_TYPE (event) == GST_EVENT_SEEK) {
-      if (seek_flags & GST_SEEK_FLAG_ACCURATE) {
-        GST_DEBUG_OBJECT (pad,
-            "Storing expected accurate seek time %" GST_TIME_FORMAT,
-            GST_TIME_ARGS (start));
-        pad_monitor->pending_seek_accurate_time = start;
-      }
-      /* 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;
-      }
-    }
+    GstValidatePadSeekData *seekdata = NULL;
 
-    gst_event_ref (event);
+    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);
     ret = pad_monitor->event_func (pad, parent, event);
 
-    if (GST_EVENT_TYPE (event) == GST_EVENT_SEEK) {
-      /* If the seek was already handled (same current seqnum), reset the
-       * expected accurate seek value */
-      if (ret && pad_monitor->has_segment
-          && seqnum == pad_monitor->pending_eos_seqnum) {
-        GST_DEBUG_OBJECT (pad,
-            "Resetting expected accurate seek value, was already handled");
-        pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE;
-      } else if (!ret) {
-        /* do not expect any of these events anymore */
-        pad_monitor->pending_flush_start_seqnum = GST_SEQNUM_INVALID;
-        pad_monitor->pending_flush_stop_seqnum = GST_SEQNUM_INVALID;
-        pad_monitor->pending_newsegment_seqnum = GST_SEQNUM_INVALID;
-        pad_monitor->pending_eos_seqnum = GST_SEQNUM_INVALID;
-        pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE;
-      }
-    }
     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:
-    case GST_EVENT_NAVIGATION:
-    case GST_EVENT_LATENCY:
-    case GST_EVENT_STEP:
-    default:
-      break;
+    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);
+    }
   }
 
-  if (handler)
-    gst_event_unref (event);
   gst_object_unref (pad);
   return ret;
 }
@@ -2276,7 +2348,6 @@ gst_validate_pad_monitor_chain_func (GstPad * pad, GstObject * parent,
   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);
   }
@@ -2449,6 +2520,44 @@ gst_validate_pad_monitor_activatemode_func (GstPad * pad, GstObject * parent,
   return ret;
 }
 
+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)
 
@@ -2574,11 +2683,13 @@ gst_validate_pad_monitor_event_probe (GstPad * pad, GstEvent * event,
     gpointer udata)
 {
   GstValidatePadMonitor *monitor = GST_VALIDATE_PAD_MONITOR_CAST (udata);
+  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;
@@ -2890,6 +3001,7 @@ gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor)
   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);
@@ -2917,6 +3029,11 @@ 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)));