pad-monitor: make debug log more readable
[platform/upstream/gstreamer.git] / validate / gst / validate / gst-validate-pad-monitor.c
1 /* GStreamer
2  *
3  * Copyright (C) 2013 Collabora Ltd.
4  *  Author: Thiago Sousa Santos <thiago.sousa.santos@collabora.com>
5  *
6  * gst-validate-pad-monitor.c - Validate PadMonitor class
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27
28 #include "gst-validate-internal.h"
29 #include "gst-validate-pad-monitor.h"
30 #include "gst-validate-element-monitor.h"
31 #include "gst-validate-reporter.h"
32 #include <string.h>
33 #include <stdarg.h>
34
35 /**
36  * SECTION:gst-validate-pad-monitor
37  * @short_description: Class that wraps a #GstPad for Validate checks
38  *
39  * TODO
40  */
41
42 #define gst_validate_pad_monitor_parent_class parent_class
43 G_DEFINE_TYPE (GstValidatePadMonitor, gst_validate_pad_monitor,
44     GST_TYPE_VALIDATE_MONITOR);
45
46 #define PENDING_FIELDS "pending-fields"
47
48 #define PAD_PARENT_IS_DEMUXER(m) \
49     (GST_VALIDATE_MONITOR_GET_PARENT(m) ? \
50         GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DEMUXER ( \
51             GST_VALIDATE_MONITOR_GET_PARENT(m)) : \
52         FALSE)
53
54 #define PAD_PARENT_IS_DECODER(m) \
55     (GST_VALIDATE_MONITOR_GET_PARENT(m) ? \
56         GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DECODER ( \
57             GST_VALIDATE_MONITOR_GET_PARENT(m)) : \
58         FALSE)
59
60 /*
61  * Locking the parent should always be done before locking the
62  * pad-monitor to prevent deadlocks in case another monitor from
63  * another pad on the same element starts an operation that also
64  * requires locking itself and some other monitors from internally
65  * linked pads.
66  *
67  * An example:
68  * An element has a sink and a src pad. Some test starts running at sinkpad
69  * and it locks the parent, and then it locks itself. In case it needs to get
70  * some information from the srcpad, it is able to lock the srcpad and get it
71  * because the srcpad should never lock itself before locking the parent (which
72  * it won't be able as sinkpad already locked it).
73  *
74  * As a side one, it is possible that srcpad locks itself without locking the
75  * parent in case it wants to do a check that won't need to use other internally
76  * linked pads (sinkpad). But in this case it might lock and unlock freely without
77  * causing deadlocks.
78  */
79 #define GST_VALIDATE_PAD_MONITOR_PARENT_LOCK(m)                  \
80 G_STMT_START {                                             \
81   if (G_LIKELY (GST_VALIDATE_MONITOR_GET_PARENT (m))) {          \
82     GST_VALIDATE_MONITOR_LOCK (GST_VALIDATE_MONITOR_GET_PARENT (m));   \
83   } else {                                                 \
84     GST_WARNING_OBJECT (m, "No parent found, can't lock"); \
85   }                                                        \
86 } G_STMT_END
87
88 #define GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK(m)                  \
89 G_STMT_START {                                               \
90   if (G_LIKELY (GST_VALIDATE_MONITOR_GET_PARENT (m))) {            \
91     GST_VALIDATE_MONITOR_UNLOCK (GST_VALIDATE_MONITOR_GET_PARENT (m));   \
92   } else {                                                   \
93     GST_WARNING_OBJECT (m, "No parent found, can't unlock"); \
94   }                                                          \
95 } G_STMT_END
96
97 typedef struct
98 {
99   GstClockTime timestamp;
100   GstEvent *event;
101 } SerializedEventData;
102
103 static void
104 debug_pending_event (GstPad * pad, GPtrArray * array)
105 {
106   guint i, len;
107
108   len = array->len;
109   for (i = 0; i < len; i++) {
110     SerializedEventData *data = g_ptr_array_index (array, i);
111     GST_DEBUG_OBJECT (pad, "event #%d %" GST_TIME_FORMAT " %s %p",
112         i, GST_TIME_ARGS (data->timestamp),
113         GST_EVENT_TYPE_NAME (data->event), data->event);
114   }
115 }
116
117 static void
118 _serialized_event_data_free (SerializedEventData * serialized_event)
119 {
120   gst_event_unref (serialized_event->event);
121   g_slice_free (SerializedEventData, serialized_event);
122 }
123
124 static gboolean gst_validate_pad_monitor_do_setup (GstValidateMonitor *
125     monitor);
126 static GstElement *gst_validate_pad_monitor_get_element (GstValidateMonitor *
127     monitor);
128 static void
129 gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor,
130     GstCaps * caps);
131 static void gst_validate_pad_monitor_setcaps_post (GstValidatePadMonitor *
132     pad_monitor, GstCaps * caps, gboolean ret);
133
134 #define PAD_IS_IN_PUSH_MODE(p) ((p)->mode == GST_PAD_MODE_PUSH)
135
136 static gboolean
137 _structure_is_raw_video (GstStructure * structure)
138 {
139   return gst_structure_has_name (structure, "video/x-raw");
140 }
141
142 static gboolean
143 _structure_is_raw_audio (GstStructure * structure)
144 {
145   return gst_structure_has_name (structure, "audio/x-raw");
146 }
147
148 static void
149 _check_field_type (GstValidatePadMonitor * monitor, GstStructure * structure,
150     const gchar * field, ...)
151 {
152   va_list var_args;
153   GType type;
154   gchar *joined_types = NULL;
155   const gchar *rejected_types[5];
156   gint rejected_types_index = 0;
157
158   if (!gst_structure_has_field (structure, field)) {
159     GST_VALIDATE_REPORT (monitor, CAPS_IS_MISSING_FIELD,
160         "Field '%s' is missing from structure: %" GST_PTR_FORMAT, field,
161         structure);
162     return;
163   }
164
165   memset (rejected_types, 0, sizeof (rejected_types));
166   va_start (var_args, field);
167   while ((type = va_arg (var_args, GType)) != 0) {
168     if (gst_structure_has_field_typed (structure, field, type)) {
169       va_end (var_args);
170       return;
171     }
172     rejected_types[rejected_types_index++] = g_type_name (type);
173   }
174   va_end (var_args);
175
176   joined_types = g_strjoinv (" / ", (gchar **) rejected_types);
177   GST_VALIDATE_REPORT (monitor, CAPS_FIELD_HAS_BAD_TYPE,
178       "Field '%s' has wrong type %s in structure '%" GST_PTR_FORMAT
179       "'. Expected: %s", field,
180       g_type_name (gst_structure_get_field_type (structure, field)), structure,
181       joined_types);
182   g_free (joined_types);
183 }
184
185 static void
186 gst_validate_pad_monitor_check_raw_video_caps_complete (GstValidatePadMonitor *
187     monitor, GstStructure * structure)
188 {
189   _check_field_type (monitor, structure, "width", G_TYPE_INT,
190       GST_TYPE_INT_RANGE, 0);
191   _check_field_type (monitor, structure, "height", G_TYPE_INT,
192       GST_TYPE_INT_RANGE, 0);
193   _check_field_type (monitor, structure, "framerate", GST_TYPE_FRACTION,
194       GST_TYPE_FRACTION_RANGE, 0);
195   _check_field_type (monitor, structure, "pixel-aspect-ratio",
196       GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE, 0);
197   _check_field_type (monitor, structure, "format", G_TYPE_STRING,
198       GST_TYPE_LIST);
199 }
200
201 static void
202 gst_validate_pad_monitor_check_raw_audio_caps_complete (GstValidatePadMonitor *
203     monitor, GstStructure * structure)
204 {
205   _check_field_type (monitor, structure, "format", G_TYPE_STRING, GST_TYPE_LIST,
206       0);
207   _check_field_type (monitor, structure, "layout", G_TYPE_STRING, GST_TYPE_LIST,
208       0);
209   _check_field_type (monitor, structure, "rate", G_TYPE_INT, GST_TYPE_LIST,
210       GST_TYPE_INT_RANGE, 0);
211   _check_field_type (monitor, structure, "channels", G_TYPE_INT, GST_TYPE_LIST,
212       GST_TYPE_INT_RANGE, 0);
213   _check_field_type (monitor, structure, "channel-mask", GST_TYPE_BITMASK,
214       GST_TYPE_LIST, 0);
215 }
216
217 static void
218 gst_validate_pad_monitor_check_caps_complete (GstValidatePadMonitor * monitor,
219     GstCaps * caps)
220 {
221   GstStructure *structure;
222   gint i;
223
224   GST_DEBUG_OBJECT (monitor->pad, "Checking caps %" GST_PTR_FORMAT, caps);
225
226   for (i = 0; i < gst_caps_get_size (caps); i++) {
227     structure = gst_caps_get_structure (caps, i);
228
229     if (_structure_is_raw_video (structure)) {
230       gst_validate_pad_monitor_check_raw_video_caps_complete (monitor,
231           structure);
232
233     } else if (_structure_is_raw_audio (structure)) {
234       gst_validate_pad_monitor_check_raw_audio_caps_complete (monitor,
235           structure);
236     }
237   }
238 }
239
240 static GstCaps *
241 gst_validate_pad_monitor_get_othercaps (GstValidatePadMonitor * monitor)
242 {
243   GstCaps *caps = gst_caps_new_empty ();
244   GstIterator *iter;
245   gboolean done;
246   GstPad *otherpad;
247   GstCaps *peercaps;
248
249   iter =
250       gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
251       (monitor));
252   done = FALSE;
253   while (!done) {
254     GValue value = { 0, };
255     switch (gst_iterator_next (iter, &value)) {
256       case GST_ITERATOR_OK:
257         otherpad = g_value_get_object (&value);
258
259         /* TODO What would be the correct caps operation to merge the caps in
260          * case one sink is internally linked to multiple srcs? */
261         peercaps = gst_pad_peer_query_caps (otherpad, NULL);
262         if (peercaps)
263           caps = gst_caps_merge (caps, peercaps);
264
265         g_value_reset (&value);
266         break;
267       case GST_ITERATOR_RESYNC:
268         gst_iterator_resync (iter);
269         gst_caps_replace (&caps, gst_caps_new_empty ());
270         break;
271       case GST_ITERATOR_ERROR:
272         GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error");
273         done = TRUE;
274         break;
275       case GST_ITERATOR_DONE:
276         done = TRUE;
277         break;
278     }
279   }
280   gst_iterator_free (iter);
281
282   GST_DEBUG_OBJECT (monitor->pad, "Otherpad caps: %" GST_PTR_FORMAT, caps);
283
284   return caps;
285 }
286
287 static gboolean
288 _structure_is_video (GstStructure * structure)
289 {
290   const gchar *name = gst_structure_get_name (structure);
291
292   return g_strstr_len (name, 6, "video/")
293       && strcmp (name, "video/quicktime") != 0;
294 }
295
296 static gboolean
297 _structure_is_audio (GstStructure * structure)
298 {
299   const gchar *name = gst_structure_get_name (structure);
300
301   return g_strstr_len (name, 6, "audio/") != NULL;
302 }
303
304 static gboolean
305 gst_validate_pad_monitor_pad_should_proxy_othercaps (GstValidatePadMonitor *
306     monitor)
307 {
308   GstValidateMonitor *parent = GST_VALIDATE_MONITOR_GET_PARENT (monitor);
309
310   if (!parent)
311     return FALSE;
312
313   /* We only know how to handle othercaps checks for codecs so far */
314   return GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DECODER (parent) ||
315       GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_ENCODER (parent);
316 }
317
318
319 /* Check if the field @f from @s2 (if present) is represented in @s1
320  * Represented here means either equal or @s1's value is in a list/range
321  * from @s2
322  */
323 static gboolean
324 _structures_field_is_contained (GstStructure * s1, GstStructure * s2,
325     const gchar * f)
326 {
327   const GValue *v1;
328   const GValue *v2;
329
330   v2 = gst_structure_get_value (s2, f);
331   if (!v2)
332     return TRUE;                /* nothing to compare to */
333
334   v1 = gst_structure_get_value (s1, f);
335   if (!v1)
336     return FALSE;
337
338   if (gst_value_compare (v1, v2) == GST_VALUE_EQUAL)
339     return TRUE;
340
341   if (GST_VALUE_HOLDS_LIST (v2)) {
342     gint i;
343     for (i = 0; i < gst_value_list_get_size (v2); i++) {
344       const GValue *v2_subvalue = gst_value_list_get_value (v2, i);
345       if (gst_value_compare (v1, v2_subvalue) == GST_VALUE_EQUAL)
346         return TRUE;
347     }
348   }
349
350   if (GST_VALUE_HOLDS_ARRAY (v2)) {
351     gint i;
352     for (i = 0; i < gst_value_array_get_size (v2); i++) {
353       const GValue *v2_subvalue = gst_value_array_get_value (v2, i);
354       if (gst_value_compare (v1, v2_subvalue) == GST_VALUE_EQUAL)
355         return TRUE;
356     }
357   }
358
359   if (GST_VALUE_HOLDS_INT_RANGE (v2)) {
360     gint min, max;
361
362     min = gst_value_get_int_range_min (v2);
363     max = gst_value_get_int_range_max (v2);
364
365     if (G_VALUE_HOLDS_INT (v1)) {
366       gint v = g_value_get_int (v1);
367
368       return v >= min && v <= max;
369     } else {
370       /* TODO compare int ranges with int ranges
371        * or with lists if useful */
372     }
373   }
374
375   if (GST_VALUE_HOLDS_FRACTION_RANGE (v2)) {
376     const GValue *min, *max;
377
378     min = gst_value_get_fraction_range_min (v2);
379     max = gst_value_get_fraction_range_max (v2);
380
381     if (GST_VALUE_HOLDS_FRACTION (v1)) {
382       gint v_min = gst_value_compare (v1, min);
383       gint v_max = gst_value_compare (v1, max);
384
385       return (v_min == GST_VALUE_EQUAL || v_min == GST_VALUE_GREATER_THAN) &&
386           (v_max == GST_VALUE_EQUAL || v_max == GST_VALUE_LESS_THAN);
387     } else {
388       /* TODO compare fraction ranges with fraction ranges
389        * or with lists if useful */
390     }
391   }
392
393   return FALSE;
394 }
395
396 static void
397 gst_validate_pad_monitor_check_caps_fields_proxied (GstValidatePadMonitor *
398     monitor, GstCaps * caps)
399 {
400   GstStructure *structure;
401   GstStructure *otherstructure;
402   GstCaps *othercaps;
403   gint i, j;
404
405   if (!gst_validate_pad_monitor_pad_should_proxy_othercaps (monitor))
406     return;
407
408   othercaps = gst_validate_pad_monitor_get_othercaps (monitor);
409
410   for (i = 0; i < gst_caps_get_size (othercaps); i++) {
411     gboolean found = FALSE;
412     gboolean type_match = FALSE;
413
414     otherstructure = gst_caps_get_structure (othercaps, i);
415
416     /* look for a proxied version of 'otherstructure' */
417     if (_structure_is_video (otherstructure)) {
418       for (j = 0; j < gst_caps_get_size (caps); j++) {
419         structure = gst_caps_get_structure (caps, j);
420         if (_structure_is_video (structure)) {
421           type_match = TRUE;
422           if (_structures_field_is_contained (structure, otherstructure,
423                   "width")
424               && _structures_field_is_contained (structure, otherstructure,
425                   "height")
426               && _structures_field_is_contained (structure, otherstructure,
427                   "framerate")
428               && _structures_field_is_contained (structure, otherstructure,
429                   "pixel-aspect-ratio")) {
430             found = TRUE;
431             break;
432           }
433         }
434       }
435     } else if (_structure_is_audio (otherstructure)) {
436       for (j = 0; j < gst_caps_get_size (caps); j++) {
437         structure = gst_caps_get_structure (caps, j);
438         if (_structure_is_audio (structure)) {
439           type_match = TRUE;
440           if (_structures_field_is_contained (structure, otherstructure, "rate")
441               && _structures_field_is_contained (structure, otherstructure,
442                   "channels")) {
443             found = TRUE;
444             break;
445           }
446         }
447       }
448     }
449
450     if (type_match && !found) {
451       GST_VALIDATE_REPORT (monitor, GET_CAPS_NOT_PROXYING_FIELDS,
452           "Peer pad structure '%" GST_PTR_FORMAT "' has no similar version "
453           "on pad's caps '%" GST_PTR_FORMAT "'", otherstructure, caps);
454     }
455   }
456 }
457
458 static void
459 gst_validate_pad_monitor_check_late_serialized_events (GstValidatePadMonitor *
460     monitor, GstClockTime ts)
461 {
462   gint i;
463
464   if (!GST_CLOCK_TIME_IS_VALID (ts))
465     return;
466
467   GST_DEBUG_OBJECT (monitor->pad, "Timestamp to check %" GST_TIME_FORMAT,
468       GST_TIME_ARGS (ts));
469
470   for (i = 0; i < monitor->serialized_events->len; i++) {
471     SerializedEventData *data =
472         g_ptr_array_index (monitor->serialized_events, i);
473
474     GST_DEBUG_OBJECT (monitor->pad, "Event #%d (%s) ts: %" GST_TIME_FORMAT,
475         i, GST_EVENT_TYPE_NAME (data->event), GST_TIME_ARGS (data->timestamp));
476
477     if (data->timestamp < ts) {
478       GST_VALIDATE_REPORT (monitor, SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME,
479           "Serialized event %" GST_PTR_FORMAT " wasn't pushed before expected "
480           "timestamp %" GST_TIME_FORMAT " on pad %s:%s", data->event,
481           GST_TIME_ARGS (data->timestamp),
482           GST_DEBUG_PAD_NAME (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor)));
483     } else {
484       /* events should be ordered by ts */
485       break;
486     }
487   }
488
489   if (i) {
490     debug_pending_event (monitor->pad, monitor->serialized_events);
491     g_ptr_array_remove_range (monitor->serialized_events, 0, i);
492   }
493 }
494
495 static void
496 gst_validate_pad_monitor_dispose (GObject * object)
497 {
498   GstValidatePadMonitor *monitor = GST_VALIDATE_PAD_MONITOR_CAST (object);
499   GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor);
500
501   if (pad) {
502     if (monitor->pad_probe_id)
503       gst_pad_remove_probe (pad, monitor->pad_probe_id);
504   }
505
506   if (monitor->expected_segment)
507     gst_event_unref (monitor->expected_segment);
508
509   gst_structure_free (monitor->pending_setcaps_fields);
510   g_ptr_array_unref (monitor->serialized_events);
511   g_list_free (monitor->expired_events);
512
513   G_OBJECT_CLASS (parent_class)->dispose (object);
514 }
515
516 static void
517 gst_validate_pad_monitor_class_init (GstValidatePadMonitorClass * klass)
518 {
519   GObjectClass *gobject_class;
520   GstValidateMonitorClass *monitor_klass;
521
522   gobject_class = G_OBJECT_CLASS (klass);
523   monitor_klass = GST_VALIDATE_MONITOR_CLASS (klass);
524
525   gobject_class->dispose = gst_validate_pad_monitor_dispose;
526
527   monitor_klass->setup = gst_validate_pad_monitor_do_setup;
528   monitor_klass->get_element = gst_validate_pad_monitor_get_element;
529 }
530
531 static void
532 gst_validate_pad_monitor_init (GstValidatePadMonitor * pad_monitor)
533 {
534   pad_monitor->pending_setcaps_fields =
535       gst_structure_new_empty (PENDING_FIELDS);
536   pad_monitor->serialized_events =
537       g_ptr_array_new_with_free_func ((GDestroyNotify)
538       _serialized_event_data_free);
539   pad_monitor->expired_events = NULL;
540   gst_segment_init (&pad_monitor->segment, GST_FORMAT_BYTES);
541   pad_monitor->first_buffer = TRUE;
542
543   pad_monitor->timestamp_range_start = GST_CLOCK_TIME_NONE;
544   pad_monitor->timestamp_range_end = GST_CLOCK_TIME_NONE;
545 }
546
547 /**
548  * gst_validate_pad_monitor_new:
549  * @pad: (transfer-none): a #GstPad to run Validate on
550  */
551 GstValidatePadMonitor *
552 gst_validate_pad_monitor_new (GstPad * pad, GstValidateRunner * runner,
553     GstValidateElementMonitor * parent)
554 {
555   GstValidatePadMonitor *monitor = g_object_new (GST_TYPE_VALIDATE_PAD_MONITOR,
556       "object", pad, "qa-runner", runner, "qa-parent",
557       parent, NULL);
558
559   if (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor) == NULL) {
560     g_object_unref (monitor);
561     return NULL;
562   }
563   return monitor;
564 }
565
566 static GstElement *
567 gst_validate_pad_monitor_get_element (GstValidateMonitor * monitor)
568 {
569   GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor);
570
571   return GST_PAD_PARENT (pad);
572 }
573
574 static void
575 gst_validate_pad_monitor_event_overrides (GstValidatePadMonitor * pad_monitor,
576     GstEvent * event)
577 {
578   GList *iter;
579
580   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
581   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
582       iter = g_list_next (iter)) {
583     GstValidateOverride *override = iter->data;
584
585     gst_validate_override_event_handler (override,
586         GST_VALIDATE_MONITOR_CAST (pad_monitor), event);
587   }
588   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
589 }
590
591 static void
592 gst_validate_pad_monitor_buffer_overrides (GstValidatePadMonitor * pad_monitor,
593     GstBuffer * buffer)
594 {
595   GList *iter;
596
597   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
598   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
599       iter = g_list_next (iter)) {
600     GstValidateOverride *override = iter->data;
601
602     gst_validate_override_buffer_handler (override,
603         GST_VALIDATE_MONITOR_CAST (pad_monitor), buffer);
604   }
605   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
606 }
607
608 static void
609 gst_validate_pad_monitor_buffer_probe_overrides (GstValidatePadMonitor *
610     pad_monitor, GstBuffer * buffer)
611 {
612   GList *iter;
613
614   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
615   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
616       iter = g_list_next (iter)) {
617     GstValidateOverride *override = iter->data;
618
619     gst_validate_override_buffer_probe_handler (override,
620         GST_VALIDATE_MONITOR_CAST (pad_monitor), buffer);
621   }
622   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
623 }
624
625 static void
626 gst_validate_pad_monitor_query_overrides (GstValidatePadMonitor * pad_monitor,
627     GstQuery * query)
628 {
629   GList *iter;
630
631   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
632   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
633       iter = g_list_next (iter)) {
634     GstValidateOverride *override = iter->data;
635
636     gst_validate_override_query_handler (override,
637         GST_VALIDATE_MONITOR_CAST (pad_monitor), query);
638   }
639   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
640 }
641
642 static void
643 gst_validate_pad_monitor_setcaps_overrides (GstValidatePadMonitor * pad_monitor,
644     GstCaps * caps)
645 {
646   GList *iter;
647
648   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
649   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
650       iter = g_list_next (iter)) {
651     GstValidateOverride *override = iter->data;
652
653     gst_validate_override_setcaps_handler (override,
654         GST_VALIDATE_MONITOR_CAST (pad_monitor), caps);
655   }
656   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
657 }
658
659 /* FIXME : This is a bit dubious, what's the point of this check ? */
660 static gboolean
661 gst_validate_pad_monitor_timestamp_is_in_received_range (GstValidatePadMonitor *
662     monitor, GstClockTime ts)
663 {
664   GST_DEBUG_OBJECT (monitor->pad, "Checking if timestamp %" GST_TIME_FORMAT
665       " is in range: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT " for pad "
666       "%s:%s", GST_TIME_ARGS (ts),
667       GST_TIME_ARGS (monitor->timestamp_range_start),
668       GST_TIME_ARGS (monitor->timestamp_range_end),
669       GST_DEBUG_PAD_NAME (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor)));
670   return !GST_CLOCK_TIME_IS_VALID (monitor->timestamp_range_start) ||
671       !GST_CLOCK_TIME_IS_VALID (monitor->timestamp_range_end) ||
672       (monitor->timestamp_range_start <= ts
673       && ts <= monitor->timestamp_range_end);
674 }
675
676 /* Iterates over internal links (sinkpads) to check that this buffer has
677  * a timestamp that is in the range of the lastly received buffers */
678 static void
679     gst_validate_pad_monitor_check_buffer_timestamp_in_received_range
680     (GstValidatePadMonitor * monitor, GstBuffer * buffer)
681 {
682   GstClockTime ts;
683   GstClockTime ts_end;
684   GstIterator *iter;
685   gboolean has_one = FALSE;
686   gboolean found = FALSE;
687   gboolean done;
688   GstPad *otherpad;
689   GstValidatePadMonitor *othermonitor;
690
691   if (!GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))
692       || !GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) {
693     GST_DEBUG_OBJECT (monitor->pad,
694         "Can't check buffer timestamps range as "
695         "buffer has no valid timestamp/duration");
696     return;
697   }
698   ts = GST_BUFFER_TIMESTAMP (buffer);
699   ts_end = ts + GST_BUFFER_DURATION (buffer);
700
701   iter =
702       gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
703       (monitor));
704   done = FALSE;
705   while (!done) {
706     GValue value = { 0, };
707     switch (gst_iterator_next (iter, &value)) {
708       case GST_ITERATOR_OK:
709         otherpad = g_value_get_object (&value);
710         GST_DEBUG_OBJECT (monitor->pad, "Checking pad %s:%s input timestamps",
711             GST_DEBUG_PAD_NAME (otherpad));
712         othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor");
713         GST_VALIDATE_MONITOR_LOCK (othermonitor);
714         if (gst_validate_pad_monitor_timestamp_is_in_received_range
715             (othermonitor, ts)
716             &&
717             gst_validate_pad_monitor_timestamp_is_in_received_range
718             (othermonitor, ts_end)) {
719           done = TRUE;
720           found = TRUE;
721         }
722         GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
723         g_value_reset (&value);
724         has_one = TRUE;
725         break;
726       case GST_ITERATOR_RESYNC:
727         gst_iterator_resync (iter);
728         has_one = FALSE;
729         found = FALSE;
730         break;
731       case GST_ITERATOR_ERROR:
732         GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error");
733         done = TRUE;
734         break;
735       case GST_ITERATOR_DONE:
736         done = TRUE;
737         break;
738     }
739   }
740   gst_iterator_free (iter);
741
742   if (!has_one) {
743     GST_DEBUG_OBJECT (monitor->pad, "Skipping timestamp in range check as no "
744         "internal linked pad was found");
745     return;
746   }
747   if (!found) {
748     GST_VALIDATE_REPORT (monitor, BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE,
749         "Timestamp %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT
750         " is out of range of received input", GST_TIME_ARGS (ts),
751         GST_TIME_ARGS (ts_end));
752   }
753 }
754
755 static void
756 gst_validate_pad_monitor_check_first_buffer (GstValidatePadMonitor *
757     pad_monitor, GstBuffer * buffer)
758 {
759   if (G_UNLIKELY (pad_monitor->first_buffer)) {
760     pad_monitor->first_buffer = FALSE;
761
762     if (!pad_monitor->has_segment
763         && PAD_IS_IN_PUSH_MODE (GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor)))
764     {
765       GST_VALIDATE_REPORT (pad_monitor, BUFFER_BEFORE_SEGMENT,
766           "Received buffer before Segment event");
767     }
768     if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) {
769       gint64 running_time = gst_segment_to_running_time (&pad_monitor->segment,
770           pad_monitor->segment.format, GST_BUFFER_TIMESTAMP (buffer));
771       if (running_time != 0) {
772         GST_VALIDATE_REPORT (pad_monitor, FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO,
773             "First buffer running time is not 0, it is: %" GST_TIME_FORMAT,
774             GST_TIME_ARGS (running_time));
775       }
776     }
777   }
778 }
779
780 static void
781 gst_validate_pad_monitor_update_buffer_data (GstValidatePadMonitor *
782     pad_monitor, GstBuffer * buffer)
783 {
784   pad_monitor->current_timestamp = GST_BUFFER_TIMESTAMP (buffer);
785   pad_monitor->current_duration = GST_BUFFER_DURATION (buffer);
786   if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) {
787     if (GST_CLOCK_TIME_IS_VALID (pad_monitor->timestamp_range_start)) {
788       pad_monitor->timestamp_range_start =
789           MIN (pad_monitor->timestamp_range_start,
790           GST_BUFFER_TIMESTAMP (buffer));
791     } else {
792       pad_monitor->timestamp_range_start = GST_BUFFER_TIMESTAMP (buffer);
793     }
794
795     if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) {
796       GstClockTime endts =
797           GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer);
798       if (GST_CLOCK_TIME_IS_VALID (pad_monitor->timestamp_range_end)) {
799         pad_monitor->timestamp_range_end =
800             MAX (pad_monitor->timestamp_range_end, endts);
801       } else {
802         pad_monitor->timestamp_range_end = endts;
803       }
804     }
805   }
806   GST_DEBUG_OBJECT (pad_monitor->pad, "Current stored range: %" GST_TIME_FORMAT
807       " - %" GST_TIME_FORMAT,
808       GST_TIME_ARGS (pad_monitor->timestamp_range_start),
809       GST_TIME_ARGS (pad_monitor->timestamp_range_end));
810 }
811
812 static GstFlowReturn
813 _combine_flows (GstFlowReturn ret1, GstFlowReturn ret2)
814 {
815   if (ret1 == ret2)
816     return ret1;
817   if (ret1 <= GST_FLOW_NOT_NEGOTIATED)
818     return ret1;
819   if (ret2 <= GST_FLOW_NOT_NEGOTIATED)
820     return ret2;
821   if (ret1 == GST_FLOW_FLUSHING || ret2 == GST_FLOW_FLUSHING)
822     return GST_FLOW_FLUSHING;
823   if (ret1 == GST_FLOW_OK || ret2 == GST_FLOW_OK)
824     return GST_FLOW_OK;
825   return ret2;
826 }
827
828 static void
829 gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor *
830     monitor, GstFlowReturn ret)
831 {
832   GstIterator *iter;
833   gboolean done;
834   GstPad *otherpad;
835   GstPad *peerpad;
836   GstValidatePadMonitor *othermonitor;
837   GstFlowReturn aggregated = GST_FLOW_NOT_LINKED;
838   gboolean found_a_pad = FALSE;
839
840   iter =
841       gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
842       (monitor));
843   done = FALSE;
844   while (!done) {
845     GValue value = { 0, };
846     switch (gst_iterator_next (iter, &value)) {
847       case GST_ITERATOR_OK:
848         otherpad = g_value_get_object (&value);
849         peerpad = gst_pad_get_peer (otherpad);
850         if (peerpad) {
851           othermonitor = g_object_get_data ((GObject *) peerpad, "qa-monitor");
852           if (othermonitor) {
853             found_a_pad = TRUE;
854             GST_VALIDATE_MONITOR_LOCK (othermonitor);
855             aggregated =
856                 _combine_flows (aggregated, othermonitor->last_flow_return);
857             GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
858           }
859
860           gst_object_unref (peerpad);
861         }
862         g_value_reset (&value);
863         break;
864       case GST_ITERATOR_RESYNC:
865         gst_iterator_resync (iter);
866         break;
867       case GST_ITERATOR_ERROR:
868         GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error");
869         done = TRUE;
870         break;
871       case GST_ITERATOR_DONE:
872         done = TRUE;
873         break;
874     }
875   }
876   gst_iterator_free (iter);
877   if (!found_a_pad) {
878     /* no peer pad found, nothing to do */
879     return;
880   }
881   if (aggregated == GST_FLOW_OK || aggregated == GST_FLOW_EOS) {
882     /* those are acceptable situations */
883
884     if (monitor->is_eos && ret == GST_FLOW_EOS) {
885       /* this element received eos and returned eos */
886       return;
887     }
888
889     if (PAD_PARENT_IS_DEMUXER (monitor) && ret == GST_FLOW_EOS) {
890       /* a demuxer can return EOS when the samples end */
891       return;
892     }
893   }
894
895   if (aggregated != ret) {
896     GST_VALIDATE_REPORT (monitor, WRONG_FLOW_RETURN,
897         "Wrong combined flow return %s(%d). Expected: %s(%d)",
898         gst_flow_get_name (ret), ret, gst_flow_get_name (aggregated),
899         aggregated);
900   }
901 }
902
903 static void
904     gst_validate_pad_monitor_otherpad_add_pending_serialized_event
905     (GstValidatePadMonitor * monitor, GstEvent * event, GstClockTime last_ts)
906 {
907   GstIterator *iter;
908   gboolean done;
909   GstPad *otherpad;
910   GstValidatePadMonitor *othermonitor;
911
912   if (!GST_EVENT_IS_SERIALIZED (event))
913     return;
914
915   iter =
916       gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
917       (monitor));
918   if (iter == NULL) {
919     /* inputselector will return NULL if the sinkpad is not the active one .... */
920     GST_FIXME_OBJECT (GST_VALIDATE_PAD_MONITOR_GET_PAD
921         (monitor), "No iterator");
922     return;
923   }
924   done = FALSE;
925   while (!done) {
926     GValue value = { 0, };
927     switch (gst_iterator_next (iter, &value)) {
928       case GST_ITERATOR_OK:
929         otherpad = g_value_get_object (&value);
930         othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor");
931         if (othermonitor) {
932           SerializedEventData *data = g_slice_new0 (SerializedEventData);
933           data->timestamp = last_ts;
934           data->event = gst_event_ref (event);
935           GST_VALIDATE_MONITOR_LOCK (othermonitor);
936           GST_DEBUG_OBJECT (monitor->pad, "Storing for pad %s:%s event %p %s",
937               GST_DEBUG_PAD_NAME (otherpad), event,
938               GST_EVENT_TYPE_NAME (event));
939           g_ptr_array_add (othermonitor->serialized_events, data);
940           debug_pending_event (otherpad, othermonitor->serialized_events);
941           GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
942         }
943         g_value_reset (&value);
944         break;
945       case GST_ITERATOR_RESYNC:
946         gst_iterator_resync (iter);
947         break;
948       case GST_ITERATOR_ERROR:
949         GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error");
950         done = TRUE;
951         break;
952       case GST_ITERATOR_DONE:
953         done = TRUE;
954         break;
955     }
956   }
957   gst_iterator_free (iter);
958 }
959
960 static void
961 gst_validate_pad_monitor_otherpad_add_pending_field (GstValidatePadMonitor *
962     monitor, GstStructure * structure, const gchar * field)
963 {
964   GstIterator *iter;
965   gboolean done;
966   GstPad *otherpad;
967   GstValidatePadMonitor *othermonitor;
968   const GValue *v;
969
970   v = gst_structure_get_value (structure, field);
971   if (v == NULL) {
972     GST_DEBUG_OBJECT (monitor->pad, "Not adding pending field %s as it isn't "
973         "present on structure %" GST_PTR_FORMAT, field, structure);
974     return;
975   }
976
977   iter =
978       gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
979       (monitor));
980   done = FALSE;
981   while (!done) {
982     GValue value = { 0, };
983     switch (gst_iterator_next (iter, &value)) {
984       case GST_ITERATOR_OK:
985         otherpad = g_value_get_object (&value);
986         othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor");
987         if (othermonitor) {
988           GST_VALIDATE_MONITOR_LOCK (othermonitor);
989           g_assert (othermonitor->pending_setcaps_fields != NULL);
990           gst_structure_set_value (othermonitor->pending_setcaps_fields,
991               field, v);
992           GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
993         }
994         g_value_reset (&value);
995         break;
996       case GST_ITERATOR_RESYNC:
997         gst_iterator_resync (iter);
998         break;
999       case GST_ITERATOR_ERROR:
1000         GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error");
1001         done = TRUE;
1002         break;
1003       case GST_ITERATOR_DONE:
1004         done = TRUE;
1005         break;
1006     }
1007   }
1008   gst_iterator_free (iter);
1009 }
1010
1011 static void
1012 gst_validate_pad_monitor_otherpad_clear_pending_fields (GstValidatePadMonitor *
1013     monitor)
1014 {
1015   GstIterator *iter;
1016   gboolean done;
1017   GstPad *otherpad;
1018   GstValidatePadMonitor *othermonitor;
1019
1020   iter =
1021       gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
1022       (monitor));
1023   done = FALSE;
1024   while (!done) {
1025     GValue value = { 0, };
1026     switch (gst_iterator_next (iter, &value)) {
1027       case GST_ITERATOR_OK:
1028         otherpad = g_value_get_object (&value);
1029         othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor");
1030         if (othermonitor) {
1031           GST_VALIDATE_MONITOR_LOCK (othermonitor);
1032           g_assert (othermonitor->pending_setcaps_fields != NULL);
1033           gst_structure_free (othermonitor->pending_setcaps_fields);
1034           othermonitor->pending_setcaps_fields =
1035               gst_structure_new_empty (PENDING_FIELDS);
1036           GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1037         }
1038         g_value_reset (&value);
1039         break;
1040       case GST_ITERATOR_RESYNC:
1041         gst_iterator_resync (iter);
1042         break;
1043       case GST_ITERATOR_ERROR:
1044         GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error");
1045         done = TRUE;
1046         break;
1047       case GST_ITERATOR_DONE:
1048         done = TRUE;
1049         break;
1050     }
1051   }
1052   gst_iterator_free (iter);
1053 }
1054
1055 static void
1056 gst_validate_pad_monitor_add_expected_newsegment (GstValidatePadMonitor *
1057     monitor, GstEvent * event)
1058 {
1059   GstIterator *iter;
1060   gboolean done;
1061   GstPad *otherpad;
1062   GstValidatePadMonitor *othermonitor;
1063
1064   iter =
1065       gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
1066       (monitor));
1067   done = FALSE;
1068   while (!done) {
1069     GValue value = { 0, };
1070     switch (gst_iterator_next (iter, &value)) {
1071       case GST_ITERATOR_OK:
1072         otherpad = g_value_get_object (&value);
1073         othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor");
1074         GST_VALIDATE_MONITOR_LOCK (othermonitor);
1075         if (othermonitor->expected_segment) {
1076           GST_VALIDATE_REPORT (othermonitor, EVENT_NEWSEGMENT_NOT_PUSHED, "");
1077           gst_event_unref (othermonitor->expected_segment);
1078         }
1079         othermonitor->expected_segment = gst_event_ref (event);
1080         GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1081         g_value_reset (&value);
1082         break;
1083       case GST_ITERATOR_RESYNC:
1084         gst_iterator_resync (iter);
1085         break;
1086       case GST_ITERATOR_ERROR:
1087         GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error");
1088         done = TRUE;
1089         break;
1090       case GST_ITERATOR_DONE:
1091         done = TRUE;
1092         break;
1093     }
1094   }
1095   gst_iterator_free (iter);
1096 }
1097
1098 static void
1099 gst_validate_pad_monitor_flush (GstValidatePadMonitor * pad_monitor)
1100 {
1101   pad_monitor->current_timestamp = GST_CLOCK_TIME_NONE;
1102   pad_monitor->current_duration = GST_CLOCK_TIME_NONE;
1103   pad_monitor->timestamp_range_start = GST_CLOCK_TIME_NONE;
1104   pad_monitor->timestamp_range_end = GST_CLOCK_TIME_NONE;
1105   pad_monitor->has_segment = FALSE;
1106   pad_monitor->is_eos = FALSE;
1107   gst_caps_replace (&pad_monitor->last_caps, NULL);
1108
1109   g_list_free_full (pad_monitor->expired_events,
1110       (GDestroyNotify) gst_event_unref);
1111   pad_monitor->expired_events = NULL;
1112
1113   if (pad_monitor->serialized_events->len)
1114     g_ptr_array_remove_range (pad_monitor->serialized_events, 0,
1115         pad_monitor->serialized_events->len);
1116 }
1117
1118 /* common checks for both sink and src event functions */
1119 static void
1120 gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor *
1121     pad_monitor, GstEvent * event)
1122 {
1123   guint32 seqnum = gst_event_get_seqnum (event);
1124
1125   switch (GST_EVENT_TYPE (event)) {
1126     case GST_EVENT_FLUSH_START:
1127     {
1128       if (pad_monitor->pending_flush_start_seqnum) {
1129         if (seqnum == pad_monitor->pending_flush_start_seqnum) {
1130           pad_monitor->pending_flush_start_seqnum = 0;
1131         } else {
1132           GST_VALIDATE_REPORT (pad_monitor, EVENT_HAS_WRONG_SEQNUM,
1133               "The expected flush-start seqnum should be the same as the "
1134               "one from the event that caused it (probably a seek). Got: %u."
1135               " Expected: %u", seqnum, pad_monitor->pending_flush_start_seqnum);
1136         }
1137       }
1138
1139       if (pad_monitor->pending_flush_stop) {
1140         GST_VALIDATE_REPORT (pad_monitor, EVENT_FLUSH_START_UNEXPECTED,
1141             "Received flush-start from " " when flush-stop was expected");
1142       }
1143       pad_monitor->pending_flush_stop = TRUE;
1144     }
1145       break;
1146     case GST_EVENT_FLUSH_STOP:
1147     {
1148       if (pad_monitor->pending_flush_stop_seqnum) {
1149         if (seqnum == pad_monitor->pending_flush_stop_seqnum) {
1150           pad_monitor->pending_flush_stop_seqnum = 0;
1151         } else {
1152           GST_VALIDATE_REPORT (pad_monitor, EVENT_HAS_WRONG_SEQNUM,
1153               "The expected flush-stop seqnum should be the same as the "
1154               "one from the event that caused it (probably a seek). Got: %u."
1155               " Expected: %u", seqnum, pad_monitor->pending_flush_stop_seqnum);
1156         }
1157       }
1158
1159       if (!pad_monitor->pending_flush_stop) {
1160         GST_VALIDATE_REPORT (pad_monitor, EVENT_FLUSH_STOP_UNEXPECTED,
1161             "Unexpected flush-stop %p" GST_PTR_FORMAT, event);
1162       }
1163       pad_monitor->pending_flush_stop = FALSE;
1164
1165       /* cleanup our data */
1166       gst_validate_pad_monitor_flush (pad_monitor);
1167     }
1168       break;
1169     default:
1170       break;
1171   }
1172 }
1173
1174 static gboolean
1175 gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor *
1176     pad_monitor, GstObject * parent, GstEvent * event,
1177     GstPadEventFunction handler)
1178 {
1179   gboolean ret = TRUE;
1180   const GstSegment *segment;
1181   guint32 seqnum = gst_event_get_seqnum (event);
1182   GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor);
1183
1184   gst_validate_pad_monitor_common_event_check (pad_monitor, event);
1185
1186   /* pre checks */
1187   switch (GST_EVENT_TYPE (event)) {
1188     case GST_EVENT_SEGMENT:
1189       /* parse segment data to be used if event is handled */
1190       gst_event_parse_segment (event, &segment);
1191
1192       if (pad_monitor->pending_newsegment_seqnum) {
1193         if (pad_monitor->pending_newsegment_seqnum == seqnum) {
1194           pad_monitor->pending_newsegment_seqnum = 0;
1195         } else {
1196           /* TODO is this an error? could be a segment from the start
1197            * received just before the seek segment */
1198         }
1199       }
1200
1201       /* got a segment, no need for EOS now */
1202       pad_monitor->pending_eos_seqnum = 0;
1203
1204       if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
1205         gst_validate_pad_monitor_add_expected_newsegment (pad_monitor, event);
1206       } else {
1207         /* check if this segment is the expected one */
1208         if (pad_monitor->expected_segment) {
1209           const GstSegment *exp_segment;
1210
1211           if (pad_monitor->expected_segment != event) {
1212             gst_event_parse_segment (pad_monitor->expected_segment,
1213                 &exp_segment);
1214             if (segment->format == exp_segment->format) {
1215               if ((exp_segment->rate * exp_segment->applied_rate !=
1216                       segment->rate * segment->applied_rate)
1217                   || exp_segment->start != segment->start
1218                   || exp_segment->stop != segment->stop
1219                   || exp_segment->position != segment->position) {
1220                 GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH,
1221                     "Expected segment didn't match received segment event");
1222               }
1223             }
1224           }
1225           gst_event_replace (&pad_monitor->expected_segment, NULL);
1226         }
1227       }
1228       break;
1229     case GST_EVENT_EOS:
1230       pad_monitor->is_eos = TRUE;
1231       if (pad_monitor->pending_eos_seqnum &&
1232           pad_monitor->pending_eos_seqnum != seqnum) {
1233         GST_VALIDATE_REPORT (pad_monitor, EVENT_HAS_WRONG_SEQNUM,
1234             "The expected EOS seqnum should be the same as the "
1235             "one from the seek that caused it. Got: %u."
1236             " Expected: %u", seqnum, pad_monitor->pending_eos_seqnum);
1237       }
1238       /*
1239        * TODO add end of stream checks for
1240        *  - events not pushed
1241        *  - buffer data not pushed
1242        *  - pending events not received
1243        */
1244       break;
1245
1246       /* both flushes are handled by the common event function */
1247     case GST_EVENT_FLUSH_START:
1248     case GST_EVENT_FLUSH_STOP:
1249     case GST_EVENT_TAG:
1250     case GST_EVENT_SINK_MESSAGE:
1251     default:
1252       break;
1253   }
1254
1255   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1256   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
1257   gst_validate_pad_monitor_event_overrides (pad_monitor, event);
1258   if (handler) {
1259     gst_event_ref (event);
1260     ret = pad_monitor->event_func (pad, parent, event);
1261   }
1262   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
1263   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1264
1265   /* post checks */
1266   switch (GST_EVENT_TYPE (event)) {
1267     case GST_EVENT_SEGMENT:
1268       if (ret) {
1269         if (!pad_monitor->has_segment
1270             && pad_monitor->segment.format != segment->format) {
1271           gst_segment_init (&pad_monitor->segment, segment->format);
1272         }
1273         gst_segment_copy_into (segment, &pad_monitor->segment);
1274         pad_monitor->has_segment = TRUE;
1275       }
1276       break;
1277     case GST_EVENT_FLUSH_START:
1278     case GST_EVENT_FLUSH_STOP:
1279     case GST_EVENT_EOS:
1280     case GST_EVENT_TAG:
1281     case GST_EVENT_SINK_MESSAGE:
1282     default:
1283       break;
1284   }
1285
1286   if (handler)
1287     gst_event_unref (event);
1288   return ret;
1289 }
1290
1291 static gboolean
1292 gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor,
1293     GstObject * parent, GstEvent * event, GstPadEventFunction handler)
1294 {
1295   gboolean ret = TRUE;
1296   gdouble rate;
1297   GstFormat format;
1298   gint64 start, stop;
1299   GstSeekFlags seek_flags;
1300   GstSeekType start_type, stop_type;
1301   guint32 seqnum = gst_event_get_seqnum (event);
1302   GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor);
1303
1304   gst_validate_pad_monitor_common_event_check (pad_monitor, event);
1305
1306   /* pre checks */
1307   switch (GST_EVENT_TYPE (event)) {
1308     case GST_EVENT_SEEK:
1309     {
1310       gst_event_parse_seek (event, &rate, &format, &seek_flags, &start_type,
1311           &start, &stop_type, &stop);
1312       /* upstream seek - store the seek event seqnum to check
1313        * flushes and newsegments share the same */
1314
1315       /* TODO we might need to use a list as multiple seeks can be sent
1316        * before the flushes arrive here */
1317       if (seek_flags & GST_SEEK_FLAG_FLUSH) {
1318         pad_monitor->pending_flush_start_seqnum = seqnum;
1319         pad_monitor->pending_flush_stop_seqnum = seqnum;
1320       }
1321       pad_monitor->pending_newsegment_seqnum = seqnum;
1322       pad_monitor->pending_eos_seqnum = seqnum;
1323     }
1324       break;
1325       /* both flushes are handled by the common event handling function */
1326     case GST_EVENT_FLUSH_START:
1327     case GST_EVENT_FLUSH_STOP:
1328     case GST_EVENT_NAVIGATION:
1329     case GST_EVENT_LATENCY:
1330     case GST_EVENT_STEP:
1331     case GST_EVENT_QOS:
1332     default:
1333       break;
1334   }
1335
1336   if (handler) {
1337     GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1338     gst_event_ref (event);
1339     ret = pad_monitor->event_func (pad, parent, event);
1340     GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1341   }
1342
1343   /* post checks */
1344   switch (GST_EVENT_TYPE (event)) {
1345     case GST_EVENT_FLUSH_START:
1346     case GST_EVENT_FLUSH_STOP:
1347     case GST_EVENT_QOS:
1348     case GST_EVENT_SEEK:
1349     case GST_EVENT_NAVIGATION:
1350     case GST_EVENT_LATENCY:
1351     case GST_EVENT_STEP:
1352     default:
1353       break;
1354   }
1355
1356   if (handler)
1357     gst_event_unref (event);
1358   return ret;
1359 }
1360
1361 static GstFlowReturn
1362 gst_validate_pad_monitor_chain_func (GstPad * pad, GstObject * parent,
1363     GstBuffer * buffer)
1364 {
1365   GstValidatePadMonitor *pad_monitor =
1366       g_object_get_data ((GObject *) pad, "qa-monitor");
1367   GstFlowReturn ret;
1368
1369   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
1370   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1371
1372   gst_validate_pad_monitor_check_first_buffer (pad_monitor, buffer);
1373   gst_validate_pad_monitor_update_buffer_data (pad_monitor, buffer);
1374
1375   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1376   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
1377
1378   gst_validate_pad_monitor_buffer_overrides (pad_monitor, buffer);
1379
1380   ret = pad_monitor->chain_func (pad, parent, buffer);
1381
1382   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
1383   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1384
1385   pad_monitor->last_flow_return = ret;
1386   if (PAD_PARENT_IS_DEMUXER (pad_monitor))
1387     gst_validate_pad_monitor_check_aggregated_return (pad_monitor, ret);
1388
1389   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1390   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
1391
1392   return ret;
1393 }
1394
1395 static gboolean
1396 gst_validate_pad_monitor_event_is_tracked (GstValidatePadMonitor * monitor,
1397     GstEvent * event)
1398 {
1399   if (!GST_EVENT_IS_SERIALIZED (event)) {
1400     return FALSE;
1401   }
1402
1403   /* we don't track Tag events because they mutate too much and it is hard
1404    * to match a tag event pushed on a source pad with the one that was received
1405    * on a sink pad.
1406    * One idea would be to use seqnum, but it seems that it is undefined whether
1407    * seqnums should be maintained in tag events that are created from others
1408    * up to today. (2013-08-29)
1409    */
1410   if (GST_EVENT_TYPE (event) == GST_EVENT_TAG)
1411     return FALSE;
1412
1413   return TRUE;
1414 }
1415
1416 static gboolean
1417 gst_validate_pad_monitor_sink_event_func (GstPad * pad, GstObject * parent,
1418     GstEvent * event)
1419 {
1420   GstValidatePadMonitor *pad_monitor =
1421       g_object_get_data ((GObject *) pad, "qa-monitor");
1422   gboolean ret;
1423
1424   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
1425   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1426
1427   if (gst_validate_pad_monitor_event_is_tracked (pad_monitor, event)) {
1428     GstClockTime last_ts;
1429     if (GST_CLOCK_TIME_IS_VALID (pad_monitor->current_timestamp)) {
1430       last_ts = pad_monitor->current_timestamp;
1431       if (GST_CLOCK_TIME_IS_VALID (pad_monitor->current_duration)) {
1432         last_ts += pad_monitor->current_duration;
1433       }
1434     } else {
1435       last_ts = 0;
1436     }
1437     gst_validate_pad_monitor_otherpad_add_pending_serialized_event (pad_monitor,
1438         event, last_ts);
1439   }
1440
1441   /* pre checks */
1442   switch (GST_EVENT_TYPE (event)) {
1443     case GST_EVENT_CAPS:{
1444       GstCaps *caps;
1445
1446       gst_event_parse_caps (event, &caps);
1447       gst_validate_pad_monitor_setcaps_pre (pad_monitor, caps);
1448       break;
1449     }
1450     default:
1451       break;
1452   }
1453   ret =
1454       gst_validate_pad_monitor_downstream_event_check (pad_monitor, parent,
1455       event, pad_monitor->event_func);
1456   /* post checks */
1457   switch (GST_EVENT_TYPE (event)) {
1458     case GST_EVENT_CAPS:{
1459       GstCaps *caps;
1460
1461       gst_event_parse_caps (event, &caps);
1462       gst_validate_pad_monitor_setcaps_post (pad_monitor, caps, ret);
1463       break;
1464     }
1465     default:
1466       break;
1467   }
1468
1469   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1470   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
1471   return ret;
1472 }
1473
1474 static gboolean
1475 gst_validate_pad_monitor_src_event_func (GstPad * pad, GstObject * parent,
1476     GstEvent * event)
1477 {
1478   GstValidatePadMonitor *pad_monitor =
1479       g_object_get_data ((GObject *) pad, "qa-monitor");
1480   gboolean ret;
1481
1482   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1483   ret = gst_validate_pad_monitor_src_event_check (pad_monitor, parent, event,
1484       pad_monitor->event_func);
1485   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1486   return ret;
1487 }
1488
1489 static gboolean
1490 gst_validate_pad_monitor_query_func (GstPad * pad, GstObject * parent,
1491     GstQuery * query)
1492 {
1493   GstValidatePadMonitor *pad_monitor =
1494       g_object_get_data ((GObject *) pad, "qa-monitor");
1495   gboolean ret;
1496
1497   gst_validate_pad_monitor_query_overrides (pad_monitor, query);
1498
1499   ret = pad_monitor->query_func (pad, parent, query);
1500
1501   if (ret) {
1502     switch (GST_QUERY_TYPE (query)) {
1503       case GST_QUERY_CAPS:{
1504         GstCaps *res;
1505         /* We shouldn't need to lock the parent as this doesn't modify
1506          * other monitors, just does some peer_pad_caps */
1507         GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1508
1509         gst_query_parse_caps_result (query, &res);
1510         if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
1511           gst_validate_pad_monitor_check_caps_fields_proxied (pad_monitor, res);
1512         }
1513         GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1514         break;
1515       }
1516       default:
1517         break;
1518     }
1519   }
1520
1521   return ret;
1522 }
1523
1524 static gboolean
1525 gst_validate_pad_monitor_activatemode_func (GstPad * pad, GstObject * parent,
1526     GstPadMode mode, gboolean active)
1527 {
1528   GstValidatePadMonitor *pad_monitor =
1529       g_object_get_data ((GObject *) pad, "qa-monitor");
1530   gboolean ret = TRUE;
1531
1532   /* TODO add overrides for activate func */
1533
1534   if (pad_monitor->activatemode_func)
1535     ret = pad_monitor->activatemode_func (pad, parent, mode, active);
1536   if (ret && active == FALSE) {
1537     GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1538     gst_validate_pad_monitor_flush (pad_monitor);
1539     GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1540   }
1541
1542   return ret;
1543 }
1544
1545 static gboolean
1546 gst_validate_pad_get_range_func (GstPad * pad, GstObject * parent,
1547     guint64 offset, guint size, GstBuffer ** buffer)
1548 {
1549   GstValidatePadMonitor *pad_monitor =
1550       g_object_get_data ((GObject *) pad, "qa-monitor");
1551   gboolean ret;
1552   ret = pad_monitor->getrange_func (pad, parent, offset, size, buffer);
1553   return ret;
1554 }
1555
1556 static gboolean
1557 gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer,
1558     gpointer udata)
1559 {
1560   GstValidatePadMonitor *monitor = udata;
1561   GstValidateMonitor *parent = GST_VALIDATE_MONITOR_GET_PARENT (monitor);
1562
1563   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor);
1564   GST_VALIDATE_MONITOR_LOCK (monitor);
1565
1566   gst_validate_pad_monitor_check_first_buffer (monitor, buffer);
1567   gst_validate_pad_monitor_update_buffer_data (monitor, buffer);
1568
1569   gst_validate_pad_monitor_check_buffer_timestamp_in_received_range (monitor,
1570       buffer);
1571
1572   gst_validate_pad_monitor_check_late_serialized_events (monitor,
1573       GST_BUFFER_TIMESTAMP (buffer));
1574
1575   /* a GstValidatePadMonitor parent must be a GstValidateElementMonitor */
1576   if (PAD_PARENT_IS_DECODER (parent)) {
1577     /* should not push out of segment data */
1578     if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer)) &&
1579         GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer)) &&
1580         !gst_segment_clip (&monitor->segment, monitor->segment.format,
1581             GST_BUFFER_TIMESTAMP (buffer), GST_BUFFER_TIMESTAMP (buffer) +
1582             GST_BUFFER_DURATION (buffer), NULL, NULL)) {
1583       /* TODO is this a timestamp issue? */
1584       GST_VALIDATE_REPORT (monitor, BUFFER_IS_OUT_OF_SEGMENT,
1585           "buffer is out of segment and shouldn't be pushed. Timestamp: %"
1586           GST_TIME_FORMAT " - duration: %" GST_TIME_FORMAT ". Range: %"
1587           GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
1588           GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
1589           GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)),
1590           GST_TIME_ARGS (monitor->segment.start),
1591           GST_TIME_ARGS (monitor->segment.stop));
1592     }
1593   }
1594
1595   GST_VALIDATE_MONITOR_UNLOCK (monitor);
1596   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (monitor);
1597   gst_validate_pad_monitor_buffer_probe_overrides (monitor, buffer);
1598   return TRUE;
1599 }
1600
1601 static gboolean
1602 gst_validate_pad_monitor_event_probe (GstPad * pad, GstEvent * event,
1603     gpointer udata)
1604 {
1605   GstValidatePadMonitor *monitor = GST_VALIDATE_PAD_MONITOR_CAST (udata);
1606   gboolean ret;
1607
1608   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor);
1609   GST_VALIDATE_MONITOR_LOCK (monitor);
1610
1611   GST_DEBUG_OBJECT (pad, "event %p %s", event, GST_EVENT_TYPE_NAME (event));
1612
1613   if (GST_EVENT_IS_SERIALIZED (event)) {
1614     gint i;
1615
1616     /* Detect if events the element received are being forwarded in the same order
1617      *
1618      * Several scenarios:
1619      * 1) The element pushes the event as-is
1620      * 2) The element consumes the event and does not forward it
1621      * 3) The element consumes the event and creates another one instead
1622      * 4) The element pushes other serialized event before pushing out the
1623      *    one it received
1624      *
1625      * For each pad we have two lists to track serialized events:
1626      *  1) We received on input and expect to see (serialized_events)
1627      *  2) We received on input but don't expect to see (expired_events)
1628      *
1629      * To detect events that are pushed in a different order from the one they were
1630      * received in we check that:
1631      *
1632      * For each event being outputted:
1633      *   If it is in the expired_events list:
1634      *     RAISE WARNING
1635      *   If it is in the serialized_events list:
1636      *     If there are other events that were received before:
1637      *        Put those events on the expired_events list
1638      *     Remove that event and any previous ones from the serialized_events list
1639      *
1640      * Clear expired events list when flushing or on pad deactivation
1641      *
1642      */
1643
1644     if (g_list_find (monitor->expired_events, event)) {
1645       /* If it's the expired events, we've failed */
1646       GST_WARNING_OBJECT (pad, "Did not expect event %p %s", event,
1647           GST_EVENT_TYPE_NAME (event));
1648       GST_VALIDATE_REPORT (monitor, EVENT_SERIALIZED_OUT_OF_ORDER,
1649           "Serialized event was pushed out of order: %" GST_PTR_FORMAT, event);
1650       monitor->expired_events =
1651           g_list_remove (monitor->expired_events, monitor);
1652     } else if (monitor->serialized_events->len) {
1653       for (i = 0; i < monitor->serialized_events->len; i++) {
1654         SerializedEventData *next_event =
1655             g_ptr_array_index (monitor->serialized_events, i);
1656         GST_DEBUG_OBJECT (pad, "Checking against stored event #%d: %p %s", i,
1657             next_event->event, GST_EVENT_TYPE_NAME (next_event->event));
1658
1659         if (event == next_event->event
1660             || GST_EVENT_TYPE (event) == GST_EVENT_TYPE (next_event->event)) {
1661           /* We have found our event */
1662           GST_DEBUG_OBJECT (pad, "Found matching event");
1663
1664           while (monitor->serialized_events->len > i
1665               && GST_EVENT_TYPE (event) == GST_EVENT_TYPE (next_event->event)) {
1666             /* Swallow all expected events of the same type */
1667             g_ptr_array_remove_index (monitor->serialized_events, i);
1668             next_event = g_ptr_array_index (monitor->serialized_events, i);
1669           }
1670
1671           /* Move all previous events to expired events */
1672           if (G_UNLIKELY (i > 0)) {
1673             GST_DEBUG_OBJECT (pad,
1674                 "Moving previous expected events to expired list");
1675             while (i--) {
1676               next_event = g_ptr_array_index (monitor->serialized_events, 0);
1677               monitor->expired_events =
1678                   g_list_append (monitor->expired_events, next_event->event);
1679               g_ptr_array_remove_index (monitor->serialized_events, 0);
1680             }
1681           }
1682           debug_pending_event (pad, monitor->serialized_events);
1683           break;
1684         }
1685       }
1686     }
1687   }
1688
1689   /* This so far is just like an event that is flowing downstream,
1690    * so we do the same checks as a sinkpad event handler */
1691   ret =
1692       gst_validate_pad_monitor_downstream_event_check (monitor, NULL, event,
1693       NULL);
1694   GST_VALIDATE_MONITOR_UNLOCK (monitor);
1695   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (monitor);
1696
1697   return ret;
1698 }
1699
1700 static GstPadProbeReturn
1701 gst_validate_pad_monitor_pad_probe (GstPad * pad, GstPadProbeInfo * info,
1702     gpointer udata)
1703 {
1704   if (info->type & GST_PAD_PROBE_TYPE_BUFFER)
1705     gst_validate_pad_monitor_buffer_probe (pad, info->data, udata);
1706   else if (info->type & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM)
1707     gst_validate_pad_monitor_event_probe (pad, info->data, udata);
1708
1709   return GST_PAD_PROBE_OK;
1710 }
1711
1712 static void
1713 gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor,
1714     GstCaps * caps)
1715 {
1716   GstStructure *structure;
1717
1718   /* Check if caps are identical to last caps and complain if so */
1719   if (pad_monitor->last_caps
1720       && gst_caps_is_equal (caps, pad_monitor->last_caps)) {
1721     GST_VALIDATE_REPORT (pad_monitor, EVENT_CAPS_DUPLICATE, "%" GST_PTR_FORMAT,
1722         caps);
1723   }
1724
1725   gst_validate_pad_monitor_check_caps_complete (pad_monitor, caps);
1726
1727   if (caps) {
1728     structure = gst_caps_get_structure (caps, 0);
1729     if (gst_structure_n_fields (pad_monitor->pending_setcaps_fields)) {
1730       gint i;
1731       for (i = 0;
1732           i < gst_structure_n_fields (pad_monitor->pending_setcaps_fields);
1733           i++) {
1734         const gchar *name =
1735             gst_structure_nth_field_name (pad_monitor->pending_setcaps_fields,
1736             i);
1737         const GValue *v = gst_structure_get_value (structure, name);
1738         const GValue *otherv =
1739             gst_structure_get_value (pad_monitor->pending_setcaps_fields, name);
1740
1741         if (v == NULL) {
1742           GST_VALIDATE_REPORT (pad_monitor, CAPS_EXPECTED_FIELD_NOT_FOUND,
1743               "Field %s is missing from setcaps caps '%" GST_PTR_FORMAT "'",
1744               name, caps);
1745         } else if (gst_value_compare (v, otherv) != GST_VALUE_EQUAL) {
1746           GST_VALIDATE_REPORT (pad_monitor, CAPS_FIELD_UNEXPECTED_VALUE,
1747               "Field %s from setcaps caps '%" GST_PTR_FORMAT "' is different "
1748               "from expected value in caps '%" GST_PTR_FORMAT "'", name, caps,
1749               pad_monitor->pending_setcaps_fields);
1750         }
1751       }
1752     }
1753
1754     if (gst_validate_pad_monitor_pad_should_proxy_othercaps (pad_monitor)) {
1755       if (_structure_is_video (structure)) {
1756         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
1757             structure, "width");
1758         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
1759             structure, "height");
1760         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
1761             structure, "framerate");
1762         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
1763             structure, "pixel-aspect-ratio");
1764       } else if (_structure_is_audio (structure)) {
1765         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
1766             structure, "rate");
1767         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
1768             structure, "channels");
1769       }
1770     }
1771   }
1772
1773   gst_structure_free (pad_monitor->pending_setcaps_fields);
1774   pad_monitor->pending_setcaps_fields =
1775       gst_structure_new_empty (PENDING_FIELDS);
1776
1777   gst_validate_pad_monitor_setcaps_overrides (pad_monitor, caps);
1778 }
1779
1780 static void
1781 gst_validate_pad_monitor_setcaps_post (GstValidatePadMonitor * pad_monitor,
1782     GstCaps * caps, gboolean ret)
1783 {
1784   if (!ret)
1785     gst_validate_pad_monitor_otherpad_clear_pending_fields (pad_monitor);
1786   else {
1787     if (pad_monitor->last_caps) {
1788       gst_caps_unref (pad_monitor->last_caps);
1789     }
1790     pad_monitor->last_caps = gst_caps_ref (caps);
1791   }
1792 }
1793
1794 static gboolean
1795 gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor)
1796 {
1797   GstValidatePadMonitor *pad_monitor = GST_VALIDATE_PAD_MONITOR_CAST (monitor);
1798   GstPad *pad;
1799   if (!GST_IS_PAD (GST_VALIDATE_MONITOR_GET_OBJECT (monitor))) {
1800     GST_WARNING_OBJECT (monitor, "Trying to create pad monitor with other "
1801         "type of object");
1802     return FALSE;
1803   }
1804
1805   pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor);
1806
1807   if (g_object_get_data ((GObject *) pad, "qa-monitor")) {
1808     GST_WARNING_OBJECT (pad_monitor, "Pad already has a qa-monitor associated");
1809     return FALSE;
1810   }
1811
1812   g_object_set_data ((GObject *) pad, "qa-monitor", pad_monitor);
1813
1814   pad_monitor->pad = pad;
1815
1816   pad_monitor->event_func = GST_PAD_EVENTFUNC (pad);
1817   pad_monitor->query_func = GST_PAD_QUERYFUNC (pad);
1818   pad_monitor->activatemode_func = GST_PAD_ACTIVATEMODEFUNC (pad);
1819   if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
1820
1821     pad_monitor->chain_func = GST_PAD_CHAINFUNC (pad);
1822     if (pad_monitor->chain_func)
1823       gst_pad_set_chain_function (pad, gst_validate_pad_monitor_chain_func);
1824
1825     gst_pad_set_event_function (pad, gst_validate_pad_monitor_sink_event_func);
1826   } else {
1827     pad_monitor->getrange_func = GST_PAD_GETRANGEFUNC (pad);
1828     if (pad_monitor->getrange_func)
1829       gst_pad_set_getrange_function (pad, gst_validate_pad_get_range_func);
1830
1831     gst_pad_set_event_function (pad, gst_validate_pad_monitor_src_event_func);
1832
1833     /* add buffer/event probes */
1834     pad_monitor->pad_probe_id =
1835         gst_pad_add_probe (pad,
1836         GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM |
1837         GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1838         (GstPadProbeCallback) gst_validate_pad_monitor_pad_probe, pad_monitor,
1839         NULL);
1840   }
1841   gst_pad_set_query_function (pad, gst_validate_pad_monitor_query_func);
1842   gst_pad_set_activatemode_function (pad,
1843       gst_validate_pad_monitor_activatemode_func);
1844
1845   gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (monitor),
1846       g_strdup_printf ("%s:%s", GST_DEBUG_PAD_NAME (pad)));
1847
1848   if (G_UNLIKELY (GST_PAD_PARENT (pad) == NULL))
1849     GST_FIXME ("Saw a pad not belonging to any object");
1850
1851   return TRUE;
1852 }