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