Merging gst-devtools
[platform/upstream/gstreamer.git] / validate / gst / validate / gst-validate-pad-monitor.c
index 1985d7d..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;
@@ -875,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);
@@ -898,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);
 }
@@ -946,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;
 }
@@ -967,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);
@@ -1346,7 +1386,6 @@ gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor *
   GstPad *otherpad;
   GstPad *peerpad;
   GstState state, pending;
-  GstValidatePadMonitor *othermonitor;
   GstFlowReturn aggregated = GST_FLOW_NOT_LINKED;
   gboolean found_a_pad = FALSE;
   GstPad *pad =
@@ -1362,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);
         }
@@ -1684,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");
+          }
         }
       }
 
@@ -1699,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;
@@ -1851,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 */
@@ -1897,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));
         }
       }
 
@@ -1964,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;
@@ -2031,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:{
@@ -2056,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 && format == GST_FORMAT_TIME) {
-        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;
 }
@@ -2301,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);
   }
@@ -2488,7 +2534,7 @@ gst_validate_pad_monitor_get_range_func (GstPad * pad, GstObject * parent,
     if (peer) {
       GST_OBJECT_LOCK (peer);
       task = GST_PAD_TASK (peer);
-      if (task) {
+      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;
@@ -2637,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;