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