validate: Also monitor ghost pads
[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-pipeline-monitor.h"
32 #include "gst-validate-reporter.h"
33 #include "gst-validate-utils.h"
34 #include "validate.h"
35 #include <string.h>
36 #include <stdarg.h>
37
38 /**
39  * SECTION:gst-validate-pad-monitor
40  * @short_description: Class that wraps a #GstPad for Validate checks
41  *
42  * TODO
43  */
44 #define _GET_PAD_MONITOR(p) g_object_get_qdata ((GObject*) p, _Q_VALIDATE_MONITOR)
45 #define _SET_PAD_MONITOR(p,d) g_object_set_qdata ((GObject*) p, _Q_VALIDATE_MONITOR, d)
46
47 static GstValidateInterceptionReturn
48 gst_validate_pad_monitor_intercept_report (GstValidateReporter * reporter,
49     GstValidateReport * report);
50
51 #define _do_init \
52   G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, _reporter_iface_init)
53
54 static void
55 _reporter_iface_init (GstValidateReporterInterface * iface)
56 {
57   iface->intercept_report = gst_validate_pad_monitor_intercept_report;
58 }
59
60 #define gst_validate_pad_monitor_parent_class parent_class
61 G_DEFINE_TYPE_WITH_CODE (GstValidatePadMonitor, gst_validate_pad_monitor,
62     GST_TYPE_VALIDATE_MONITOR, _do_init);
63
64 #define PENDING_FIELDS "pending-fields"
65 #define AUDIO_TIMESTAMP_TOLERANCE (GST_MSECOND * 100)
66
67 #define PAD_PARENT_IS_DEMUXER(m) \
68     (GST_VALIDATE_MONITOR_GET_PARENT(m) ? \
69         GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DEMUXER ( \
70             GST_VALIDATE_MONITOR_GET_PARENT(m)) : \
71         FALSE)
72
73 #define PAD_PARENT_IS_DECODER(m) \
74     (GST_VALIDATE_MONITOR_GET_PARENT(m) ? \
75         GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DECODER ( \
76             GST_VALIDATE_MONITOR_GET_PARENT(m)) : \
77         FALSE)
78
79 #define PAD_PARENT_IS_ENCODER(m) \
80     (GST_VALIDATE_MONITOR_GET_PARENT(m) ? \
81         GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_ENCODER ( \
82             GST_VALIDATE_MONITOR_GET_PARENT(m)) : \
83         FALSE)
84
85
86 /*
87  * Locking the parent should always be done before locking the
88  * pad-monitor to prevent deadlocks in case another monitor from
89  * another pad on the same element starts an operation that also
90  * requires locking itself and some other monitors from internally
91  * linked pads.
92  *
93  * An example:
94  * An element has a sink and a src pad. Some test starts running at sinkpad
95  * and it locks the parent, and then it locks itself. In case it needs to get
96  * some information from the srcpad, it is able to lock the srcpad and get it
97  * because the srcpad should never lock itself before locking the parent (which
98  * it won't be able as sinkpad already locked it).
99  *
100  * As a side one, it is possible that srcpad locks itself without locking the
101  * parent in case it wants to do a check that won't need to use other internally
102  * linked pads (sinkpad). But in this case it might lock and unlock freely without
103  * causing deadlocks.
104  */
105 #define GST_VALIDATE_PAD_MONITOR_PARENT_LOCK(m)                  \
106 G_STMT_START {                                             \
107   if (G_LIKELY (GST_VALIDATE_MONITOR_GET_PARENT (m))) {          \
108     GST_VALIDATE_MONITOR_LOCK (GST_VALIDATE_MONITOR_GET_PARENT (m));   \
109   } else {                                                 \
110     GST_WARNING_OBJECT (m, "No parent found, can't lock"); \
111   }                                                        \
112 } G_STMT_END
113
114 #define GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK(m)                  \
115 G_STMT_START {                                               \
116   if (G_LIKELY (GST_VALIDATE_MONITOR_GET_PARENT (m))) {            \
117     GST_VALIDATE_MONITOR_UNLOCK (GST_VALIDATE_MONITOR_GET_PARENT (m));   \
118   } else {                                                   \
119     GST_WARNING_OBJECT (m, "No parent found, can't unlock"); \
120   }                                                          \
121 } G_STMT_END
122
123 typedef struct
124 {
125   GstClockTime timestamp;
126   GstEvent *event;
127 } SerializedEventData;
128
129 static GstPad *
130 _get_actual_pad (GstPad * pad)
131 {
132   pad = gst_object_ref (pad);
133
134   while (GST_IS_PROXY_PAD (pad)) {
135     GstPad *next_pad;
136
137     if (GST_PAD_IS_SINK (pad)) {
138       if (GST_IS_GHOST_PAD (pad))
139         next_pad = gst_ghost_pad_get_target (GST_GHOST_PAD (pad));
140       else
141         next_pad = GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (pad)));
142     } else {
143       next_pad = gst_pad_get_peer (pad);
144     }
145
146     gst_object_unref (pad);
147     if (!next_pad)
148       return NULL;
149
150     pad = next_pad;
151   }
152
153   return pad;
154 }
155
156 static gboolean
157 _find_master_report_on_pad (GstPad * pad, GstValidateReport * report)
158 {
159   GstValidatePadMonitor *pad_monitor;
160   GstValidateReport *prev_report;
161   gboolean result = FALSE;
162   GstPad *tmppad = pad;
163
164   pad = _get_actual_pad (pad);
165   if (pad == NULL) {
166     GST_ERROR_OBJECT (tmppad, "Does not have a target yet");
167
168     return FALSE;
169   }
170
171   pad_monitor = _GET_PAD_MONITOR (pad);
172
173   /* For some reason this pad isn't monitored */
174   if (pad_monitor == NULL)
175     goto done;
176
177   prev_report = gst_validate_reporter_get_report ((GstValidateReporter *)
178       pad_monitor, report->issue->issue_id);
179
180   if (prev_report) {
181     if (prev_report->master_report)
182       result = gst_validate_report_set_master_report (report,
183           prev_report->master_report);
184     else
185       result = gst_validate_report_set_master_report (report, prev_report);
186   }
187
188 done:
189   gst_object_unref (pad);
190
191   return result;
192 }
193
194 static gboolean
195 _find_master_report_for_sink_pad (GstValidatePadMonitor * pad_monitor,
196     GstValidateReport * report)
197 {
198   GstPad *peerpad;
199   gboolean result = FALSE;
200   GstPad *pad =
201       GST_PAD_CAST (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
202           (pad_monitor)));
203
204   peerpad = gst_pad_get_peer (pad);
205   gst_object_unref (pad);
206
207   /* If the peer src pad already has a similar report no need to look
208    * any further */
209   if (peerpad && _find_master_report_on_pad (peerpad, report))
210     result = TRUE;
211
212   if (peerpad)
213     gst_object_unref (peerpad);
214
215   return result;
216 }
217
218 static gboolean
219 _find_master_report_for_src_pad (GstValidatePadMonitor * pad_monitor,
220     GstValidateReport * report)
221 {
222   GstIterator *iter;
223   gboolean done;
224   gboolean result = FALSE;
225   GstPad *target =
226       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
227           (pad_monitor)));
228
229   iter = gst_pad_iterate_internal_links (target);
230   done = FALSE;
231   while (!done) {
232     GValue value = { 0, };
233     switch (gst_iterator_next (iter, &value)) {
234       case GST_ITERATOR_OK:
235       {
236         GstPad *pad = g_value_get_object (&value);
237
238         if (_find_master_report_on_pad (pad, report)) {
239           result = TRUE;
240           done = TRUE;
241         }
242
243         g_value_reset (&value);
244         break;
245       }
246       case GST_ITERATOR_RESYNC:
247         gst_iterator_resync (iter);
248         break;
249       case GST_ITERATOR_ERROR:
250         GST_WARNING_OBJECT (target, "Internal links pad iteration error");
251         done = TRUE;
252         break;
253       case GST_ITERATOR_DONE:
254         done = TRUE;
255         break;
256     }
257   }
258   gst_object_unref (target);
259   gst_iterator_free (iter);
260
261   return result;
262 }
263
264 static GstValidateInterceptionReturn
265 _concatenate_issues (GstValidatePadMonitor * pad_monitor,
266     GstValidateReport * report)
267 {
268   GstPad *pad =
269       GST_PAD_CAST (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
270           (pad_monitor)));
271
272   if (GST_PAD_IS_SINK (pad)
273       && _find_master_report_for_sink_pad (pad_monitor, report)) {
274     gst_object_unref (pad);
275     return GST_VALIDATE_REPORTER_KEEP;
276   } else if (GST_PAD_IS_SRC (pad)
277       && _find_master_report_for_src_pad (pad_monitor, report)) {
278     gst_object_unref (pad);
279     return GST_VALIDATE_REPORTER_KEEP;
280   }
281
282   gst_object_unref (pad);
283   return GST_VALIDATE_REPORTER_REPORT;
284 }
285
286 static GstValidateInterceptionReturn
287 gst_validate_pad_monitor_intercept_report (GstValidateReporter *
288     reporter, GstValidateReport * report)
289 {
290   GstValidateReporterInterface *iface_class, *old_iface_class;
291   GstValidatePadMonitor *pad_monitor = GST_VALIDATE_PAD_MONITOR (reporter);
292   GstValidateReportingDetails monitor_reporting_level;
293   GstValidateInterceptionReturn ret;
294
295   monitor_reporting_level =
296       gst_validate_reporter_get_reporting_level (reporter);
297
298   iface_class =
299       G_TYPE_INSTANCE_GET_INTERFACE (reporter, GST_TYPE_VALIDATE_REPORTER,
300       GstValidateReporterInterface);
301   old_iface_class = g_type_interface_peek_parent (iface_class);
302
303   old_iface_class->intercept_report (reporter, report);
304
305   switch (monitor_reporting_level) {
306     case GST_VALIDATE_SHOW_NONE:
307       ret = GST_VALIDATE_REPORTER_DROP;
308       break;
309     case GST_VALIDATE_SHOW_UNKNOWN:
310       ret = _concatenate_issues (pad_monitor, report);
311       break;
312     default:
313       ret = GST_VALIDATE_REPORTER_REPORT;
314       break;
315   }
316
317   gst_validate_report_set_reporting_level (report, monitor_reporting_level);
318   return ret;
319 }
320
321 static void
322 debug_pending_event (GstPad * pad, GPtrArray * array)
323 {
324   guint i, len;
325
326   len = array->len;
327   for (i = 0; i < len; i++) {
328     SerializedEventData *data = g_ptr_array_index (array, i);
329     GST_DEBUG_OBJECT (pad, "event #%d %" GST_TIME_FORMAT " %s %p",
330         i, GST_TIME_ARGS (data->timestamp),
331         GST_EVENT_TYPE_NAME (data->event), data->event);
332   }
333 }
334
335 static void
336 _serialized_event_data_free (SerializedEventData * serialized_event)
337 {
338   gst_event_unref (serialized_event->event);
339   g_slice_free (SerializedEventData, serialized_event);
340 }
341
342 static gboolean gst_validate_pad_monitor_do_setup (GstValidateMonitor *
343     monitor);
344 static GstElement *gst_validate_pad_monitor_get_element (GstValidateMonitor *
345     monitor);
346 static void
347 gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor,
348     GstCaps * caps);
349 static void gst_validate_pad_monitor_setcaps_post (GstValidatePadMonitor *
350     pad_monitor, GstCaps * caps, gboolean ret);
351
352 #define PAD_IS_IN_PUSH_MODE(p) ((p)->mode == GST_PAD_MODE_PUSH)
353
354 static gboolean
355 _structure_is_raw_video (GstStructure * structure)
356 {
357   return gst_structure_has_name (structure, "video/x-raw");
358 }
359
360 static gboolean
361 _structure_is_raw_audio (GstStructure * structure)
362 {
363   return gst_structure_has_name (structure, "audio/x-raw");
364 }
365
366 static gchar *
367 _get_event_string (GstEvent * event)
368 {
369   const GstStructure *st;
370
371   if ((st = gst_event_get_structure (event)))
372     return gst_structure_to_string (st);
373   else
374     return g_strdup_printf ("%s", GST_EVENT_TYPE_NAME (event));
375 }
376
377 static void
378 _check_field_type (GstValidatePadMonitor * monitor,
379     GstStructure * structure, gboolean mandatory, const gchar * field, ...)
380 {
381   va_list var_args;
382   GType type;
383   gchar *joined_types = NULL;
384   const gchar *rejected_types[5];
385   gint rejected_types_index = 0;
386   gchar *struct_str;
387
388   if (!gst_structure_has_field (structure, field)) {
389     if (mandatory) {
390       gchar *str = gst_structure_to_string (structure);
391
392       GST_VALIDATE_REPORT (monitor, CAPS_IS_MISSING_FIELD,
393           "Field '%s' is missing from structure: %s", field, str);
394       g_free (str);
395     } else {
396       GST_DEBUG_OBJECT (monitor, "Field %s is missing but is not mandatory",
397           field);
398     }
399     return;
400   }
401
402   memset ((gchar **) rejected_types, 0, sizeof (rejected_types));
403   va_start (var_args, field);
404   while ((type = va_arg (var_args, GType)) != 0) {
405     if (gst_structure_has_field_typed (structure, field, type)) {
406       va_end (var_args);
407       return;
408     }
409     rejected_types[rejected_types_index++] = g_type_name (type);
410   }
411   va_end (var_args);
412
413   joined_types = g_strjoinv (" / ", (gchar **) rejected_types);
414   struct_str = gst_structure_to_string (structure);
415   GST_VALIDATE_REPORT (monitor, CAPS_FIELD_HAS_BAD_TYPE,
416       "Field '%s' has wrong type %s in structure '%s'. Expected: %s", field,
417       g_type_name (gst_structure_get_field_type (structure, field)), struct_str,
418       joined_types);
419   g_free (joined_types);
420   g_free (struct_str);
421 }
422
423 static void
424 gst_validate_pad_monitor_check_raw_video_caps_complete (GstValidatePadMonitor *
425     monitor, GstStructure * structure)
426 {
427   _check_field_type (monitor, structure, TRUE, "width", G_TYPE_INT,
428       GST_TYPE_INT_RANGE, 0);
429   _check_field_type (monitor, structure, TRUE, "height", G_TYPE_INT,
430       GST_TYPE_INT_RANGE, 0);
431   _check_field_type (monitor, structure, TRUE, "framerate", GST_TYPE_FRACTION,
432       GST_TYPE_FRACTION_RANGE, 0);
433   _check_field_type (monitor, structure, FALSE, "pixel-aspect-ratio",
434       GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE, 0);
435   _check_field_type (monitor, structure, TRUE, "format", G_TYPE_STRING,
436       GST_TYPE_LIST);
437 }
438
439 static void
440 gst_validate_pad_monitor_check_raw_audio_caps_complete (GstValidatePadMonitor *
441     monitor, GstStructure * structure)
442 {
443   gint channels;
444   _check_field_type (monitor, structure, TRUE, "format", G_TYPE_STRING,
445       GST_TYPE_LIST, 0);
446   _check_field_type (monitor, structure, TRUE, "layout", G_TYPE_STRING,
447       GST_TYPE_LIST, 0);
448   _check_field_type (monitor, structure, TRUE, "rate", G_TYPE_INT,
449       GST_TYPE_LIST, GST_TYPE_INT_RANGE, 0);
450   _check_field_type (monitor, structure, TRUE, "channels", G_TYPE_INT,
451       GST_TYPE_LIST, GST_TYPE_INT_RANGE, 0);
452   if (gst_structure_get_int (structure, "channels", &channels)) {
453     if (channels > 2)
454       _check_field_type (monitor, structure, TRUE, "channel-mask",
455           GST_TYPE_BITMASK, GST_TYPE_LIST, 0);
456   }
457 }
458
459 static void
460 gst_validate_pad_monitor_check_caps_complete (GstValidatePadMonitor * monitor,
461     GstCaps * caps)
462 {
463   GstStructure *structure;
464   gint i;
465
466   GST_DEBUG_OBJECT (monitor, "Checking caps %" GST_PTR_FORMAT, caps);
467
468   for (i = 0; i < gst_caps_get_size (caps); i++) {
469     structure = gst_caps_get_structure (caps, i);
470
471     if (_structure_is_raw_video (structure)) {
472       gst_validate_pad_monitor_check_raw_video_caps_complete (monitor,
473           structure);
474
475     } else if (_structure_is_raw_audio (structure)) {
476       gst_validate_pad_monitor_check_raw_audio_caps_complete (monitor,
477           structure);
478     }
479   }
480 }
481
482 static GstCaps *
483 gst_validate_pad_monitor_get_othercaps (GstValidatePadMonitor * monitor,
484     GstCaps * filter)
485 {
486   GstCaps *caps = gst_caps_new_empty ();
487   GstIterator *iter;
488   gboolean done;
489   GstPad *otherpad;
490   GstCaps *peercaps;
491   GstPad *pad =
492       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
493           (monitor)));
494
495   iter = gst_pad_iterate_internal_links (pad);
496   done = FALSE;
497   while (!done) {
498     GValue value = { 0, };
499     switch (gst_iterator_next (iter, &value)) {
500       case GST_ITERATOR_OK:
501         otherpad = g_value_get_object (&value);
502
503         /* TODO What would be the correct caps operation to merge the caps in
504          * case one sink is internally linked to multiple srcs? */
505         peercaps = gst_pad_peer_query_caps (otherpad, filter);
506         if (peercaps)
507           caps = gst_caps_merge (caps, peercaps);
508
509         g_value_reset (&value);
510         break;
511       case GST_ITERATOR_RESYNC:
512         gst_iterator_resync (iter);
513         gst_caps_unref (caps);
514         caps = gst_caps_new_empty ();
515         break;
516       case GST_ITERATOR_ERROR:
517         GST_WARNING_OBJECT (pad, "Internal links pad iteration error");
518         done = TRUE;
519         break;
520       case GST_ITERATOR_DONE:
521         done = TRUE;
522         break;
523     }
524   }
525   GST_DEBUG_OBJECT (pad, "Otherpad caps: %" GST_PTR_FORMAT, caps);
526
527   gst_iterator_free (iter);
528   gst_object_unref (pad);
529
530   return caps;
531 }
532
533 static gboolean
534 _structure_is_video (GstStructure * structure)
535 {
536   const gchar *name = gst_structure_get_name (structure);
537
538   return g_strstr_len (name, 6, "video/")
539       && g_strcmp0 (name, "video/quicktime") != 0;
540 }
541
542 static gboolean
543 _structure_is_audio (GstStructure * structure)
544 {
545   const gchar *name = gst_structure_get_name (structure);
546
547   return g_strstr_len (name, 6, "audio/") != NULL;
548 }
549
550 static gboolean
551 gst_validate_pad_monitor_pad_should_proxy_othercaps (GstValidatePadMonitor *
552     monitor)
553 {
554   GstValidateMonitor *parent = GST_VALIDATE_MONITOR_GET_PARENT (monitor);
555
556   if (!parent)
557     return FALSE;
558
559   /* We only know how to handle othercaps checks for codecs so far */
560   return (GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DECODER (parent) ||
561       GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_ENCODER (parent)) &&
562       !GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_CONVERTER (parent);
563 }
564
565
566 /* Check if the field @f from @s2 (if present) is represented in @s1
567  * Represented here means either equal or @s1's value is in a list/range
568  * from @s2
569  */
570 static gboolean
571 _structures_field_is_contained (GstStructure * s1, GstStructure * s2,
572     gboolean mandatory, const gchar * f)
573 {
574   const GValue *v1;
575   const GValue *v2;
576
577   v2 = gst_structure_get_value (s2, f);
578   if (!v2)
579     return TRUE;                /* nothing to compare to */
580
581   v1 = gst_structure_get_value (s1, f);
582   if (!v1)
583     return !mandatory;
584
585   if (!gst_value_is_fixed (v1))
586     return TRUE;
587
588   if (gst_value_compare (v1, v2) == GST_VALUE_EQUAL)
589     return TRUE;
590
591   if (GST_VALUE_HOLDS_LIST (v2)) {
592     gint i;
593     for (i = 0; i < gst_value_list_get_size (v2); i++) {
594       const GValue *v2_subvalue = gst_value_list_get_value (v2, i);
595       if (gst_value_compare (v1, v2_subvalue) == GST_VALUE_EQUAL)
596         return TRUE;
597     }
598   }
599
600   if (GST_VALUE_HOLDS_ARRAY (v2)) {
601     gint i;
602     for (i = 0; i < gst_value_array_get_size (v2); i++) {
603       const GValue *v2_subvalue = gst_value_array_get_value (v2, i);
604       if (gst_value_compare (v1, v2_subvalue) == GST_VALUE_EQUAL)
605         return TRUE;
606     }
607   }
608
609   if (GST_VALUE_HOLDS_INT_RANGE (v2)) {
610     gint min, max;
611
612     min = gst_value_get_int_range_min (v2);
613     max = gst_value_get_int_range_max (v2);
614
615     if (G_VALUE_HOLDS_INT (v1)) {
616       gint v = g_value_get_int (v1);
617
618       return v >= min && v <= max;
619     } else {
620       /* TODO compare int ranges with int ranges
621        * or with lists if useful */
622     }
623   }
624
625   if (GST_VALUE_HOLDS_FRACTION_RANGE (v2)) {
626     const GValue *min, *max;
627
628     min = gst_value_get_fraction_range_min (v2);
629     max = gst_value_get_fraction_range_max (v2);
630
631     if (GST_VALUE_HOLDS_FRACTION (v1)) {
632       gint v_min = gst_value_compare (v1, min);
633       gint v_max = gst_value_compare (v1, max);
634
635       return (v_min == GST_VALUE_EQUAL || v_min == GST_VALUE_GREATER_THAN) &&
636           (v_max == GST_VALUE_EQUAL || v_max == GST_VALUE_LESS_THAN);
637     } else {
638       /* TODO compare fraction ranges with fraction ranges
639        * or with lists if useful */
640     }
641   }
642
643   return FALSE;
644 }
645
646 static void
647 _check_and_copy_structure_field (GstStructure * from, GstStructure * to,
648     const gchar * name)
649 {
650   if (gst_structure_has_field (from, name)) {
651     gst_structure_set_value (to, name, gst_structure_get_value (from, name));
652   }
653 }
654
655 static GstCaps *
656 gst_validate_pad_monitor_copy_caps_fields_into_caps (GstValidatePadMonitor *
657     monitor, GstCaps * from_caps, GstCaps * into_caps)
658 {
659   gint i, j, into_size, from_size;
660   GstStructure *structure;
661   GstCaps *res = gst_caps_new_empty ();
662
663   into_size = gst_caps_get_size (into_caps);
664   from_size = gst_caps_get_size (from_caps);
665
666   for (i = 0; i < into_size; i++) {
667     GstStructure *s = gst_caps_get_structure (into_caps, i);
668
669     for (j = 0; j < from_size; j++) {
670       GstStructure *new_structure = gst_structure_copy (s);
671
672       structure = gst_caps_get_structure (from_caps, j);
673       if (_structure_is_video (structure)) {
674         _check_and_copy_structure_field (structure, new_structure, "width");
675         _check_and_copy_structure_field (structure, new_structure, "height");
676         _check_and_copy_structure_field (structure, new_structure, "framerate");
677         _check_and_copy_structure_field (structure, new_structure,
678             "pixel-aspect-ratio");
679       } else if (_structure_is_audio (s)) {
680         _check_and_copy_structure_field (structure, new_structure, "rate");
681         _check_and_copy_structure_field (structure, new_structure, "channels");
682       }
683
684       gst_caps_append_structure (res, new_structure);
685     }
686   }
687   return res;
688 }
689
690 static GstCaps *
691 gst_validate_pad_monitor_transform_caps (GstValidatePadMonitor * monitor,
692     GstCaps * caps)
693 {
694   GstCaps *othercaps;
695   GstCaps *new_caps;
696   GstIterator *iter;
697   gboolean done;
698   GstPad *otherpad;
699   GstCaps *template_caps;
700   GstPad *pad;
701
702
703   GST_DEBUG_OBJECT (monitor, "Transform caps %" GST_PTR_FORMAT, caps);
704
705   if (caps == NULL)
706     return NULL;
707
708   othercaps = gst_caps_new_empty ();
709
710   pad =
711       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
712           (monitor)));
713   iter = gst_pad_iterate_internal_links (pad);
714   done = FALSE;
715   while (!done) {
716     GValue value = { 0, };
717     switch (gst_iterator_next (iter, &value)) {
718       case GST_ITERATOR_OK:
719         otherpad = g_value_get_object (&value);
720         template_caps = gst_pad_get_pad_template_caps (otherpad);
721
722         new_caps =
723             gst_validate_pad_monitor_copy_caps_fields_into_caps (monitor, caps,
724             template_caps);
725         if (!gst_caps_is_empty (new_caps))
726           gst_caps_append (othercaps, new_caps);
727         else
728           gst_caps_unref (new_caps);
729
730         gst_caps_unref (template_caps);
731         g_value_reset (&value);
732         break;
733       case GST_ITERATOR_RESYNC:
734         gst_iterator_resync (iter);
735         gst_caps_unref (othercaps);
736         othercaps = gst_caps_new_empty ();
737         break;
738       case GST_ITERATOR_ERROR:
739         GST_WARNING_OBJECT (pad, "Internal links pad iteration error");
740         done = TRUE;
741         break;
742       case GST_ITERATOR_DONE:
743         done = TRUE;
744         break;
745     }
746   }
747   gst_iterator_free (iter);
748
749   GST_DEBUG_OBJECT (pad, "Transformed caps: %" GST_PTR_FORMAT, othercaps);
750   gst_object_unref (pad);
751
752   return othercaps;
753 }
754
755 static void
756 gst_validate_pad_monitor_check_caps_fields_proxied (GstValidatePadMonitor *
757     monitor, GstCaps * caps, GstCaps * filter)
758 {
759   GstStructure *structure;
760   GstStructure *otherstructure;
761   GstCaps *othercaps;
762   GstCaps *otherfilter;
763   gint i, j;
764
765   if (!gst_validate_pad_monitor_pad_should_proxy_othercaps (monitor))
766     return;
767
768   otherfilter = gst_validate_pad_monitor_transform_caps (monitor, filter);
769   othercaps = gst_validate_pad_monitor_get_othercaps (monitor, otherfilter);
770   if (otherfilter)
771     gst_caps_unref (otherfilter);
772
773   for (i = 0; i < gst_caps_get_size (othercaps); i++) {
774     gboolean found = FALSE;
775     gboolean type_match = FALSE;
776
777     otherstructure = gst_caps_get_structure (othercaps, i);
778
779     /* look for a proxied version of 'otherstructure' */
780     if (_structure_is_video (otherstructure)) {
781       for (j = 0; j < gst_caps_get_size (caps); j++) {
782         structure = gst_caps_get_structure (caps, j);
783         if (_structure_is_video (structure)) {
784           type_match = TRUE;
785           if (_structures_field_is_contained (structure, otherstructure, TRUE,
786                   "width")
787               && _structures_field_is_contained (structure, otherstructure,
788                   TRUE, "height")
789               && _structures_field_is_contained (structure, otherstructure,
790                   TRUE, "framerate")
791               && _structures_field_is_contained (structure, otherstructure,
792                   FALSE, "pixel-aspect-ratio")) {
793             found = TRUE;
794             break;
795           }
796         }
797       }
798     } else if (_structure_is_audio (otherstructure)) {
799       for (j = 0; j < gst_caps_get_size (caps); j++) {
800         structure = gst_caps_get_structure (caps, j);
801         if (_structure_is_audio (structure)) {
802           type_match = TRUE;
803           if (_structures_field_is_contained (structure, otherstructure, TRUE,
804                   "rate")
805               && _structures_field_is_contained (structure, otherstructure,
806                   TRUE, "channels")) {
807             found = TRUE;
808             break;
809           }
810         }
811       }
812     }
813
814     if (type_match && !found) {
815       gchar *otherstruct_str = gst_structure_to_string (otherstructure),
816           *caps_str = gst_caps_to_string (caps);
817
818       GST_VALIDATE_REPORT (monitor, GET_CAPS_NOT_PROXYING_FIELDS,
819           "Peer pad structure '%s' has no similar version "
820           "on pad's caps '%s'", otherstruct_str, caps_str);
821
822       g_free (otherstruct_str);
823       g_free (caps_str);
824     }
825   }
826
827   gst_caps_unref (othercaps);
828 }
829
830 static void
831 gst_validate_pad_monitor_check_late_serialized_events (GstValidatePadMonitor *
832     monitor, GstClockTime ts)
833 {
834   gint i;
835   GstPad *pad;
836
837   if (!GST_CLOCK_TIME_IS_VALID (ts))
838     return;
839
840   pad =
841       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
842           (monitor)));
843
844   GST_DEBUG_OBJECT (pad, "Timestamp to check %" GST_TIME_FORMAT,
845       GST_TIME_ARGS (ts));
846
847   for (i = 0; i < monitor->serialized_events->len; i++) {
848     SerializedEventData *data =
849         g_ptr_array_index (monitor->serialized_events, i);
850
851     GST_DEBUG_OBJECT (pad, "Event #%d (%s) ts: %" GST_TIME_FORMAT,
852         i, GST_EVENT_TYPE_NAME (data->event), GST_TIME_ARGS (data->timestamp));
853
854     if (GST_CLOCK_TIME_IS_VALID (data->timestamp) && data->timestamp < ts) {
855       gchar *event_str = _get_event_string (data->event);
856
857       GST_VALIDATE_REPORT (monitor, SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME,
858           "Serialized event %s wasn't pushed before expected timestamp %"
859           GST_TIME_FORMAT " on pad %s:%s", event_str,
860           GST_TIME_ARGS (data->timestamp), GST_DEBUG_PAD_NAME (pad));
861
862       g_free (event_str);
863     } else {
864       /* events should be ordered by ts */
865       break;
866     }
867   }
868
869   if (i) {
870     debug_pending_event (pad, monitor->serialized_events);
871     g_ptr_array_remove_range (monitor->serialized_events, 0, i);
872   }
873
874   gst_object_unref (pad);
875 }
876
877 static void
878 gst_validate_pad_monitor_dispose (GObject * object)
879 {
880   GstValidatePadMonitor *monitor = GST_VALIDATE_PAD_MONITOR_CAST (object);
881   GstPad *pad =
882       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
883           (monitor)));
884
885   if (pad) {
886     if (monitor->pad_probe_id)
887       gst_pad_remove_probe (pad, monitor->pad_probe_id);
888     gst_object_unref (pad);
889   }
890
891   if (monitor->expected_segment)
892     gst_event_unref (monitor->expected_segment);
893
894   gst_structure_free (monitor->pending_setcaps_fields);
895   g_ptr_array_unref (monitor->serialized_events);
896   g_list_free_full (monitor->expired_events, (GDestroyNotify) gst_event_unref);
897   g_list_free_full (monitor->all_bufs, (GDestroyNotify) gst_buffer_unref);
898   gst_caps_replace (&monitor->last_caps, NULL);
899   gst_caps_replace (&monitor->last_query_res, NULL);
900   gst_caps_replace (&monitor->last_query_filter, NULL);
901
902   G_OBJECT_CLASS (parent_class)->dispose (object);
903 }
904
905 static void
906 gst_validate_pad_monitor_class_init (GstValidatePadMonitorClass * klass)
907 {
908   GObjectClass *gobject_class;
909   GstValidateMonitorClass *monitor_klass;
910
911   gobject_class = G_OBJECT_CLASS (klass);
912   monitor_klass = GST_VALIDATE_MONITOR_CLASS (klass);
913
914   gobject_class->dispose = gst_validate_pad_monitor_dispose;
915
916   monitor_klass->setup = gst_validate_pad_monitor_do_setup;
917   monitor_klass->get_element = gst_validate_pad_monitor_get_element;
918 }
919
920 /* Called when a pad is being flushed */
921 static void
922 gst_validate_pad_monitor_flush (GstValidatePadMonitor * pad_monitor)
923 {
924   /* Note: Keep in the same order as in the GstValidatePadMonitor structure */
925
926   gst_caps_replace (&pad_monitor->last_caps, NULL);
927   pad_monitor->caps_is_audio = pad_monitor->caps_is_video =
928       pad_monitor->caps_is_raw = FALSE;
929
930   pad_monitor->first_buffer = TRUE;
931
932   pad_monitor->has_segment = FALSE;
933   pad_monitor->is_eos = FALSE;
934
935   pad_monitor->pending_buffer_discont = TRUE;
936
937   gst_event_replace (&pad_monitor->expected_segment, NULL);
938   if (pad_monitor->serialized_events->len)
939     g_ptr_array_remove_range (pad_monitor->serialized_events, 0,
940         pad_monitor->serialized_events->len);
941   g_list_free_full (pad_monitor->expired_events,
942       (GDestroyNotify) gst_event_unref);
943   pad_monitor->expired_events = NULL;
944
945   gst_segment_init (&pad_monitor->segment, GST_FORMAT_BYTES);
946   pad_monitor->current_timestamp = GST_CLOCK_TIME_NONE;
947   pad_monitor->current_duration = GST_CLOCK_TIME_NONE;
948
949   pad_monitor->last_flow_return = GST_FLOW_OK;
950
951   pad_monitor->timestamp_range_start = GST_CLOCK_TIME_NONE;
952   pad_monitor->timestamp_range_end = GST_CLOCK_TIME_NONE;
953 }
954
955 /* Called when the pad monitor is initialized or when
956  * the pad is deactivated */
957 static void
958 gst_validate_pad_monitor_reset (GstValidatePadMonitor * pad_monitor)
959 {
960   gst_validate_pad_monitor_flush (pad_monitor);
961
962   /* Note : For the entries that haven't been resetted in _flush(), do
963    * it here and keep in the same order as the GstValidatePadMonitor
964    * structure */
965
966   pad_monitor->pending_flush_stop = FALSE;
967   pad_monitor->pending_newsegment_seqnum = GST_SEQNUM_INVALID;
968   pad_monitor->pending_eos_seqnum = GST_SEQNUM_INVALID;
969
970   pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE;
971
972   if (pad_monitor->pending_setcaps_fields)
973     gst_structure_free (pad_monitor->pending_setcaps_fields);
974   pad_monitor->pending_setcaps_fields =
975       gst_structure_new_empty (PENDING_FIELDS);
976
977   /* FIXME : Why BYTES and not UNDEFINED ? */
978   gst_segment_init (&pad_monitor->segment, GST_FORMAT_BYTES);
979
980   pad_monitor->min_buf_freq = 0;
981   pad_monitor->buffers_pushed = 0;
982   pad_monitor->last_buffers_pushed = 0;
983   pad_monitor->min_buf_freq_interval_ts = GST_CLOCK_TIME_NONE;
984   pad_monitor->min_buf_freq_first_buffer_ts = GST_CLOCK_TIME_NONE;
985   pad_monitor->min_buf_freq_start = GST_CLOCK_TIME_NONE;
986 }
987
988 static void
989 gst_validate_pad_monitor_init (GstValidatePadMonitor * pad_monitor)
990 {
991   pad_monitor->serialized_events =
992       g_ptr_array_new_with_free_func ((GDestroyNotify)
993       _serialized_event_data_free);
994
995   gst_validate_pad_monitor_reset (pad_monitor);
996 }
997
998 /**
999  * gst_validate_pad_monitor_new:
1000  * @pad: (transfer none): a #GstPad to run Validate on
1001  */
1002 GstValidatePadMonitor *
1003 gst_validate_pad_monitor_new (GstPad * pad, GstValidateRunner * runner,
1004     GstValidateElementMonitor * parent)
1005 {
1006   GstValidatePadMonitor *monitor = g_object_new (GST_TYPE_VALIDATE_PAD_MONITOR,
1007       "object", pad, "validate-runner", runner, "validate-parent",
1008       parent, NULL);
1009   GstObject *target =
1010       gst_validate_monitor_get_target (GST_VALIDATE_MONITOR (monitor));
1011
1012   if (target == NULL) {
1013     g_object_unref (monitor);
1014     return NULL;
1015   }
1016
1017   gst_object_unref (target);
1018   return monitor;
1019 }
1020
1021 static GstElement *
1022 gst_validate_pad_monitor_get_element (GstValidateMonitor * monitor)
1023 {
1024   GstPad *pad =
1025       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1026           (monitor)));
1027   GstElement *parent = GST_ELEMENT (gst_pad_get_parent (pad));
1028
1029   gst_object_unref (pad);
1030
1031   return parent;
1032 }
1033
1034 static void
1035 gst_validate_pad_monitor_event_overrides (GstValidatePadMonitor * pad_monitor,
1036     GstEvent * event)
1037 {
1038   GList *iter;
1039
1040   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
1041   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
1042       iter = g_list_next (iter)) {
1043     GstValidateOverride *override = iter->data;
1044
1045     gst_validate_override_event_handler (override,
1046         GST_VALIDATE_MONITOR_CAST (pad_monitor), event);
1047   }
1048   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
1049 }
1050
1051 static void
1052 gst_validate_pad_monitor_buffer_overrides (GstValidatePadMonitor * pad_monitor,
1053     GstBuffer * buffer)
1054 {
1055   GList *iter;
1056
1057   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
1058   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
1059       iter = g_list_next (iter)) {
1060     GstValidateOverride *override = iter->data;
1061
1062     gst_validate_override_buffer_handler (override,
1063         GST_VALIDATE_MONITOR_CAST (pad_monitor), buffer);
1064   }
1065   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
1066 }
1067
1068 static void
1069 gst_validate_pad_monitor_buffer_probe_overrides (GstValidatePadMonitor *
1070     pad_monitor, GstBuffer * buffer)
1071 {
1072   GList *iter;
1073
1074   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
1075   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
1076       iter = g_list_next (iter)) {
1077     GstValidateOverride *override = iter->data;
1078
1079     gst_validate_override_buffer_probe_handler (override,
1080         GST_VALIDATE_MONITOR_CAST (pad_monitor), buffer);
1081   }
1082   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
1083 }
1084
1085 static void
1086 gst_validate_pad_monitor_query_overrides (GstValidatePadMonitor * pad_monitor,
1087     GstQuery * query)
1088 {
1089   GList *iter;
1090
1091   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
1092   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
1093       iter = g_list_next (iter)) {
1094     GstValidateOverride *override = iter->data;
1095
1096     gst_validate_override_query_handler (override,
1097         GST_VALIDATE_MONITOR_CAST (pad_monitor), query);
1098   }
1099   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
1100 }
1101
1102 static void
1103 gst_validate_pad_monitor_setcaps_overrides (GstValidatePadMonitor * pad_monitor,
1104     GstCaps * caps)
1105 {
1106   GList *iter;
1107
1108   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
1109   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
1110       iter = g_list_next (iter)) {
1111     GstValidateOverride *override = iter->data;
1112
1113     gst_validate_override_setcaps_handler (override,
1114         GST_VALIDATE_MONITOR_CAST (pad_monitor), caps);
1115   }
1116   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
1117 }
1118
1119 /* FIXME : This is a bit dubious, what's the point of this check ? */
1120 static gboolean
1121 gst_validate_pad_monitor_timestamp_is_in_received_range (GstValidatePadMonitor *
1122     monitor, GstClockTime ts, GstClockTime tolerance)
1123 {
1124   GstPad *pad =
1125       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1126           (monitor)));
1127
1128   GST_DEBUG_OBJECT (pad,
1129       "Checking if timestamp %" GST_TIME_FORMAT " is in range: %"
1130       GST_TIME_FORMAT " - %" GST_TIME_FORMAT " for pad "
1131       "%s:%s with tolerance: %" GST_TIME_FORMAT, GST_TIME_ARGS (ts),
1132       GST_TIME_ARGS (monitor->timestamp_range_start),
1133       GST_TIME_ARGS (monitor->timestamp_range_end), GST_DEBUG_PAD_NAME (pad),
1134       GST_TIME_ARGS (tolerance));
1135   gst_object_unref (pad);
1136
1137   return !GST_CLOCK_TIME_IS_VALID (monitor->timestamp_range_start) ||
1138       !GST_CLOCK_TIME_IS_VALID (monitor->timestamp_range_end) ||
1139       ((monitor->timestamp_range_start >= tolerance ?
1140           monitor->timestamp_range_start - tolerance : 0) <= ts
1141       && (ts >= tolerance ? ts - tolerance : 0) <=
1142       monitor->timestamp_range_end);
1143 }
1144
1145 /* Iterates over internal links (sinkpads) to check that this buffer has
1146  * a timestamp that is in the range of the lastly received buffers */
1147 static void
1148     gst_validate_pad_monitor_check_buffer_timestamp_in_received_range
1149     (GstValidatePadMonitor * monitor, GstBuffer * buffer,
1150     GstClockTime tolerance)
1151 {
1152   GstClockTime ts;
1153   GstClockTime ts_end;
1154   GstIterator *iter;
1155   gboolean has_one = FALSE;
1156   gboolean found = FALSE;
1157   gboolean done;
1158   GstPad *otherpad;
1159   GstValidatePadMonitor *othermonitor;
1160   GstPad *pad =
1161       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1162           (monitor)));
1163
1164   if (!GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))
1165       || !GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) {
1166     GST_DEBUG_OBJECT (pad,
1167         "Can't check buffer timestamps range as "
1168         "buffer has no valid timestamp/duration");
1169     goto done;
1170   }
1171
1172   ts = GST_BUFFER_TIMESTAMP (buffer);
1173   ts_end = ts + GST_BUFFER_DURATION (buffer);
1174
1175   iter = gst_pad_iterate_internal_links (pad);
1176
1177   if (iter == NULL) {
1178     GST_WARNING_OBJECT (pad, "No iterator available");
1179     goto done;
1180   }
1181
1182   done = FALSE;
1183   while (!done) {
1184     GValue value = { 0, };
1185     switch (gst_iterator_next (iter, &value)) {
1186       case GST_ITERATOR_OK:
1187         otherpad = g_value_get_object (&value);
1188         GST_DEBUG_OBJECT (pad, "Checking pad %s:%s input timestamps",
1189             GST_DEBUG_PAD_NAME (otherpad));
1190         othermonitor = _GET_PAD_MONITOR (otherpad);
1191         if (!othermonitor)
1192           continue;
1193
1194         GST_VALIDATE_MONITOR_LOCK (othermonitor);
1195         if (gst_validate_pad_monitor_timestamp_is_in_received_range
1196             (othermonitor, ts, tolerance)
1197             &&
1198             gst_validate_pad_monitor_timestamp_is_in_received_range
1199             (othermonitor, ts_end, tolerance)) {
1200           done = TRUE;
1201           found = TRUE;
1202         }
1203         GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1204         g_value_reset (&value);
1205         has_one = TRUE;
1206         break;
1207       case GST_ITERATOR_RESYNC:
1208         gst_iterator_resync (iter);
1209         has_one = FALSE;
1210         found = FALSE;
1211         break;
1212       case GST_ITERATOR_ERROR:
1213         GST_WARNING_OBJECT (pad, "Internal links pad iteration error");
1214         done = TRUE;
1215         break;
1216       case GST_ITERATOR_DONE:
1217         done = TRUE;
1218         break;
1219     }
1220   }
1221   gst_iterator_free (iter);
1222
1223   if (!has_one) {
1224     GST_DEBUG_OBJECT (pad, "Skipping timestamp in range check as no "
1225         "internal linked pad was found");
1226     goto done;
1227   }
1228   if (!found) {
1229     GST_VALIDATE_REPORT (monitor, BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE,
1230         "Timestamp %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT
1231         " is out of range of received input", GST_TIME_ARGS (ts),
1232         GST_TIME_ARGS (ts_end));
1233   }
1234 done:
1235   if (pad)
1236     gst_object_unref (pad);
1237 }
1238
1239 static void
1240 gst_validate_pad_monitor_check_discont (GstValidatePadMonitor * pad_monitor,
1241     GstBuffer * buffer)
1242 {
1243   if (pad_monitor->pending_buffer_discont) {
1244     if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT))
1245       GST_VALIDATE_REPORT (pad_monitor, BUFFER_MISSING_DISCONT,
1246           "Buffer is missing a DISCONT flag");
1247     pad_monitor->pending_buffer_discont = FALSE;
1248   }
1249 }
1250
1251 static void
1252 gst_validate_pad_monitor_check_first_buffer (GstValidatePadMonitor *
1253     pad_monitor, GstBuffer * buffer)
1254 {
1255   GstPad *pad =
1256       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1257           (pad_monitor)));
1258
1259   if (G_UNLIKELY (pad_monitor->first_buffer)) {
1260     pad_monitor->first_buffer = FALSE;
1261
1262     if (!pad_monitor->has_segment && PAD_IS_IN_PUSH_MODE (pad)) {
1263       GST_VALIDATE_REPORT (pad_monitor, BUFFER_BEFORE_SEGMENT,
1264           "Received buffer before Segment event");
1265     }
1266
1267     GST_DEBUG_OBJECT (pad,
1268         "Checking first buffer (pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
1269         ")", GST_TIME_ARGS (GST_BUFFER_PTS (buffer)),
1270         GST_TIME_ARGS (GST_BUFFER_DTS (buffer)));
1271
1272   }
1273
1274   gst_object_unref (pad);
1275 }
1276
1277 static void
1278 gst_validate_pad_monitor_check_eos (GstValidatePadMonitor *
1279     pad_monitor, GstBuffer * buffer)
1280 {
1281   if (G_UNLIKELY (pad_monitor->is_eos)) {
1282     GST_VALIDATE_REPORT (pad_monitor, BUFFER_AFTER_EOS,
1283         "Received buffer %" GST_PTR_FORMAT " after EOS", buffer);
1284   }
1285 }
1286
1287 static void
1288 gst_validate_pad_monitor_update_buffer_data (GstValidatePadMonitor *
1289     pad_monitor, GstBuffer * buffer)
1290 {
1291   GstPad *pad =
1292       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1293           (pad_monitor)));
1294   pad_monitor->current_timestamp = GST_BUFFER_TIMESTAMP (buffer);
1295   pad_monitor->current_duration = GST_BUFFER_DURATION (buffer);
1296   if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) {
1297     if (GST_CLOCK_TIME_IS_VALID (pad_monitor->timestamp_range_start)) {
1298       pad_monitor->timestamp_range_start =
1299           MIN (pad_monitor->timestamp_range_start,
1300           GST_BUFFER_TIMESTAMP (buffer));
1301     } else {
1302       pad_monitor->timestamp_range_start = GST_BUFFER_TIMESTAMP (buffer);
1303     }
1304
1305     if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) {
1306       GstClockTime endts =
1307           GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer);
1308       if (GST_CLOCK_TIME_IS_VALID (pad_monitor->timestamp_range_end)) {
1309         pad_monitor->timestamp_range_end =
1310             MAX (pad_monitor->timestamp_range_end, endts);
1311       } else {
1312         pad_monitor->timestamp_range_end = endts;
1313       }
1314     }
1315   }
1316   GST_DEBUG_OBJECT (pad, "Current stored range: %" GST_TIME_FORMAT
1317       " - %" GST_TIME_FORMAT,
1318       GST_TIME_ARGS (pad_monitor->timestamp_range_start),
1319       GST_TIME_ARGS (pad_monitor->timestamp_range_end));
1320
1321   gst_object_unref (pad);
1322 }
1323
1324 static GstFlowReturn
1325 _combine_flows (GstFlowReturn ret1, GstFlowReturn ret2)
1326 {
1327   if (ret1 == ret2)
1328     return ret1;
1329   if (ret1 <= GST_FLOW_NOT_NEGOTIATED)
1330     return ret1;
1331   if (ret2 <= GST_FLOW_NOT_NEGOTIATED)
1332     return ret2;
1333   if (ret1 == GST_FLOW_FLUSHING || ret2 == GST_FLOW_FLUSHING)
1334     return GST_FLOW_FLUSHING;
1335   if (ret1 == GST_FLOW_OK || ret2 == GST_FLOW_OK)
1336     return GST_FLOW_OK;
1337   return ret2;
1338 }
1339
1340 static void
1341 gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor *
1342     monitor, GstObject * parent, GstFlowReturn ret)
1343 {
1344   GstIterator *iter;
1345   gboolean done;
1346   GstPad *otherpad;
1347   GstPad *peerpad;
1348   GstState state, pending;
1349   GstValidatePadMonitor *othermonitor;
1350   GstFlowReturn aggregated = GST_FLOW_NOT_LINKED;
1351   gboolean found_a_pad = FALSE;
1352   GstPad *pad =
1353       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1354           (monitor)));
1355
1356   iter = gst_pad_iterate_internal_links (pad);
1357   done = FALSE;
1358   while (!done) {
1359     GValue value = { 0, };
1360     switch (gst_iterator_next (iter, &value)) {
1361       case GST_ITERATOR_OK:
1362         otherpad = g_value_get_object (&value);
1363         peerpad = gst_pad_get_peer (otherpad);
1364         if (peerpad) {
1365           othermonitor = _GET_PAD_MONITOR (peerpad);
1366           if (othermonitor) {
1367             found_a_pad = TRUE;
1368             GST_VALIDATE_MONITOR_LOCK (othermonitor);
1369             aggregated =
1370                 _combine_flows (aggregated, othermonitor->last_flow_return);
1371             GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1372           }
1373
1374           gst_object_unref (peerpad);
1375         }
1376         g_value_reset (&value);
1377         break;
1378       case GST_ITERATOR_RESYNC:
1379         gst_iterator_resync (iter);
1380         break;
1381       case GST_ITERATOR_ERROR:
1382         GST_WARNING_OBJECT (pad, "Internal links pad iteration error");
1383         done = TRUE;
1384         break;
1385       case GST_ITERATOR_DONE:
1386         done = TRUE;
1387         break;
1388     }
1389   }
1390   gst_iterator_free (iter);
1391   if (!found_a_pad) {
1392     /* no peer pad found, nothing to do */
1393     goto done;
1394   }
1395
1396   if (aggregated == GST_FLOW_FLUSHING) {
1397     gst_element_get_state (GST_ELEMENT (parent), &state, &pending, 0);
1398     if (state < GST_STATE_PAUSED || pending < GST_STATE_PAUSED) {
1399       /* Aggregated is flushing, we might have been aggregating a combination
1400        * of pads that are not what was present on the element during the actual
1401        * data flow combination (pads might have been removed meanwhile) */
1402
1403       goto done;
1404     }
1405   } else if (aggregated == GST_FLOW_OK || aggregated == GST_FLOW_EOS) {
1406
1407     /* those are acceptable situations */
1408     if (GST_PAD_IS_FLUSHING (pad) && ret == GST_FLOW_FLUSHING) {
1409       /* pad is flushing, always acceptable to return flushing */
1410       goto done;
1411     }
1412
1413     gst_element_get_state (GST_ELEMENT (parent), &state, &pending, 0);
1414     if (ret == GST_FLOW_FLUSHING && (state < GST_STATE_PAUSED
1415             || pending < GST_STATE_PAUSED)) {
1416       /* Element is being teared down, accept FLOW_FLUSHING */
1417
1418       goto done;
1419     }
1420
1421     if (monitor->is_eos && ret == GST_FLOW_EOS) {
1422       /* this element received eos and returned eos */
1423       goto done;
1424     }
1425
1426     if (PAD_PARENT_IS_DEMUXER (monitor) && ret == GST_FLOW_EOS) {
1427       /* a demuxer can return EOS when the samples end */
1428       goto done;
1429     }
1430   }
1431
1432   if (aggregated != ret) {
1433     GST_VALIDATE_REPORT (monitor, WRONG_FLOW_RETURN,
1434         "Wrong combined flow return %s(%d). Expected: %s(%d)",
1435         gst_flow_get_name (ret), ret, gst_flow_get_name (aggregated),
1436         aggregated);
1437   }
1438
1439 done:
1440   gst_object_unref (pad);
1441 }
1442
1443 static void
1444     gst_validate_pad_monitor_otherpad_add_pending_serialized_event
1445     (GstValidatePadMonitor * monitor, GstEvent * event, GstClockTime last_ts)
1446 {
1447   GstIterator *iter;
1448   gboolean done;
1449   GstPad *otherpad;
1450   GstValidatePadMonitor *othermonitor;
1451   GstPad *pad;
1452
1453
1454   if (!GST_EVENT_IS_SERIALIZED (event))
1455     return;
1456
1457   pad =
1458       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1459           (monitor)));
1460   iter = gst_pad_iterate_internal_links (pad);
1461   if (iter == NULL) {
1462     /* inputselector will return NULL if the sinkpad is not the active one .... */
1463     GST_FIXME_OBJECT (pad, "No iterator");
1464     gst_object_unref (pad);
1465     return;
1466   }
1467
1468   done = FALSE;
1469   while (!done) {
1470     GValue value = { 0, };
1471     switch (gst_iterator_next (iter, &value)) {
1472       case GST_ITERATOR_OK:
1473         otherpad = g_value_get_object (&value);
1474         othermonitor = _GET_PAD_MONITOR (otherpad);
1475         if (othermonitor) {
1476           SerializedEventData *data = g_slice_new0 (SerializedEventData);
1477           data->timestamp = last_ts;
1478           data->event = gst_event_ref (event);
1479           GST_VALIDATE_MONITOR_LOCK (othermonitor);
1480           GST_DEBUG_OBJECT (pad, "Storing for pad %s:%s event %p %s",
1481               GST_DEBUG_PAD_NAME (otherpad), event,
1482               GST_EVENT_TYPE_NAME (event));
1483           g_ptr_array_add (othermonitor->serialized_events, data);
1484           debug_pending_event (otherpad, othermonitor->serialized_events);
1485           GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1486         }
1487         g_value_reset (&value);
1488         break;
1489       case GST_ITERATOR_RESYNC:
1490         gst_iterator_resync (iter);
1491         break;
1492       case GST_ITERATOR_ERROR:
1493         GST_WARNING_OBJECT (pad, "Internal links pad iteration error");
1494         done = TRUE;
1495         break;
1496       case GST_ITERATOR_DONE:
1497         done = TRUE;
1498         break;
1499     }
1500   }
1501   gst_iterator_free (iter);
1502   gst_object_unref (pad);
1503 }
1504
1505 static void
1506 gst_validate_pad_monitor_otherpad_add_pending_field (GstValidatePadMonitor *
1507     monitor, GstStructure * structure, const gchar * field)
1508 {
1509   GstIterator *iter;
1510   gboolean done;
1511   GstPad *otherpad;
1512   GstValidatePadMonitor *othermonitor;
1513   const GValue *v;
1514   GstPad *pad;
1515
1516   v = gst_structure_get_value (structure, field);
1517   pad =
1518       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1519           (monitor)));
1520
1521   if (v == NULL) {
1522     GST_DEBUG_OBJECT (pad, "Not adding pending field %s as it isn't "
1523         "present on structure %" GST_PTR_FORMAT, field, structure);
1524     gst_object_unref (pad);
1525     return;
1526   }
1527
1528   iter = gst_pad_iterate_internal_links (pad);
1529   done = FALSE;
1530   while (!done) {
1531     GValue value = { 0, };
1532     switch (gst_iterator_next (iter, &value)) {
1533       case GST_ITERATOR_OK:
1534         otherpad = g_value_get_object (&value);
1535         othermonitor = _GET_PAD_MONITOR (otherpad);
1536         if (othermonitor) {
1537           GST_VALIDATE_MONITOR_LOCK (othermonitor);
1538           g_assert (othermonitor->pending_setcaps_fields != NULL);
1539           gst_structure_set_value (othermonitor->pending_setcaps_fields,
1540               field, v);
1541           GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1542         }
1543         g_value_reset (&value);
1544         break;
1545       case GST_ITERATOR_RESYNC:
1546         gst_iterator_resync (iter);
1547         break;
1548       case GST_ITERATOR_ERROR:
1549         GST_WARNING_OBJECT (pad, "Internal links pad iteration error");
1550         done = TRUE;
1551         break;
1552       case GST_ITERATOR_DONE:
1553         done = TRUE;
1554         break;
1555     }
1556   }
1557   gst_iterator_free (iter);
1558   gst_object_unref (pad);
1559 }
1560
1561 static void
1562 gst_validate_pad_monitor_otherpad_clear_pending_fields (GstValidatePadMonitor *
1563     monitor)
1564 {
1565   GstIterator *iter;
1566   gboolean done;
1567   GstPad *otherpad;
1568   GstValidatePadMonitor *othermonitor;
1569
1570   GstPad *pad =
1571       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1572           (monitor)));
1573
1574   iter = gst_pad_iterate_internal_links (pad);
1575   if (iter == NULL) {
1576     gst_object_unref (pad);
1577     GST_DEBUG_OBJECT (monitor, "No internally linked pad");
1578
1579     return;
1580   }
1581
1582   done = FALSE;
1583   while (!done) {
1584     GValue value = { 0, };
1585     switch (gst_iterator_next (iter, &value)) {
1586       case GST_ITERATOR_OK:
1587         otherpad = g_value_get_object (&value);
1588         othermonitor = _GET_PAD_MONITOR (otherpad);
1589         if (othermonitor) {
1590           GST_VALIDATE_MONITOR_LOCK (othermonitor);
1591           g_assert (othermonitor->pending_setcaps_fields != NULL);
1592           gst_structure_free (othermonitor->pending_setcaps_fields);
1593           othermonitor->pending_setcaps_fields =
1594               gst_structure_new_empty (PENDING_FIELDS);
1595           GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1596         }
1597         g_value_reset (&value);
1598         break;
1599       case GST_ITERATOR_RESYNC:
1600         gst_iterator_resync (iter);
1601         break;
1602       case GST_ITERATOR_ERROR:
1603         GST_WARNING_OBJECT (pad, "Internal links pad iteration error");
1604         done = TRUE;
1605         break;
1606       case GST_ITERATOR_DONE:
1607         done = TRUE;
1608         break;
1609     }
1610   }
1611   gst_object_unref (pad);
1612   gst_iterator_free (iter);
1613 }
1614
1615 static void
1616 gst_validate_pad_monitor_add_expected_newsegment (GstValidatePadMonitor *
1617     monitor, GstEvent * event)
1618 {
1619   GstIterator *iter;
1620   gboolean done;
1621   GstPad *otherpad;
1622   GstValidatePadMonitor *othermonitor;
1623   GstPad *pad =
1624       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1625           (monitor)));
1626
1627   iter = gst_pad_iterate_internal_links (pad);
1628   if (iter == NULL) {
1629     GST_DEBUG_OBJECT (monitor, "No internally linked pad");
1630     gst_object_unref (pad);
1631     return;
1632   }
1633
1634   done = FALSE;
1635   while (!done) {
1636     GValue value = { 0, };
1637     switch (gst_iterator_next (iter, &value)) {
1638       case GST_ITERATOR_OK:
1639         otherpad = g_value_get_object (&value);
1640         if (!otherpad)
1641           continue;
1642         othermonitor = _GET_PAD_MONITOR (otherpad);
1643         if (!othermonitor)
1644           continue;
1645         GST_VALIDATE_MONITOR_LOCK (othermonitor);
1646         gst_event_replace (&othermonitor->expected_segment, event);
1647         GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1648         g_value_reset (&value);
1649         break;
1650       case GST_ITERATOR_RESYNC:
1651         gst_iterator_resync (iter);
1652         break;
1653       case GST_ITERATOR_ERROR:
1654         GST_WARNING_OBJECT (pad, "Internal links pad iteration error");
1655         done = TRUE;
1656         break;
1657       case GST_ITERATOR_DONE:
1658         done = TRUE;
1659         break;
1660     }
1661   }
1662   gst_iterator_free (iter);
1663   gst_object_unref (pad);
1664 }
1665
1666 /* common checks for both sink and src event functions */
1667 static void
1668 gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor *
1669     pad_monitor, GstEvent * event)
1670 {
1671   guint32 seqnum = gst_event_get_seqnum (event);
1672
1673   if (seqnum == GST_SEQNUM_INVALID)
1674     GST_VALIDATE_REPORT (pad_monitor, EVENT_INVALID_SEQNUM,
1675         "Event %p (%s) has an invalid SEQNUM", event,
1676         GST_EVENT_TYPE_NAME (event));
1677
1678   switch (GST_EVENT_TYPE (event)) {
1679     case GST_EVENT_FLUSH_START:
1680     {
1681       if (pad_monitor->pending_flush_start_seqnum != GST_SEQNUM_INVALID) {
1682         if (seqnum == pad_monitor->pending_flush_start_seqnum) {
1683           pad_monitor->pending_flush_start_seqnum = GST_SEQNUM_INVALID;
1684         } else {
1685           GST_VALIDATE_REPORT (pad_monitor, FLUSH_START_HAS_WRONG_SEQNUM,
1686               "Got: %u Expected: %u", seqnum,
1687               pad_monitor->pending_flush_start_seqnum);
1688         }
1689       }
1690
1691       if (pad_monitor->pending_flush_stop) {
1692         GST_VALIDATE_REPORT (pad_monitor, EVENT_FLUSH_START_UNEXPECTED,
1693             "Received flush-start from when flush-stop was expected");
1694       }
1695       pad_monitor->pending_flush_stop = TRUE;
1696     }
1697       break;
1698     case GST_EVENT_FLUSH_STOP:
1699     {
1700       if (pad_monitor->pending_flush_stop_seqnum != GST_SEQNUM_INVALID) {
1701         if (seqnum == pad_monitor->pending_flush_stop_seqnum) {
1702           pad_monitor->pending_flush_stop_seqnum = GST_SEQNUM_INVALID;
1703         } else {
1704           GST_VALIDATE_REPORT (pad_monitor, FLUSH_STOP_HAS_WRONG_SEQNUM,
1705               "Got: %u Expected: %u", seqnum,
1706               pad_monitor->pending_flush_stop_seqnum);
1707         }
1708       }
1709
1710       pad_monitor->pending_newsegment_seqnum = seqnum;
1711       pad_monitor->pending_eos_seqnum = seqnum;
1712
1713       if (!pad_monitor->pending_flush_stop) {
1714         gchar *event_str = _get_event_string (event);
1715
1716         GST_VALIDATE_REPORT (pad_monitor, EVENT_FLUSH_STOP_UNEXPECTED,
1717             "Unexpected flush-stop %s", event_str);
1718         g_free (event_str);
1719       }
1720       pad_monitor->pending_flush_stop = FALSE;
1721
1722       /* Buffers following a FLUSH should have the DISCONT flag set */
1723       pad_monitor->pending_buffer_discont = TRUE;
1724
1725       /* cleanup our data */
1726       gst_validate_pad_monitor_flush (pad_monitor);
1727     }
1728       break;
1729     default:
1730       break;
1731   }
1732 }
1733
1734 static void
1735 mark_pads_eos (GstValidatePadMonitor * pad_monitor)
1736 {
1737   GstValidatePadMonitor *peer_monitor;
1738   GstPad *real_peer;
1739   GstPad *pad =
1740       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1741           (pad_monitor)));
1742   GstPad *peer = gst_pad_get_peer (pad);
1743
1744   gst_object_unref (pad);
1745   pad_monitor->is_eos = TRUE;
1746   if (peer) {
1747     real_peer = _get_actual_pad (peer);
1748     peer_monitor = _GET_PAD_MONITOR (real_peer);
1749     if (peer_monitor)
1750       peer_monitor->is_eos = TRUE;
1751     gst_object_unref (peer);
1752     gst_object_unref (real_peer);
1753   }
1754 }
1755
1756 static inline gboolean
1757 _should_check_buffers (GstValidatePadMonitor * pad_monitor,
1758     gboolean force_checks)
1759 {
1760   GstPad *pad =
1761       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1762           (pad_monitor)));
1763   GstValidateMonitor *monitor = GST_VALIDATE_MONITOR (pad_monitor);
1764
1765   if (pad_monitor->first_buffer || force_checks) {
1766     if (pad_monitor->segment.rate != 1.0) {
1767       GST_INFO_OBJECT (pad_monitor, "We do not support buffer checking"
1768           " for trick modes");
1769
1770       pad_monitor->check_buffers = FALSE;
1771     } else if (!PAD_PARENT_IS_DECODER (pad_monitor)) {
1772       GST_DEBUG_OBJECT (pad, "Not on a decoder => no buffer checking");
1773
1774       pad_monitor->check_buffers = FALSE;
1775     } else if (GST_PAD_DIRECTION (pad) != GST_PAD_SINK) {
1776       GST_DEBUG_OBJECT (pad, "Not a sinkpad => no buffer checking");
1777
1778       pad_monitor->check_buffers = FALSE;
1779     } else if (!pad_monitor->caps_is_video) {
1780       GST_DEBUG_OBJECT (pad, "Not working with video => no buffer checking");
1781
1782       pad_monitor->check_buffers = FALSE;
1783     } else if (monitor->media_descriptor == NULL) {
1784       GST_DEBUG_OBJECT (pad, "No media_descriptor set => no buffer checking");
1785
1786       pad_monitor->check_buffers = FALSE;
1787     } else if (!gst_validate_media_descriptor_detects_frames
1788         (monitor->media_descriptor)) {
1789       GST_DEBUG_OBJECT (pad,
1790           "No frame detection media descriptor => no buffer checking");
1791       pad_monitor->check_buffers = FALSE;
1792     } else if (pad_monitor->all_bufs == NULL &&
1793         !gst_validate_media_descriptor_get_buffers (monitor->media_descriptor,
1794             pad, NULL, &pad_monitor->all_bufs)) {
1795
1796       GST_INFO_OBJECT (monitor,
1797           "The MediaInfo is marked as detecting frame, but getting frames"
1798           " from pad %" GST_PTR_FORMAT " did not work (some format conversion"
1799           " might be happening)", pad);
1800
1801       pad_monitor->check_buffers = FALSE;
1802     } else {
1803       if (!pad_monitor->current_buf)
1804         pad_monitor->current_buf = pad_monitor->all_bufs;
1805       pad_monitor->check_buffers = TRUE;
1806     }
1807   }
1808   gst_object_unref (pad);
1809
1810   return pad_monitor->check_buffers;
1811 }
1812
1813 static void
1814 gst_validate_monitor_find_next_buffer (GstValidatePadMonitor * pad_monitor)
1815 {
1816   GList *tmp;
1817   gboolean passed_start = FALSE;
1818
1819   if (!_should_check_buffers (pad_monitor, TRUE))
1820     return;
1821
1822   for (tmp = g_list_last (pad_monitor->all_bufs); tmp; tmp = tmp->prev) {
1823     GstBuffer *cbuf = (GstBuffer *) tmp->data;
1824     GstClockTime ts =
1825         GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DTS (cbuf)) ? GST_BUFFER_DTS (cbuf)
1826         : GST_BUFFER_PTS (cbuf);
1827
1828     if (!GST_CLOCK_TIME_IS_VALID (ts))
1829       continue;
1830
1831     if (ts <= pad_monitor->segment.start)
1832       passed_start = TRUE;
1833
1834     if (!passed_start)
1835       continue;
1836
1837     if (!GST_BUFFER_FLAG_IS_SET (cbuf, GST_BUFFER_FLAG_DELTA_UNIT)) {
1838       break;
1839     }
1840   }
1841
1842   if (tmp == NULL)
1843     pad_monitor->current_buf = pad_monitor->all_bufs;
1844   else
1845     pad_monitor->current_buf = tmp;
1846 }
1847
1848 /* Checks whether a segment is just an update of another,
1849  * That is to say that only the base and offset field differ and all
1850  * other fields are identical */
1851 static gboolean
1852 is_segment_update (GstSegment * a, const GstSegment * b)
1853 {
1854   /* Note : We never care about the position field, it is only
1855    * used for internal usage by elements */
1856   if (a->rate == b->rate &&
1857       a->applied_rate == b->applied_rate &&
1858       a->format == b->format && a->time == b->time) {
1859     /* Changes in base/offset are considered updates */
1860     /* Updating the end position of a segment is an update */
1861     /* Updating the duration of a segment is an update */
1862     if (a->rate > 0.0) {
1863       if (a->start == b->start)
1864         return TRUE;
1865     } else {
1866       if (a->stop == b->stop)
1867         return TRUE;
1868     }
1869   }
1870   return FALSE;
1871 }
1872
1873 static GstFlowReturn
1874 gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor *
1875     pad_monitor, GstObject * parent, GstEvent * event,
1876     GstPadEventFunction handler)
1877 {
1878   GstFlowReturn ret = GST_FLOW_OK;
1879   const GstSegment *segment;
1880   guint32 seqnum = gst_event_get_seqnum (event);
1881   GstPad *pad =
1882       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1883           (pad_monitor)));
1884
1885   gst_validate_pad_monitor_common_event_check (pad_monitor, event);
1886
1887   /* pre checks */
1888   switch (GST_EVENT_TYPE (event)) {
1889     case GST_EVENT_STREAM_START:
1890       /* Buffers following a STREAM_START should have the DISCONT flag set */
1891       pad_monitor->pending_buffer_discont = TRUE;
1892       break;
1893     case GST_EVENT_SEGMENT:
1894       /* parse segment data to be used if event is handled */
1895       gst_event_parse_segment (event, &segment);
1896
1897       GST_DEBUG_OBJECT (pad, "Got segment %" GST_SEGMENT_FORMAT, segment);
1898
1899       /* Reset expected flush start/stop values, we have a segment */
1900       pad_monitor->pending_flush_start_seqnum = GST_SEQNUM_INVALID;
1901       pad_monitor->pending_flush_stop_seqnum = GST_SEQNUM_INVALID;
1902
1903       if (pad_monitor->pending_newsegment_seqnum != GST_SEQNUM_INVALID) {
1904         if (pad_monitor->pending_newsegment_seqnum == seqnum) {
1905           pad_monitor->pending_newsegment_seqnum = GST_SEQNUM_INVALID;
1906           if (GST_CLOCK_TIME_IS_VALID (pad_monitor->pending_seek_accurate_time)) {
1907             if (segment->time == pad_monitor->pending_seek_accurate_time) {
1908               pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE;
1909             } else {
1910               GST_VALIDATE_REPORT (pad_monitor, SEGMENT_HAS_WRONG_START,
1911                   "After an accurate seek, got: %" GST_TIME_FORMAT
1912                   " Expected: %" GST_TIME_FORMAT, GST_TIME_ARGS (segment->time),
1913                   GST_TIME_ARGS (pad_monitor->pending_seek_accurate_time));
1914             }
1915           }
1916         } else {
1917           GST_VALIDATE_REPORT (pad_monitor, SEGMENT_HAS_WRONG_SEQNUM,
1918               "Got: %u Expected: %u", seqnum, pad_monitor->pending_eos_seqnum);
1919         }
1920       }
1921
1922       pad_monitor->pending_eos_seqnum = seqnum;
1923
1924       if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
1925         gst_validate_pad_monitor_add_expected_newsegment (pad_monitor, event);
1926       } else {
1927         /* check if this segment is the expected one */
1928         if (pad_monitor->expected_segment) {
1929           const GstSegment *exp_segment;
1930
1931           if (pad_monitor->expected_segment != event) {
1932             gst_event_parse_segment (pad_monitor->expected_segment,
1933                 &exp_segment);
1934             if (segment->format == exp_segment->format) {
1935               if ((exp_segment->rate * exp_segment->applied_rate !=
1936                       segment->rate * segment->applied_rate))
1937                 GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH,
1938                     "Rate * applied_rate %f != expected %f",
1939                     segment->rate * segment->applied_rate,
1940                     exp_segment->rate * exp_segment->applied_rate);
1941               if (exp_segment->start != segment->start)
1942                 GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH,
1943                     "Start %" GST_TIME_FORMAT " != expected %" GST_TIME_FORMAT,
1944                     GST_TIME_ARGS (segment->start),
1945                     GST_TIME_ARGS (exp_segment->start));
1946               if (exp_segment->stop != segment->stop)
1947                 GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH,
1948                     "Stop %" GST_TIME_FORMAT " != expected %" GST_TIME_FORMAT,
1949                     GST_TIME_ARGS (segment->stop),
1950                     GST_TIME_ARGS (exp_segment->stop));
1951               if (exp_segment->position != segment->position)
1952                 GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH,
1953                     "Position %" GST_TIME_FORMAT " != expected %"
1954                     GST_TIME_FORMAT, GST_TIME_ARGS (segment->position),
1955                     GST_TIME_ARGS (exp_segment->position));
1956             }
1957           }
1958           gst_event_replace (&pad_monitor->expected_segment, NULL);
1959         }
1960       }
1961       break;
1962     case GST_EVENT_CAPS:{
1963       GstCaps *caps;
1964
1965       gst_event_parse_caps (event, &caps);
1966       gst_validate_pad_monitor_setcaps_pre (pad_monitor, caps);
1967       break;
1968     }
1969     case GST_EVENT_EOS:
1970       pad_monitor->is_eos = TRUE;
1971       /* FIXME : This feels and looks wrong ... */
1972       if (pad_monitor->pending_eos_seqnum == GST_SEQNUM_INVALID) {
1973         GST_VALIDATE_REPORT (pad_monitor, EVENT_EOS_WITHOUT_SEGMENT,
1974             "EOS %" GST_PTR_FORMAT " received before a segment was received",
1975             event);
1976       } else if (pad_monitor->pending_eos_seqnum != seqnum) {
1977         GST_VALIDATE_REPORT (pad_monitor, EOS_HAS_WRONG_SEQNUM,
1978             "Got: %u. Expected: %u", seqnum, pad_monitor->pending_eos_seqnum);
1979       }
1980
1981       /*
1982        * TODO add end of stream checks for
1983        *  - events not pushed
1984        *  - buffer data not pushed
1985        *  - pending events not received
1986        */
1987       break;
1988
1989       /* both flushes are handled by the common event function */
1990     case GST_EVENT_FLUSH_START:
1991     case GST_EVENT_FLUSH_STOP:
1992     case GST_EVENT_TAG:
1993     case GST_EVENT_SINK_MESSAGE:
1994     default:
1995       break;
1996   }
1997
1998   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1999   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
2000   gst_validate_pad_monitor_event_overrides (pad_monitor, event);
2001   if (handler) {
2002     gst_event_ref (event);
2003     if (pad_monitor->event_full_func)
2004       ret = pad_monitor->event_full_func (pad, parent, event);
2005     else if (pad_monitor->event_func (pad, parent, event))
2006       ret = GST_FLOW_OK;
2007     else
2008       ret = GST_FLOW_ERROR;
2009   }
2010   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
2011   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
2012
2013   /* post checks */
2014   switch (GST_EVENT_TYPE (event)) {
2015     case GST_EVENT_SEGMENT:
2016       if (ret == GST_FLOW_OK) {
2017         /* If the new segment is not an update of the previous one, then
2018          * the following buffer should have the DISCONT flag set */
2019         if (!is_segment_update (&pad_monitor->segment, segment))
2020           pad_monitor->pending_buffer_discont = TRUE;
2021         if (!pad_monitor->has_segment
2022             && pad_monitor->segment.format != segment->format) {
2023           gst_segment_init (&pad_monitor->segment, segment->format);
2024         }
2025         gst_segment_copy_into (segment, &pad_monitor->segment);
2026         pad_monitor->has_segment = TRUE;
2027         gst_validate_monitor_find_next_buffer (pad_monitor);
2028       }
2029       break;
2030     case GST_EVENT_CAPS:{
2031       GstCaps *caps;
2032
2033       gst_event_parse_caps (event, &caps);
2034       gst_validate_pad_monitor_setcaps_post (pad_monitor, caps,
2035           ret == GST_FLOW_OK);
2036       break;
2037     }
2038     case GST_EVENT_FLUSH_START:
2039     case GST_EVENT_FLUSH_STOP:
2040     case GST_EVENT_EOS:
2041     case GST_EVENT_TAG:
2042     case GST_EVENT_SINK_MESSAGE:
2043     default:
2044       break;
2045   }
2046
2047   if (handler)
2048     gst_event_unref (event);
2049   gst_object_unref (pad);
2050   return ret;
2051 }
2052
2053 static gboolean
2054 gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor,
2055     GstObject * parent, GstEvent * event, GstPadEventFunction handler)
2056 {
2057   gboolean ret = TRUE;
2058   gdouble rate;
2059   GstFormat format;
2060   gint64 start, stop;
2061   GstSeekFlags seek_flags;
2062   GstSeekType start_type, stop_type;
2063   guint32 seqnum = gst_event_get_seqnum (event);
2064   GstPad *pad =
2065       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
2066           (pad_monitor)));
2067
2068   gst_validate_pad_monitor_common_event_check (pad_monitor, event);
2069
2070   /* pre checks */
2071   switch (GST_EVENT_TYPE (event)) {
2072     case GST_EVENT_SEEK:
2073     {
2074       gst_event_parse_seek (event, &rate, &format, &seek_flags, &start_type,
2075           &start, &stop_type, &stop);
2076       /* upstream seek - store the seek event seqnum to check
2077        * flushes and newsegments share the same */
2078     }
2079       break;
2080       /* both flushes are handled by the common event handling function */
2081     case GST_EVENT_FLUSH_START:
2082     case GST_EVENT_FLUSH_STOP:
2083     case GST_EVENT_NAVIGATION:
2084     case GST_EVENT_LATENCY:
2085     case GST_EVENT_STEP:
2086     case GST_EVENT_QOS:
2087     default:
2088       break;
2089   }
2090
2091   if (handler) {
2092     GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
2093     /* Safely store pending accurate seek values */
2094     if (GST_EVENT_TYPE (event) == GST_EVENT_SEEK) {
2095       if (seek_flags & GST_SEEK_FLAG_ACCURATE && format == GST_FORMAT_TIME) {
2096         GST_DEBUG_OBJECT (pad,
2097             "Storing expected accurate seek time %" GST_TIME_FORMAT,
2098             GST_TIME_ARGS (start));
2099         pad_monitor->pending_seek_accurate_time = start;
2100       }
2101       /* TODO we might need to use a list as multiple seeks can be sent
2102        * before the flushes arrive here */
2103       if (seek_flags & GST_SEEK_FLAG_FLUSH) {
2104         pad_monitor->pending_flush_start_seqnum = seqnum;
2105         pad_monitor->pending_flush_stop_seqnum = seqnum;
2106       }
2107     }
2108
2109     gst_event_ref (event);
2110     ret = pad_monitor->event_func (pad, parent, event);
2111
2112     if (GST_EVENT_TYPE (event) == GST_EVENT_SEEK) {
2113       /* If the seek was already handled (same current seqnum), reset the
2114        * expected accurate seek value */
2115       if (ret && pad_monitor->has_segment
2116           && seqnum == pad_monitor->pending_eos_seqnum) {
2117         GST_DEBUG_OBJECT (pad,
2118             "Resetting expected accurate seek value, was already handled");
2119         pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE;
2120       } else if (!ret) {
2121         /* do not expect any of these events anymore */
2122         pad_monitor->pending_flush_start_seqnum = GST_SEQNUM_INVALID;
2123         pad_monitor->pending_flush_stop_seqnum = GST_SEQNUM_INVALID;
2124         pad_monitor->pending_newsegment_seqnum = GST_SEQNUM_INVALID;
2125         pad_monitor->pending_eos_seqnum = GST_SEQNUM_INVALID;
2126         pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE;
2127       }
2128     }
2129     GST_VALIDATE_MONITOR_LOCK (pad_monitor);
2130   }
2131
2132   /* post checks */
2133   switch (GST_EVENT_TYPE (event)) {
2134     case GST_EVENT_FLUSH_START:
2135     case GST_EVENT_FLUSH_STOP:
2136     case GST_EVENT_QOS:
2137     case GST_EVENT_SEEK:
2138     case GST_EVENT_NAVIGATION:
2139     case GST_EVENT_LATENCY:
2140     case GST_EVENT_STEP:
2141     default:
2142       break;
2143   }
2144
2145   if (handler)
2146     gst_event_unref (event);
2147   gst_object_unref (pad);
2148   return ret;
2149 }
2150
2151 static gboolean
2152 gst_validate_pad_monitor_check_right_buffer (GstValidatePadMonitor *
2153     pad_monitor, GstBuffer * buffer)
2154 {
2155   gchar *checksum;
2156   GstBuffer *wanted_buf;
2157   GstMapInfo map, wanted_map;
2158
2159   gboolean ret = TRUE;
2160   GstPad *pad;
2161
2162
2163   if (_should_check_buffers (pad_monitor, FALSE) == FALSE)
2164     return FALSE;
2165
2166   pad =
2167       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
2168           (pad_monitor)));
2169   if (pad_monitor->current_buf == NULL) {
2170     GST_INFO_OBJECT (pad, "No current buffer one pad, Why?");
2171     gst_object_unref (pad);
2172     return FALSE;
2173   }
2174
2175   wanted_buf = pad_monitor->current_buf->data;
2176
2177   if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (wanted_buf)) &&
2178       GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (buffer)) &&
2179       GST_BUFFER_PTS (wanted_buf) != GST_BUFFER_PTS (buffer)) {
2180
2181     GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER,
2182         "buffer %" GST_PTR_FORMAT " PTS %" GST_TIME_FORMAT
2183         " different than expected: %" GST_TIME_FORMAT, buffer,
2184         GST_TIME_ARGS (GST_BUFFER_PTS (buffer)),
2185         GST_TIME_ARGS (GST_BUFFER_PTS (wanted_buf)));
2186
2187     ret = FALSE;
2188   }
2189
2190   if (GST_BUFFER_DTS (wanted_buf) != GST_BUFFER_DTS (buffer)) {
2191     GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER,
2192         "buffer %" GST_PTR_FORMAT " DTS %" GST_TIME_FORMAT
2193         " different than expected: %" GST_TIME_FORMAT, buffer,
2194         GST_TIME_ARGS (GST_BUFFER_DTS (buffer)),
2195         GST_TIME_ARGS (GST_BUFFER_DTS (wanted_buf)));
2196     ret = FALSE;
2197   }
2198
2199   if (GST_BUFFER_DURATION (wanted_buf) != GST_BUFFER_DURATION (buffer)) {
2200     GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER,
2201         "buffer %" GST_PTR_FORMAT " DURATION %" GST_TIME_FORMAT
2202         " different than expected: %" GST_TIME_FORMAT, buffer,
2203         GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)),
2204         GST_TIME_ARGS (GST_BUFFER_DURATION (wanted_buf)));
2205     ret = FALSE;
2206   }
2207
2208   if (GST_BUFFER_FLAG_IS_SET (wanted_buf, GST_BUFFER_FLAG_DELTA_UNIT) !=
2209       GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)) {
2210     GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER,
2211         "buffer %" GST_PTR_FORMAT "  Delta unit is set to %s but expected %s",
2212         buffer, GST_BUFFER_FLAG_IS_SET (buffer,
2213             GST_BUFFER_FLAG_DELTA_UNIT) ? "True" : "False",
2214         GST_BUFFER_FLAG_IS_SET (wanted_buf,
2215             GST_BUFFER_FLAG_DELTA_UNIT) ? "True" : "False");
2216     ret = FALSE;
2217   }
2218
2219   g_assert (gst_buffer_map (wanted_buf, &wanted_map, GST_MAP_READ));
2220   g_assert (gst_buffer_map (buffer, &map, GST_MAP_READ));
2221
2222   checksum = g_compute_checksum_for_data (G_CHECKSUM_MD5,
2223       (const guchar *) map.data, map.size);
2224
2225   if (g_strcmp0 ((gchar *) wanted_map.data, checksum)) {
2226     GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER,
2227         "buffer %" GST_PTR_FORMAT " checksum %s different from expected: %s",
2228         buffer, checksum, wanted_map.data);
2229     ret = FALSE;
2230   }
2231
2232   gst_buffer_unmap (wanted_buf, &wanted_map);
2233   gst_buffer_unmap (buffer, &map);
2234   g_free (checksum);
2235   gst_object_unref (pad);
2236
2237   pad_monitor->current_buf = pad_monitor->current_buf->next;
2238
2239   return ret;
2240 }
2241
2242 static void
2243 gst_validate_pad_monitor_check_return (GstValidatePadMonitor * pad_monitor,
2244     GstFlowReturn ret)
2245 {
2246   GstValidateMonitor *parent = GST_VALIDATE_MONITOR (pad_monitor);
2247
2248   if (ret != GST_FLOW_ERROR)
2249     return;
2250
2251   while (GST_VALIDATE_MONITOR_GET_PARENT (parent))
2252     parent = GST_VALIDATE_MONITOR_GET_PARENT (parent);
2253
2254   if (GST_IS_VALIDATE_PIPELINE_MONITOR (parent)) {
2255     GstValidatePipelineMonitor *m = GST_VALIDATE_PIPELINE_MONITOR (parent);
2256
2257     GST_VALIDATE_MONITOR_LOCK (m);
2258     if (m->got_error == FALSE) {
2259       GST_VALIDATE_REPORT (pad_monitor, FLOW_ERROR_WITHOUT_ERROR_MESSAGE,
2260           "Pad return GST_FLOW_ERROR but no GST_MESSAGE_ERROR was received on"
2261           " the bus");
2262
2263       /* Only report it the first time */
2264       m->got_error = TRUE;
2265     }
2266     GST_VALIDATE_MONITOR_UNLOCK (m);
2267   }
2268 }
2269
2270 static GstFlowReturn
2271 gst_validate_pad_monitor_chain_func (GstPad * pad, GstObject * parent,
2272     GstBuffer * buffer)
2273 {
2274   GstValidatePadMonitor *pad_monitor = _GET_PAD_MONITOR (pad);
2275   GstFlowReturn ret;
2276
2277   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
2278   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
2279
2280   gst_validate_pad_monitor_check_discont (pad_monitor, buffer);
2281   gst_validate_pad_monitor_check_right_buffer (pad_monitor, buffer);
2282   gst_validate_pad_monitor_check_first_buffer (pad_monitor, buffer);
2283   gst_validate_pad_monitor_update_buffer_data (pad_monitor, buffer);
2284   gst_validate_pad_monitor_check_eos (pad_monitor, buffer);
2285
2286   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
2287   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
2288
2289   gst_validate_pad_monitor_buffer_overrides (pad_monitor, buffer);
2290
2291   ret = pad_monitor->chain_func (pad, parent, buffer);
2292
2293   gst_validate_pad_monitor_check_return (pad_monitor, ret);
2294
2295   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
2296   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
2297
2298   pad_monitor->last_flow_return = ret;
2299   if (ret == GST_FLOW_EOS) {
2300     mark_pads_eos (pad_monitor);
2301   }
2302   if (PAD_PARENT_IS_DEMUXER (pad_monitor))
2303     gst_validate_pad_monitor_check_aggregated_return (pad_monitor, parent, ret);
2304
2305   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
2306   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
2307
2308   return ret;
2309 }
2310
2311 static gboolean
2312 gst_validate_pad_monitor_event_is_tracked (GstValidatePadMonitor * monitor,
2313     GstEvent * event)
2314 {
2315   if (!GST_EVENT_IS_SERIALIZED (event)) {
2316     return FALSE;
2317   }
2318
2319   /* we don't track Tag events because they mutate too much and it is hard
2320    * to match a tag event pushed on a source pad with the one that was received
2321    * on a sink pad.
2322    * One idea would be to use seqnum, but it seems that it is undefined whether
2323    * seqnums should be maintained in tag events that are created from others
2324    * up to today. (2013-08-29)
2325    */
2326   if (GST_EVENT_TYPE (event) == GST_EVENT_TAG)
2327     return FALSE;
2328
2329   return TRUE;
2330 }
2331
2332 static GstFlowReturn
2333 gst_validate_pad_monitor_sink_event_full_func (GstPad * pad, GstObject * parent,
2334     GstEvent * event)
2335 {
2336   GstValidatePadMonitor *pad_monitor = _GET_PAD_MONITOR (pad);
2337   GstFlowReturn ret;
2338
2339   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
2340   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
2341
2342   GST_DEBUG_OBJECT (pad, "event %p %s", event, GST_EVENT_TYPE_NAME (event));
2343
2344   if (gst_validate_pad_monitor_event_is_tracked (pad_monitor, event)) {
2345     GstClockTime last_ts = GST_CLOCK_TIME_NONE;
2346     if (GST_CLOCK_TIME_IS_VALID (pad_monitor->current_timestamp)) {
2347       last_ts = pad_monitor->current_timestamp;
2348       if (GST_CLOCK_TIME_IS_VALID (pad_monitor->current_duration)) {
2349         last_ts += pad_monitor->current_duration;
2350       }
2351     }
2352     gst_validate_pad_monitor_otherpad_add_pending_serialized_event (pad_monitor,
2353         event, last_ts);
2354   }
2355
2356   ret =
2357       gst_validate_pad_monitor_downstream_event_check (pad_monitor, parent,
2358       event, pad_monitor->event_func);
2359
2360   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
2361   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
2362   return ret;
2363 }
2364
2365 static gboolean
2366 gst_validate_pad_monitor_sink_event_func (GstPad * pad, GstObject * parent,
2367     GstEvent * event)
2368 {
2369   if (gst_validate_pad_monitor_sink_event_full_func (pad, parent,
2370           event) == GST_FLOW_OK)
2371     return TRUE;
2372   return FALSE;
2373 }
2374
2375 static gboolean
2376 gst_validate_pad_monitor_src_event_func (GstPad * pad, GstObject * parent,
2377     GstEvent * event)
2378 {
2379   GstValidatePadMonitor *pad_monitor = _GET_PAD_MONITOR (pad);
2380   gboolean ret;
2381
2382   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
2383   ret = gst_validate_pad_monitor_src_event_check (pad_monitor, parent, event,
2384       pad_monitor->event_func);
2385   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
2386   return ret;
2387 }
2388
2389 static gboolean
2390 gst_validate_pad_monitor_query_func (GstPad * pad, GstObject * parent,
2391     GstQuery * query)
2392 {
2393   GstValidatePadMonitor *pad_monitor = _GET_PAD_MONITOR (pad);
2394   gboolean ret;
2395
2396   gst_validate_pad_monitor_query_overrides (pad_monitor, query);
2397   ret = pad_monitor->query_func (pad, parent, query);
2398
2399   if (ret) {
2400     switch (GST_QUERY_TYPE (query)) {
2401       case GST_QUERY_ACCEPT_CAPS:
2402       {
2403         gboolean result;
2404
2405         gst_caps_replace (&pad_monitor->last_refused_caps, NULL);
2406         gst_query_parse_accept_caps_result (query, &result);
2407         if (!result) {
2408           GstCaps *refused_caps;
2409
2410           gst_query_parse_accept_caps (query, &refused_caps);
2411           pad_monitor->last_refused_caps = gst_caps_copy (refused_caps);
2412
2413         }
2414
2415         break;
2416       }
2417       case GST_QUERY_CAPS:{
2418         GstCaps *res;
2419         GstCaps *filter;
2420
2421         /* We shouldn't need to lock the parent as this doesn't modify
2422          * other monitors, just does some peer_pad_caps */
2423         GST_VALIDATE_MONITOR_LOCK (pad_monitor);
2424
2425         gst_query_parse_caps (query, &filter);
2426         gst_query_parse_caps_result (query, &res);
2427
2428         gst_caps_replace (&pad_monitor->last_query_res, NULL);
2429         gst_caps_replace (&pad_monitor->last_query_filter, NULL);
2430         pad_monitor->last_query_res =
2431             res ? gst_caps_copy (res) : gst_caps_ref (GST_CAPS_NONE);
2432         pad_monitor->last_query_filter =
2433             filter ? gst_caps_copy (filter) : gst_caps_ref (GST_CAPS_NONE);
2434
2435         if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
2436           gst_validate_pad_monitor_check_caps_fields_proxied (pad_monitor, res,
2437               filter);
2438         }
2439         GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
2440         break;
2441       }
2442       default:
2443         break;
2444     }
2445   }
2446
2447   return ret;
2448 }
2449
2450 static gboolean
2451 gst_validate_pad_monitor_activatemode_func (GstPad * pad, GstObject * parent,
2452     GstPadMode mode, gboolean active)
2453 {
2454   GstValidatePadMonitor *pad_monitor = _GET_PAD_MONITOR (pad);
2455   gboolean ret = TRUE;
2456
2457   /* TODO add overrides for activate func */
2458   GST_DEBUG_OBJECT (pad, "active:%d", active);
2459
2460   if (pad_monitor->activatemode_func)
2461     ret = pad_monitor->activatemode_func (pad, parent, mode, active);
2462   if (ret && active == FALSE) {
2463     GST_VALIDATE_MONITOR_LOCK (pad_monitor);
2464     gst_validate_pad_monitor_reset (pad_monitor);
2465     GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
2466   }
2467
2468   return ret;
2469 }
2470
2471 /* The interval between two buffer frequency checks */
2472 #define BUF_FREQ_CHECK_INTERVAL (GST_SECOND)
2473
2474 static void
2475 gst_validate_pad_monitor_check_buffer_freq (GstValidatePadMonitor * monitor,
2476     GstPad * pad)
2477 {
2478   GstClockTime ts;
2479
2480   if (!GST_PAD_IS_SRC (pad))
2481     return;
2482
2483   if (!monitor->min_buf_freq)
2484     return;
2485
2486   ts = gst_util_get_timestamp ();
2487   monitor->buffers_pushed++;
2488
2489   /* Same logic as in fpsdisplaysink to compute the buffer frequency */
2490   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID
2491           (monitor->min_buf_freq_first_buffer_ts))) {
2492     monitor->min_buf_freq_first_buffer_ts = ts;
2493     monitor->min_buf_freq_interval_ts = ts;
2494     return;
2495   }
2496
2497   if (GST_CLOCK_DIFF (monitor->min_buf_freq_interval_ts,
2498           ts) > BUF_FREQ_CHECK_INTERVAL) {
2499     guint time_diff;
2500     gdouble fps;
2501
2502     time_diff = (gdouble) (ts - monitor->min_buf_freq_interval_ts) / GST_SECOND;
2503     fps =
2504         (gdouble) (monitor->buffers_pushed -
2505         monitor->last_buffers_pushed) / time_diff;
2506
2507     if (fps < monitor->min_buf_freq) {
2508       if (GST_CLOCK_TIME_IS_VALID (monitor->min_buf_freq_start) &&
2509           GST_CLOCK_DIFF (monitor->min_buf_freq_first_buffer_ts,
2510               ts) < monitor->min_buf_freq_start) {
2511         GST_DEBUG_OBJECT (pad,
2512             "buffer frequency is too low (%.2f) but ignore for now (buffer-frequency-start =%"
2513             GST_TIME_FORMAT ")", fps,
2514             GST_TIME_ARGS (monitor->min_buf_freq_start));
2515       } else {
2516         GST_VALIDATE_REPORT (monitor, CONFIG_BUFFER_FREQUENCY_TOO_LOW,
2517             "Buffers are not pushed fast enough on this pad: %.2f/sec (minimum: %.2f)",
2518             fps, monitor->min_buf_freq);
2519       }
2520     }
2521
2522     monitor->last_buffers_pushed = monitor->buffers_pushed;
2523     monitor->min_buf_freq_interval_ts = ts;
2524   }
2525 }
2526
2527 static gboolean
2528 gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer,
2529     gpointer udata, gboolean pull_mode)
2530 {
2531   GstValidatePadMonitor *monitor = udata;
2532
2533   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor);
2534   GST_VALIDATE_MONITOR_LOCK (monitor);
2535
2536   if (!pull_mode)
2537     gst_validate_pad_monitor_check_discont (monitor, buffer);
2538   gst_validate_pad_monitor_check_first_buffer (monitor, buffer);
2539   gst_validate_pad_monitor_update_buffer_data (monitor, buffer);
2540   gst_validate_pad_monitor_check_eos (monitor, buffer);
2541
2542   if (PAD_PARENT_IS_DECODER (monitor) || PAD_PARENT_IS_ENCODER (monitor)) {
2543     GstClockTime tolerance = 0;
2544
2545     if (monitor->caps_is_audio)
2546       tolerance = AUDIO_TIMESTAMP_TOLERANCE;
2547
2548     gst_validate_pad_monitor_check_buffer_timestamp_in_received_range (monitor,
2549         buffer, tolerance);
2550   }
2551
2552   gst_validate_pad_monitor_check_late_serialized_events (monitor,
2553       GST_BUFFER_TIMESTAMP (buffer));
2554
2555   /* a GstValidatePadMonitor parent must be a GstValidateElementMonitor */
2556   if (PAD_PARENT_IS_DECODER (monitor)) {
2557
2558     /* should not push out of segment data */
2559     if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer)) &&
2560         GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer)) &&
2561         ((!gst_segment_clip (&monitor->segment, monitor->segment.format,
2562                     GST_BUFFER_TIMESTAMP (buffer),
2563                     GST_BUFFER_TIMESTAMP (buffer) +
2564                     GST_BUFFER_DURATION (buffer), NULL, NULL)) ||
2565             /* In the case of raw data, buffers should be strictly contained inside the
2566              * segment */
2567             (monitor->caps_is_raw &&
2568                 GST_BUFFER_PTS (buffer) + GST_BUFFER_DURATION (buffer) <
2569                 monitor->segment.start))
2570         ) {
2571       /* TODO is this a timestamp issue? */
2572       GST_VALIDATE_REPORT (monitor, BUFFER_IS_OUT_OF_SEGMENT,
2573           "buffer is out of segment and shouldn't be pushed. Timestamp: %"
2574           GST_TIME_FORMAT " - Duration: %" GST_TIME_FORMAT ". Range: %"
2575           GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2576           GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
2577           GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)),
2578           GST_TIME_ARGS (monitor->segment.start),
2579           GST_TIME_ARGS (monitor->segment.stop));
2580     }
2581   }
2582
2583   gst_validate_pad_monitor_check_buffer_freq (monitor, pad);
2584
2585   GST_VALIDATE_MONITOR_UNLOCK (monitor);
2586   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (monitor);
2587   gst_validate_pad_monitor_buffer_probe_overrides (monitor, buffer);
2588   return TRUE;
2589 }
2590
2591 static void
2592 gst_validate_pad_monitor_event_probe (GstPad * pad, GstEvent * event,
2593     gpointer udata)
2594 {
2595   GstValidatePadMonitor *monitor = GST_VALIDATE_PAD_MONITOR_CAST (udata);
2596
2597   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor);
2598   GST_VALIDATE_MONITOR_LOCK (monitor);
2599
2600   GST_DEBUG_OBJECT (pad, "event %p %s", event, GST_EVENT_TYPE_NAME (event));
2601
2602   if (GST_EVENT_IS_SERIALIZED (event)) {
2603     gint i;
2604
2605     /* Detect if events the element received are being forwarded in the same order
2606      *
2607      * Several scenarios:
2608      * 1) The element pushes the event as-is
2609      * 2) The element consumes the event and does not forward it
2610      * 3) The element consumes the event and creates another one instead
2611      * 4) The element pushes other serialized event before pushing out the
2612      *    one it received
2613      *
2614      * For each pad we have two lists to track serialized events:
2615      *  1) We received on input and expect to see (serialized_events)
2616      *  2) We received on input but don't expect to see (expired_events)
2617      *
2618      * To detect events that are pushed in a different order from the one they were
2619      * received in we check that:
2620      *
2621      * For each event being outputted:
2622      *   If it is in the expired_events list:
2623      *     RAISE WARNING
2624      *   If it is in the serialized_events list:
2625      *     If there are other events that were received before:
2626      *        Put those events on the expired_events list
2627      *     Remove that event and any previous ones from the serialized_events list
2628      *
2629      * Clear expired events list when flushing or on pad deactivation
2630      *
2631      */
2632
2633     if (g_list_find (monitor->expired_events, event)) {
2634       gchar *event_str = _get_event_string (event);
2635       /* If it's the expired events, we've failed */
2636       GST_WARNING_OBJECT (pad, "Did not expect event %p %s", event,
2637           GST_EVENT_TYPE_NAME (event));
2638       GST_VALIDATE_REPORT (monitor, EVENT_SERIALIZED_OUT_OF_ORDER,
2639           "Serialized event was pushed out of order: %s", event_str);
2640
2641       g_free (event_str);
2642       monitor->expired_events = g_list_remove (monitor->expired_events, event);
2643       gst_event_unref (event);  /* remove the ref that was on the list */
2644     } else if (monitor->serialized_events->len) {
2645       for (i = 0; i < monitor->serialized_events->len; i++) {
2646         SerializedEventData *next_event =
2647             g_ptr_array_index (monitor->serialized_events, i);
2648         GST_DEBUG_OBJECT (pad, "Checking against stored event #%d: %p %s", i,
2649             next_event->event, GST_EVENT_TYPE_NAME (next_event->event));
2650
2651         if (event == next_event->event
2652             || GST_EVENT_TYPE (event) == GST_EVENT_TYPE (next_event->event)) {
2653           /* We have found our event */
2654           GST_DEBUG_OBJECT (pad, "Found matching event");
2655
2656           while (monitor->serialized_events->len > i
2657               && GST_EVENT_TYPE (event) == GST_EVENT_TYPE (next_event->event)) {
2658             /* Swallow all expected events of the same type */
2659             g_ptr_array_remove_index (monitor->serialized_events, i);
2660             next_event = g_ptr_array_index (monitor->serialized_events, i);
2661           }
2662
2663           /* Move all previous events to expired events */
2664           if (G_UNLIKELY (i > 0)) {
2665             GST_DEBUG_OBJECT (pad,
2666                 "Moving previous expected events to expired list");
2667             while (i--) {
2668               next_event = g_ptr_array_index (monitor->serialized_events, 0);
2669               monitor->expired_events =
2670                   g_list_append (monitor->expired_events,
2671                   gst_event_ref (next_event->event));
2672               g_ptr_array_remove_index (monitor->serialized_events, 0);
2673             }
2674           }
2675           debug_pending_event (pad, monitor->serialized_events);
2676           break;
2677         }
2678       }
2679     }
2680   }
2681
2682   /* This so far is just like an event that is flowing downstream,
2683    * so we do the same checks as a sinkpad event handler */
2684   gst_validate_pad_monitor_downstream_event_check (monitor, NULL, event, NULL);
2685   GST_VALIDATE_MONITOR_UNLOCK (monitor);
2686   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (monitor);
2687 }
2688
2689 static GstPadProbeReturn
2690 gst_validate_pad_monitor_pad_probe (GstPad * pad, GstPadProbeInfo * info,
2691     gpointer udata)
2692 {
2693   if (info->type & GST_PAD_PROBE_TYPE_BUFFER)
2694     gst_validate_pad_monitor_buffer_probe (pad, info->data, udata,
2695         GST_PAD_PROBE_INFO_TYPE (info) & GST_PAD_PROBE_TYPE_PULL);
2696   else if (info->type & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM)
2697     gst_validate_pad_monitor_event_probe (pad, info->data, udata);
2698
2699   return GST_PAD_PROBE_OK;
2700 }
2701
2702 static void
2703 gst_validate_pad_monitor_update_caps_info (GstValidatePadMonitor * pad_monitor,
2704     GstCaps * caps)
2705 {
2706   GstStructure *structure;
2707
2708   g_return_if_fail (gst_caps_is_fixed (caps));
2709
2710   pad_monitor->caps_is_audio = FALSE;
2711   pad_monitor->caps_is_video = FALSE;
2712
2713   structure = gst_caps_get_structure (caps, 0);
2714   if (g_str_has_prefix (gst_structure_get_name (structure), "audio/")) {
2715     pad_monitor->caps_is_audio = TRUE;
2716   } else if (g_str_has_prefix (gst_structure_get_name (structure), "video/")) {
2717     pad_monitor->caps_is_video = TRUE;
2718   }
2719
2720   if (g_str_has_prefix (gst_structure_get_name (structure), "audio/x-raw") ||
2721       g_str_has_prefix (gst_structure_get_name (structure), "video/x-raw")) {
2722     pad_monitor->caps_is_raw = TRUE;
2723   } else {
2724     pad_monitor->caps_is_raw = FALSE;
2725   }
2726 }
2727
2728 static void
2729 gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor,
2730     GstCaps * caps)
2731 {
2732   GstStructure *structure;
2733   GstPad *pad =
2734       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
2735           (pad_monitor)));
2736
2737   /* Check if caps are identical to last caps and complain if so
2738    * Only checked for sink pads as src pads might push the same caps
2739    * multiple times during unlinked/autoplugging scenarios */
2740   if (GST_PAD_IS_SINK (pad) && pad_monitor->last_caps
2741       && gst_caps_is_equal (caps, pad_monitor->last_caps)) {
2742     gchar *caps_str = gst_caps_to_string (caps);
2743
2744     GST_VALIDATE_REPORT (pad_monitor, EVENT_CAPS_DUPLICATE, "%s", caps_str);
2745     g_free (caps_str);
2746
2747   }
2748
2749   gst_validate_pad_monitor_check_caps_complete (pad_monitor, caps);
2750
2751   if (caps) {
2752     structure = gst_caps_get_structure (caps, 0);
2753     if (gst_structure_n_fields (pad_monitor->pending_setcaps_fields)) {
2754       gint i;
2755       for (i = 0;
2756           i < gst_structure_n_fields (pad_monitor->pending_setcaps_fields);
2757           i++) {
2758         const gchar *name =
2759             gst_structure_nth_field_name (pad_monitor->pending_setcaps_fields,
2760             i);
2761         const GValue *v = gst_structure_get_value (structure, name);
2762         const GValue *otherv =
2763             gst_structure_get_value (pad_monitor->pending_setcaps_fields, name);
2764
2765         if (v == NULL) {
2766           gchar *caps_str = gst_caps_to_string (caps);
2767
2768           GST_VALIDATE_REPORT (pad_monitor, CAPS_EXPECTED_FIELD_NOT_FOUND,
2769               "Field %s is missing from setcaps caps '%s'", name, caps_str);
2770           g_free (caps_str);
2771         } else if (gst_value_compare (v, otherv) != GST_VALUE_EQUAL) {
2772           gchar *caps_str = gst_caps_to_string (caps),
2773               *pending_setcaps_fields_str =
2774               gst_structure_to_string (pad_monitor->pending_setcaps_fields);
2775
2776
2777           GST_VALIDATE_REPORT (pad_monitor, CAPS_FIELD_UNEXPECTED_VALUE,
2778               "Field %s from setcaps caps '%s' is different "
2779               "from expected value in caps '%s'", name, caps_str,
2780               pending_setcaps_fields_str);
2781
2782           g_free (pending_setcaps_fields_str);
2783           g_free (caps_str);
2784         }
2785       }
2786     }
2787
2788     if (GST_PAD_IS_SINK (pad) &&
2789         gst_validate_pad_monitor_pad_should_proxy_othercaps (pad_monitor)) {
2790       if (_structure_is_video (structure)) {
2791         GST_DEBUG_OBJECT (pad,
2792             "Adding video common pending fields to other pad: %" GST_PTR_FORMAT,
2793             structure);
2794         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2795             structure, "width");
2796         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2797             structure, "height");
2798         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2799             structure, "framerate");
2800         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2801             structure, "pixel-aspect-ratio");
2802       } else if (_structure_is_audio (structure)) {
2803         GST_DEBUG_OBJECT (pad,
2804             "Adding audio common pending fields to other pad: %" GST_PTR_FORMAT,
2805             structure);
2806         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2807             structure, "rate");
2808         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2809             structure, "channels");
2810       }
2811     }
2812   }
2813
2814   gst_structure_free (pad_monitor->pending_setcaps_fields);
2815   pad_monitor->pending_setcaps_fields =
2816       gst_structure_new_empty (PENDING_FIELDS);
2817   gst_object_unref (pad);
2818
2819   gst_validate_pad_monitor_setcaps_overrides (pad_monitor, caps);
2820 }
2821
2822 static void
2823 gst_validate_pad_monitor_setcaps_post (GstValidatePadMonitor * pad_monitor,
2824     GstCaps * caps, gboolean ret)
2825 {
2826   if (!ret)
2827     gst_validate_pad_monitor_otherpad_clear_pending_fields (pad_monitor);
2828   else {
2829     if (pad_monitor->last_caps) {
2830       gst_caps_unref (pad_monitor->last_caps);
2831     }
2832     pad_monitor->last_caps = gst_caps_ref (caps);
2833     gst_validate_pad_monitor_update_caps_info (pad_monitor, caps);
2834   }
2835 }
2836
2837 static void
2838 gst_validate_pad_monitor_get_min_buffer_frequency (GstValidatePadMonitor *
2839     monitor, GstPad * pad)
2840 {
2841   GList *config, *l;
2842
2843   if (!GST_PAD_IS_SRC (pad))
2844     return;
2845
2846   config = gst_validate_plugin_get_config (NULL);
2847   for (l = config; l != NULL; l = g_list_next (l)) {
2848     GstStructure *s = l->data;
2849     gdouble min_buf_freq;
2850     const gchar *pad_name;
2851     GstElement *element = NULL;
2852
2853     if (!gst_structure_get_double (s, "min-buffer-frequency", &min_buf_freq)) {
2854       gint max_int;
2855
2856       if (!gst_structure_get_int (s, "min-buffer-frequency", &max_int))
2857         goto next;
2858
2859       min_buf_freq = max_int;
2860     }
2861
2862     pad_name = gst_structure_get_string (s, "name");
2863     if (!pad_name)
2864       pad_name = "src";
2865
2866     if (g_strcmp0 (GST_PAD_NAME (pad), pad_name))
2867       goto next;
2868
2869     element = gst_pad_get_parent_element (pad);
2870
2871     if (!gst_validate_element_matches_target (element, s))
2872       goto next;
2873
2874     monitor->min_buf_freq = min_buf_freq;
2875
2876     gst_validate_utils_get_clocktime (s, "buffer-frequency-start",
2877         &monitor->min_buf_freq_start);
2878
2879     GST_DEBUG_OBJECT (pad, "pad has a minimum buffer frequency of %f",
2880         min_buf_freq);
2881   next:
2882     g_clear_object (&element);
2883   }
2884 }
2885
2886 static gboolean
2887 gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor)
2888 {
2889   GstValidatePadMonitor *pad_monitor = GST_VALIDATE_PAD_MONITOR_CAST (monitor);
2890   GstPad *pad = (gpointer) gst_validate_monitor_get_target (monitor);
2891
2892   if (!GST_IS_PAD (pad)) {
2893     GST_WARNING_OBJECT (monitor, "Trying to create pad monitor with other "
2894         "type of object");
2895     gst_object_unref (pad);
2896     return FALSE;
2897   }
2898
2899   if (_GET_PAD_MONITOR (pad)) {
2900     GST_WARNING_OBJECT (pad_monitor,
2901         "Pad already has a validate-monitor associated");
2902     gst_object_unref (pad);
2903     return FALSE;
2904   }
2905
2906   _SET_PAD_MONITOR (pad, pad_monitor);
2907
2908   pad_monitor->event_func = GST_PAD_EVENTFUNC (pad);
2909   pad_monitor->event_full_func = GST_PAD_EVENTFULLFUNC (pad);
2910   pad_monitor->query_func = GST_PAD_QUERYFUNC (pad);
2911   pad_monitor->activatemode_func = GST_PAD_ACTIVATEMODEFUNC (pad);
2912   if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
2913
2914     pad_monitor->chain_func = GST_PAD_CHAINFUNC (pad);
2915     if (pad_monitor->chain_func)
2916       gst_pad_set_chain_function (pad, gst_validate_pad_monitor_chain_func);
2917
2918     if (pad_monitor->event_full_func)
2919       gst_pad_set_event_full_function (pad,
2920           gst_validate_pad_monitor_sink_event_full_func);
2921     else
2922       gst_pad_set_event_function (pad,
2923           gst_validate_pad_monitor_sink_event_func);
2924   } else {
2925     gst_pad_set_event_function (pad, gst_validate_pad_monitor_src_event_func);
2926
2927     /* add buffer/event probes */
2928     pad_monitor->pad_probe_id =
2929         gst_pad_add_probe (pad,
2930         GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM |
2931         GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2932         (GstPadProbeCallback) gst_validate_pad_monitor_pad_probe, pad_monitor,
2933         NULL);
2934   }
2935   gst_pad_set_query_function (pad, gst_validate_pad_monitor_query_func);
2936   gst_pad_set_activatemode_function (pad,
2937       gst_validate_pad_monitor_activatemode_func);
2938
2939   gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (monitor),
2940       g_strdup_printf ("%s:%s", GST_DEBUG_PAD_NAME (pad)));
2941
2942   if (G_UNLIKELY (GST_PAD_PARENT (pad) == NULL))
2943     GST_FIXME ("Saw a pad not belonging to any object");
2944
2945   gst_validate_pad_monitor_get_min_buffer_frequency (pad_monitor, pad);
2946
2947   gst_object_unref (pad);
2948   return TRUE;
2949 }