validate: Do not check pulling thread when thread is paused
[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 reset 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           g_value_reset (&value);
1642           continue;
1643         }
1644
1645         othermonitor = _GET_PAD_MONITOR (otherpad);
1646         if (!othermonitor) {
1647           g_value_reset (&value);
1648           continue;
1649         }
1650
1651         GST_VALIDATE_MONITOR_LOCK (othermonitor);
1652         gst_event_replace (&othermonitor->expected_segment, event);
1653         GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1654         g_value_reset (&value);
1655         break;
1656       case GST_ITERATOR_RESYNC:
1657         gst_iterator_resync (iter);
1658         break;
1659       case GST_ITERATOR_ERROR:
1660         GST_WARNING_OBJECT (pad, "Internal links pad iteration error");
1661         done = TRUE;
1662         break;
1663       case GST_ITERATOR_DONE:
1664         done = TRUE;
1665         break;
1666     }
1667   }
1668   gst_iterator_free (iter);
1669   gst_object_unref (pad);
1670 }
1671
1672 /* common checks for both sink and src event functions */
1673 static void
1674 gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor *
1675     pad_monitor, GstEvent * event)
1676 {
1677   guint32 seqnum = gst_event_get_seqnum (event);
1678
1679   if (seqnum == GST_SEQNUM_INVALID)
1680     GST_VALIDATE_REPORT (pad_monitor, EVENT_INVALID_SEQNUM,
1681         "Event %p (%s) has an invalid SEQNUM", event,
1682         GST_EVENT_TYPE_NAME (event));
1683
1684   switch (GST_EVENT_TYPE (event)) {
1685     case GST_EVENT_FLUSH_START:
1686     {
1687       if (pad_monitor->pending_flush_start_seqnum != GST_SEQNUM_INVALID) {
1688         if (seqnum == pad_monitor->pending_flush_start_seqnum) {
1689           pad_monitor->pending_flush_start_seqnum = GST_SEQNUM_INVALID;
1690         } else {
1691           GST_VALIDATE_REPORT (pad_monitor, FLUSH_START_HAS_WRONG_SEQNUM,
1692               "Got: %u Expected: %u", seqnum,
1693               pad_monitor->pending_flush_start_seqnum);
1694         }
1695       }
1696
1697       if (pad_monitor->pending_flush_stop) {
1698         GST_VALIDATE_REPORT (pad_monitor, EVENT_FLUSH_START_UNEXPECTED,
1699             "Received flush-start from when flush-stop was expected");
1700       }
1701       pad_monitor->pending_flush_stop = TRUE;
1702     }
1703       break;
1704     case GST_EVENT_FLUSH_STOP:
1705     {
1706       if (pad_monitor->pending_flush_stop_seqnum != GST_SEQNUM_INVALID) {
1707         if (seqnum == pad_monitor->pending_flush_stop_seqnum) {
1708           pad_monitor->pending_flush_stop_seqnum = GST_SEQNUM_INVALID;
1709         } else {
1710           GST_VALIDATE_REPORT (pad_monitor, FLUSH_STOP_HAS_WRONG_SEQNUM,
1711               "Got: %u Expected: %u", seqnum,
1712               pad_monitor->pending_flush_stop_seqnum);
1713         }
1714       }
1715
1716       pad_monitor->pending_newsegment_seqnum = seqnum;
1717       pad_monitor->pending_eos_seqnum = seqnum;
1718
1719       if (!pad_monitor->pending_flush_stop) {
1720         gchar *event_str = _get_event_string (event);
1721
1722         GST_VALIDATE_REPORT (pad_monitor, EVENT_FLUSH_STOP_UNEXPECTED,
1723             "Unexpected flush-stop %s", event_str);
1724         g_free (event_str);
1725       }
1726       pad_monitor->pending_flush_stop = FALSE;
1727
1728       /* Buffers following a FLUSH should have the DISCONT flag set */
1729       pad_monitor->pending_buffer_discont = TRUE;
1730
1731       /* cleanup our data */
1732       gst_validate_pad_monitor_flush (pad_monitor);
1733     }
1734       break;
1735     default:
1736       break;
1737   }
1738 }
1739
1740 static void
1741 mark_pads_eos (GstValidatePadMonitor * pad_monitor)
1742 {
1743   GstValidatePadMonitor *peer_monitor;
1744   GstPad *real_peer;
1745   GstPad *pad =
1746       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1747           (pad_monitor)));
1748   GstPad *peer = gst_pad_get_peer (pad);
1749
1750   gst_object_unref (pad);
1751   pad_monitor->is_eos = TRUE;
1752   if (peer) {
1753     real_peer = _get_actual_pad (peer);
1754     peer_monitor = _GET_PAD_MONITOR (real_peer);
1755     if (peer_monitor)
1756       peer_monitor->is_eos = TRUE;
1757     gst_object_unref (peer);
1758     gst_object_unref (real_peer);
1759   }
1760 }
1761
1762 static inline gboolean
1763 _should_check_buffers (GstValidatePadMonitor * pad_monitor,
1764     gboolean force_checks)
1765 {
1766   GstPad *pad =
1767       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1768           (pad_monitor)));
1769   GstValidateMonitor *monitor = GST_VALIDATE_MONITOR (pad_monitor);
1770
1771   if (pad_monitor->first_buffer || force_checks) {
1772     if (pad_monitor->segment.rate != 1.0) {
1773       GST_INFO_OBJECT (pad_monitor, "We do not support buffer checking"
1774           " for trick modes");
1775
1776       pad_monitor->check_buffers = FALSE;
1777     } else if (!PAD_PARENT_IS_DECODER (pad_monitor)) {
1778       GST_DEBUG_OBJECT (pad, "Not on a decoder => no buffer checking");
1779
1780       pad_monitor->check_buffers = FALSE;
1781     } else if (GST_PAD_DIRECTION (pad) != GST_PAD_SINK) {
1782       GST_DEBUG_OBJECT (pad, "Not a sinkpad => no buffer checking");
1783
1784       pad_monitor->check_buffers = FALSE;
1785     } else if (!pad_monitor->caps_is_video) {
1786       GST_DEBUG_OBJECT (pad, "Not working with video => no buffer checking");
1787
1788       pad_monitor->check_buffers = FALSE;
1789     } else if (monitor->media_descriptor == NULL) {
1790       GST_DEBUG_OBJECT (pad, "No media_descriptor set => no buffer checking");
1791
1792       pad_monitor->check_buffers = FALSE;
1793     } else if (!gst_validate_media_descriptor_detects_frames
1794         (monitor->media_descriptor)) {
1795       GST_DEBUG_OBJECT (pad,
1796           "No frame detection media descriptor => no buffer checking");
1797       pad_monitor->check_buffers = FALSE;
1798     } else if (pad_monitor->all_bufs == NULL &&
1799         !gst_validate_media_descriptor_get_buffers (monitor->media_descriptor,
1800             pad, NULL, &pad_monitor->all_bufs)) {
1801
1802       GST_INFO_OBJECT (monitor,
1803           "The MediaInfo is marked as detecting frame, but getting frames"
1804           " from pad %" GST_PTR_FORMAT " did not work (some format conversion"
1805           " might be happening)", pad);
1806
1807       pad_monitor->check_buffers = FALSE;
1808     } else {
1809       if (!pad_monitor->current_buf)
1810         pad_monitor->current_buf = pad_monitor->all_bufs;
1811       pad_monitor->check_buffers = TRUE;
1812     }
1813   }
1814   gst_object_unref (pad);
1815
1816   return pad_monitor->check_buffers;
1817 }
1818
1819 static void
1820 gst_validate_monitor_find_next_buffer (GstValidatePadMonitor * pad_monitor)
1821 {
1822   GList *tmp;
1823   gboolean passed_start = FALSE;
1824
1825   if (!_should_check_buffers (pad_monitor, TRUE))
1826     return;
1827
1828   for (tmp = g_list_last (pad_monitor->all_bufs); tmp; tmp = tmp->prev) {
1829     GstBuffer *cbuf = (GstBuffer *) tmp->data;
1830     GstClockTime ts =
1831         GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DTS (cbuf)) ? GST_BUFFER_DTS (cbuf)
1832         : GST_BUFFER_PTS (cbuf);
1833
1834     if (!GST_CLOCK_TIME_IS_VALID (ts))
1835       continue;
1836
1837     if (ts <= pad_monitor->segment.start)
1838       passed_start = TRUE;
1839
1840     if (!passed_start)
1841       continue;
1842
1843     if (!GST_BUFFER_FLAG_IS_SET (cbuf, GST_BUFFER_FLAG_DELTA_UNIT)) {
1844       break;
1845     }
1846   }
1847
1848   if (tmp == NULL)
1849     pad_monitor->current_buf = pad_monitor->all_bufs;
1850   else
1851     pad_monitor->current_buf = tmp;
1852 }
1853
1854 /* Checks whether a segment is just an update of another,
1855  * That is to say that only the base and offset field differ and all
1856  * other fields are identical */
1857 static gboolean
1858 is_segment_update (GstSegment * a, const GstSegment * b)
1859 {
1860   /* Note : We never care about the position field, it is only
1861    * used for internal usage by elements */
1862   if (a->rate == b->rate &&
1863       a->applied_rate == b->applied_rate &&
1864       a->format == b->format && a->time == b->time) {
1865     /* Changes in base/offset are considered updates */
1866     /* Updating the end position of a segment is an update */
1867     /* Updating the duration of a segment is an update */
1868     if (a->rate > 0.0) {
1869       if (a->start == b->start)
1870         return TRUE;
1871     } else {
1872       if (a->stop == b->stop)
1873         return TRUE;
1874     }
1875   }
1876   return FALSE;
1877 }
1878
1879 static GstFlowReturn
1880 gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor *
1881     pad_monitor, GstObject * parent, GstEvent * event,
1882     GstPadEventFunction handler)
1883 {
1884   GstFlowReturn ret = GST_FLOW_OK;
1885   const GstSegment *segment;
1886   guint32 seqnum = gst_event_get_seqnum (event);
1887   GstPad *pad =
1888       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1889           (pad_monitor)));
1890
1891   gst_validate_pad_monitor_common_event_check (pad_monitor, event);
1892
1893   /* pre checks */
1894   switch (GST_EVENT_TYPE (event)) {
1895     case GST_EVENT_STREAM_START:
1896       /* Buffers following a STREAM_START should have the DISCONT flag set */
1897       pad_monitor->pending_buffer_discont = TRUE;
1898       break;
1899     case GST_EVENT_SEGMENT:
1900       /* parse segment data to be used if event is handled */
1901       gst_event_parse_segment (event, &segment);
1902
1903       GST_DEBUG_OBJECT (pad, "Got segment %" GST_SEGMENT_FORMAT, segment);
1904
1905       /* Reset expected flush start/stop values, we have a segment */
1906       pad_monitor->pending_flush_start_seqnum = GST_SEQNUM_INVALID;
1907       pad_monitor->pending_flush_stop_seqnum = GST_SEQNUM_INVALID;
1908
1909       if (pad_monitor->pending_newsegment_seqnum != GST_SEQNUM_INVALID) {
1910         if (pad_monitor->pending_newsegment_seqnum == seqnum) {
1911           pad_monitor->pending_newsegment_seqnum = GST_SEQNUM_INVALID;
1912           if (GST_CLOCK_TIME_IS_VALID (pad_monitor->pending_seek_accurate_time)) {
1913             if (segment->time == pad_monitor->pending_seek_accurate_time) {
1914               pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE;
1915             } else {
1916               GST_VALIDATE_REPORT (pad_monitor, SEGMENT_HAS_WRONG_START,
1917                   "After an accurate seek, got: %" GST_TIME_FORMAT
1918                   " Expected: %" GST_TIME_FORMAT, GST_TIME_ARGS (segment->time),
1919                   GST_TIME_ARGS (pad_monitor->pending_seek_accurate_time));
1920             }
1921           }
1922         } else {
1923           GST_VALIDATE_REPORT (pad_monitor, SEGMENT_HAS_WRONG_SEQNUM,
1924               "Got: %u Expected: %u", seqnum, pad_monitor->pending_eos_seqnum);
1925         }
1926       }
1927
1928       pad_monitor->pending_eos_seqnum = seqnum;
1929
1930       if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
1931         gst_validate_pad_monitor_add_expected_newsegment (pad_monitor, event);
1932       } else {
1933         /* check if this segment is the expected one */
1934         if (pad_monitor->expected_segment) {
1935           const GstSegment *exp_segment;
1936
1937           if (pad_monitor->expected_segment != event) {
1938             gst_event_parse_segment (pad_monitor->expected_segment,
1939                 &exp_segment);
1940             if (segment->format == exp_segment->format) {
1941               if ((exp_segment->rate * exp_segment->applied_rate !=
1942                       segment->rate * segment->applied_rate))
1943                 GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH,
1944                     "Rate * applied_rate %f != expected %f",
1945                     segment->rate * segment->applied_rate,
1946                     exp_segment->rate * exp_segment->applied_rate);
1947               if (exp_segment->start != segment->start)
1948                 GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH,
1949                     "Start %" GST_TIME_FORMAT " != expected %" GST_TIME_FORMAT,
1950                     GST_TIME_ARGS (segment->start),
1951                     GST_TIME_ARGS (exp_segment->start));
1952               if (exp_segment->stop != segment->stop)
1953                 GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH,
1954                     "Stop %" GST_TIME_FORMAT " != expected %" GST_TIME_FORMAT,
1955                     GST_TIME_ARGS (segment->stop),
1956                     GST_TIME_ARGS (exp_segment->stop));
1957               if (exp_segment->position != segment->position)
1958                 GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH,
1959                     "Position %" GST_TIME_FORMAT " != expected %"
1960                     GST_TIME_FORMAT, GST_TIME_ARGS (segment->position),
1961                     GST_TIME_ARGS (exp_segment->position));
1962             }
1963           }
1964           gst_event_replace (&pad_monitor->expected_segment, NULL);
1965         }
1966       }
1967       break;
1968     case GST_EVENT_CAPS:{
1969       GstCaps *caps;
1970
1971       gst_event_parse_caps (event, &caps);
1972       gst_validate_pad_monitor_setcaps_pre (pad_monitor, caps);
1973       break;
1974     }
1975     case GST_EVENT_EOS:
1976       pad_monitor->is_eos = TRUE;
1977       /* FIXME : This feels and looks wrong ... */
1978       if (pad_monitor->pending_eos_seqnum == GST_SEQNUM_INVALID) {
1979         GST_VALIDATE_REPORT (pad_monitor, EVENT_EOS_WITHOUT_SEGMENT,
1980             "EOS %" GST_PTR_FORMAT " received before a segment was received",
1981             event);
1982       } else if (pad_monitor->pending_eos_seqnum != seqnum) {
1983         GST_VALIDATE_REPORT (pad_monitor, EOS_HAS_WRONG_SEQNUM,
1984             "Got: %u. Expected: %u", seqnum, pad_monitor->pending_eos_seqnum);
1985       }
1986
1987       /*
1988        * TODO add end of stream checks for
1989        *  - events not pushed
1990        *  - buffer data not pushed
1991        *  - pending events not received
1992        */
1993       break;
1994
1995       /* both flushes are handled by the common event function */
1996     case GST_EVENT_FLUSH_START:
1997     case GST_EVENT_FLUSH_STOP:
1998     case GST_EVENT_TAG:
1999     case GST_EVENT_SINK_MESSAGE:
2000     default:
2001       break;
2002   }
2003
2004   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
2005   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
2006   gst_validate_pad_monitor_event_overrides (pad_monitor, event);
2007   if (handler) {
2008     gst_event_ref (event);
2009     if (pad_monitor->event_full_func)
2010       ret = pad_monitor->event_full_func (pad, parent, event);
2011     else if (pad_monitor->event_func (pad, parent, event))
2012       ret = GST_FLOW_OK;
2013     else
2014       ret = GST_FLOW_ERROR;
2015   }
2016   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
2017   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
2018
2019   /* post checks */
2020   switch (GST_EVENT_TYPE (event)) {
2021     case GST_EVENT_SEGMENT:
2022       if (ret == GST_FLOW_OK) {
2023         /* If the new segment is not an update of the previous one, then
2024          * the following buffer should have the DISCONT flag set */
2025         if (!is_segment_update (&pad_monitor->segment, segment))
2026           pad_monitor->pending_buffer_discont = TRUE;
2027         if (!pad_monitor->has_segment
2028             && pad_monitor->segment.format != segment->format) {
2029           gst_segment_init (&pad_monitor->segment, segment->format);
2030         }
2031         gst_segment_copy_into (segment, &pad_monitor->segment);
2032         pad_monitor->has_segment = TRUE;
2033         gst_validate_monitor_find_next_buffer (pad_monitor);
2034       }
2035       break;
2036     case GST_EVENT_CAPS:{
2037       GstCaps *caps;
2038
2039       gst_event_parse_caps (event, &caps);
2040       gst_validate_pad_monitor_setcaps_post (pad_monitor, caps,
2041           ret == GST_FLOW_OK);
2042       break;
2043     }
2044     case GST_EVENT_FLUSH_START:
2045     case GST_EVENT_FLUSH_STOP:
2046     case GST_EVENT_EOS:
2047     case GST_EVENT_TAG:
2048     case GST_EVENT_SINK_MESSAGE:
2049     default:
2050       break;
2051   }
2052
2053   if (handler)
2054     gst_event_unref (event);
2055   gst_object_unref (pad);
2056   return ret;
2057 }
2058
2059 static gboolean
2060 gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor,
2061     GstObject * parent, GstEvent * event, GstPadEventFunction handler)
2062 {
2063   gboolean ret = TRUE;
2064   gdouble rate;
2065   GstFormat format;
2066   gint64 start, stop;
2067   GstSeekFlags seek_flags;
2068   GstSeekType start_type, stop_type;
2069   guint32 seqnum = gst_event_get_seqnum (event);
2070   GstPad *pad =
2071       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
2072           (pad_monitor)));
2073
2074   gst_validate_pad_monitor_common_event_check (pad_monitor, event);
2075
2076   /* pre checks */
2077   switch (GST_EVENT_TYPE (event)) {
2078     case GST_EVENT_SEEK:
2079     {
2080       gst_event_parse_seek (event, &rate, &format, &seek_flags, &start_type,
2081           &start, &stop_type, &stop);
2082       /* upstream seek - store the seek event seqnum to check
2083        * flushes and newsegments share the same */
2084     }
2085       break;
2086       /* both flushes are handled by the common event handling function */
2087     case GST_EVENT_FLUSH_START:
2088     case GST_EVENT_FLUSH_STOP:
2089     case GST_EVENT_NAVIGATION:
2090     case GST_EVENT_LATENCY:
2091     case GST_EVENT_STEP:
2092     case GST_EVENT_QOS:
2093     default:
2094       break;
2095   }
2096
2097   if (handler) {
2098     GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
2099     /* Safely store pending accurate seek values */
2100     if (GST_EVENT_TYPE (event) == GST_EVENT_SEEK) {
2101       if (seek_flags & GST_SEEK_FLAG_ACCURATE && format == GST_FORMAT_TIME) {
2102         GST_DEBUG_OBJECT (pad,
2103             "Storing expected accurate seek time %" GST_TIME_FORMAT,
2104             GST_TIME_ARGS (start));
2105         pad_monitor->pending_seek_accurate_time = start;
2106       }
2107       /* TODO we might need to use a list as multiple seeks can be sent
2108        * before the flushes arrive here */
2109       if (seek_flags & GST_SEEK_FLAG_FLUSH) {
2110         pad_monitor->pending_flush_start_seqnum = seqnum;
2111         pad_monitor->pending_flush_stop_seqnum = seqnum;
2112       }
2113     }
2114
2115     gst_event_ref (event);
2116     ret = pad_monitor->event_func (pad, parent, event);
2117
2118     if (GST_EVENT_TYPE (event) == GST_EVENT_SEEK) {
2119       /* If the seek was already handled (same current seqnum), reset the
2120        * expected accurate seek value */
2121       if (ret && pad_monitor->has_segment
2122           && seqnum == pad_monitor->pending_eos_seqnum) {
2123         GST_DEBUG_OBJECT (pad,
2124             "Resetting expected accurate seek value, was already handled");
2125         pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE;
2126       } else if (!ret) {
2127         /* do not expect any of these events anymore */
2128         pad_monitor->pending_flush_start_seqnum = GST_SEQNUM_INVALID;
2129         pad_monitor->pending_flush_stop_seqnum = GST_SEQNUM_INVALID;
2130         pad_monitor->pending_newsegment_seqnum = GST_SEQNUM_INVALID;
2131         pad_monitor->pending_eos_seqnum = GST_SEQNUM_INVALID;
2132         pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE;
2133       }
2134     }
2135     GST_VALIDATE_MONITOR_LOCK (pad_monitor);
2136   }
2137
2138   /* post checks */
2139   switch (GST_EVENT_TYPE (event)) {
2140     case GST_EVENT_FLUSH_START:
2141     case GST_EVENT_FLUSH_STOP:
2142     case GST_EVENT_QOS:
2143     case GST_EVENT_SEEK:
2144     case GST_EVENT_NAVIGATION:
2145     case GST_EVENT_LATENCY:
2146     case GST_EVENT_STEP:
2147     default:
2148       break;
2149   }
2150
2151   if (handler)
2152     gst_event_unref (event);
2153   gst_object_unref (pad);
2154   return ret;
2155 }
2156
2157 static gboolean
2158 gst_validate_pad_monitor_check_right_buffer (GstValidatePadMonitor *
2159     pad_monitor, GstBuffer * buffer)
2160 {
2161   gchar *checksum;
2162   GstBuffer *wanted_buf;
2163   GstMapInfo map, wanted_map;
2164
2165   gboolean ret = TRUE;
2166   GstPad *pad;
2167
2168
2169   if (_should_check_buffers (pad_monitor, FALSE) == FALSE)
2170     return FALSE;
2171
2172   pad =
2173       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
2174           (pad_monitor)));
2175   if (pad_monitor->current_buf == NULL) {
2176     GST_INFO_OBJECT (pad, "No current buffer one pad, Why?");
2177     gst_object_unref (pad);
2178     return FALSE;
2179   }
2180
2181   wanted_buf = pad_monitor->current_buf->data;
2182
2183   if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (wanted_buf)) &&
2184       GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (buffer)) &&
2185       GST_BUFFER_PTS (wanted_buf) != GST_BUFFER_PTS (buffer)) {
2186
2187     GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER,
2188         "buffer %" GST_PTR_FORMAT " PTS %" GST_TIME_FORMAT
2189         " different than expected: %" GST_TIME_FORMAT, buffer,
2190         GST_TIME_ARGS (GST_BUFFER_PTS (buffer)),
2191         GST_TIME_ARGS (GST_BUFFER_PTS (wanted_buf)));
2192
2193     ret = FALSE;
2194   }
2195
2196   if (GST_BUFFER_DTS (wanted_buf) != GST_BUFFER_DTS (buffer)) {
2197     GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER,
2198         "buffer %" GST_PTR_FORMAT " DTS %" GST_TIME_FORMAT
2199         " different than expected: %" GST_TIME_FORMAT, buffer,
2200         GST_TIME_ARGS (GST_BUFFER_DTS (buffer)),
2201         GST_TIME_ARGS (GST_BUFFER_DTS (wanted_buf)));
2202     ret = FALSE;
2203   }
2204
2205   if (GST_BUFFER_DURATION (wanted_buf) != GST_BUFFER_DURATION (buffer)) {
2206     GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER,
2207         "buffer %" GST_PTR_FORMAT " DURATION %" GST_TIME_FORMAT
2208         " different than expected: %" GST_TIME_FORMAT, buffer,
2209         GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)),
2210         GST_TIME_ARGS (GST_BUFFER_DURATION (wanted_buf)));
2211     ret = FALSE;
2212   }
2213
2214   if (GST_BUFFER_FLAG_IS_SET (wanted_buf, GST_BUFFER_FLAG_DELTA_UNIT) !=
2215       GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)) {
2216     GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER,
2217         "buffer %" GST_PTR_FORMAT "  Delta unit is set to %s but expected %s",
2218         buffer, GST_BUFFER_FLAG_IS_SET (buffer,
2219             GST_BUFFER_FLAG_DELTA_UNIT) ? "True" : "False",
2220         GST_BUFFER_FLAG_IS_SET (wanted_buf,
2221             GST_BUFFER_FLAG_DELTA_UNIT) ? "True" : "False");
2222     ret = FALSE;
2223   }
2224
2225   g_assert (gst_buffer_map (wanted_buf, &wanted_map, GST_MAP_READ));
2226   g_assert (gst_buffer_map (buffer, &map, GST_MAP_READ));
2227
2228   checksum = g_compute_checksum_for_data (G_CHECKSUM_MD5,
2229       (const guchar *) map.data, map.size);
2230
2231   if (g_strcmp0 ((gchar *) wanted_map.data, checksum)) {
2232     GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER,
2233         "buffer %" GST_PTR_FORMAT " checksum %s different from expected: %s",
2234         buffer, checksum, wanted_map.data);
2235     ret = FALSE;
2236   }
2237
2238   gst_buffer_unmap (wanted_buf, &wanted_map);
2239   gst_buffer_unmap (buffer, &map);
2240   g_free (checksum);
2241   gst_object_unref (pad);
2242
2243   pad_monitor->current_buf = pad_monitor->current_buf->next;
2244
2245   return ret;
2246 }
2247
2248 static void
2249 gst_validate_pad_monitor_check_return (GstValidatePadMonitor * pad_monitor,
2250     GstFlowReturn ret)
2251 {
2252   GstValidateMonitor *parent = GST_VALIDATE_MONITOR (pad_monitor);
2253
2254   if (ret != GST_FLOW_ERROR)
2255     return;
2256
2257   while (GST_VALIDATE_MONITOR_GET_PARENT (parent))
2258     parent = GST_VALIDATE_MONITOR_GET_PARENT (parent);
2259
2260   if (GST_IS_VALIDATE_PIPELINE_MONITOR (parent)) {
2261     GstValidatePipelineMonitor *m = GST_VALIDATE_PIPELINE_MONITOR (parent);
2262
2263     GST_VALIDATE_MONITOR_LOCK (m);
2264     if (m->got_error == FALSE) {
2265       GST_VALIDATE_REPORT (pad_monitor, FLOW_ERROR_WITHOUT_ERROR_MESSAGE,
2266           "Pad return GST_FLOW_ERROR but no GST_MESSAGE_ERROR was received on"
2267           " the bus");
2268
2269       /* Only report it the first time */
2270       m->got_error = TRUE;
2271     }
2272     GST_VALIDATE_MONITOR_UNLOCK (m);
2273   }
2274 }
2275
2276 static GstFlowReturn
2277 gst_validate_pad_monitor_chain_func (GstPad * pad, GstObject * parent,
2278     GstBuffer * buffer)
2279 {
2280   GstValidatePadMonitor *pad_monitor = _GET_PAD_MONITOR (pad);
2281   GstFlowReturn ret;
2282
2283   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
2284   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
2285
2286   gst_validate_pad_monitor_check_discont (pad_monitor, buffer);
2287   gst_validate_pad_monitor_check_right_buffer (pad_monitor, buffer);
2288   gst_validate_pad_monitor_check_first_buffer (pad_monitor, buffer);
2289   gst_validate_pad_monitor_update_buffer_data (pad_monitor, buffer);
2290   gst_validate_pad_monitor_check_eos (pad_monitor, buffer);
2291
2292   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
2293   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
2294
2295   gst_validate_pad_monitor_buffer_overrides (pad_monitor, buffer);
2296
2297   ret = pad_monitor->chain_func (pad, parent, buffer);
2298
2299   gst_validate_pad_monitor_check_return (pad_monitor, ret);
2300
2301   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
2302   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
2303
2304   pad_monitor->last_flow_return = ret;
2305   if (ret == GST_FLOW_EOS) {
2306     mark_pads_eos (pad_monitor);
2307   }
2308   if (PAD_PARENT_IS_DEMUXER (pad_monitor))
2309     gst_validate_pad_monitor_check_aggregated_return (pad_monitor, parent, ret);
2310
2311   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
2312   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
2313
2314   return ret;
2315 }
2316
2317 static gboolean
2318 gst_validate_pad_monitor_event_is_tracked (GstValidatePadMonitor * monitor,
2319     GstEvent * event)
2320 {
2321   if (!GST_EVENT_IS_SERIALIZED (event)) {
2322     return FALSE;
2323   }
2324
2325   /* we don't track Tag events because they mutate too much and it is hard
2326    * to match a tag event pushed on a source pad with the one that was received
2327    * on a sink pad.
2328    * One idea would be to use seqnum, but it seems that it is undefined whether
2329    * seqnums should be maintained in tag events that are created from others
2330    * up to today. (2013-08-29)
2331    */
2332   if (GST_EVENT_TYPE (event) == GST_EVENT_TAG)
2333     return FALSE;
2334
2335   return TRUE;
2336 }
2337
2338 static GstFlowReturn
2339 gst_validate_pad_monitor_sink_event_full_func (GstPad * pad, GstObject * parent,
2340     GstEvent * event)
2341 {
2342   GstValidatePadMonitor *pad_monitor = _GET_PAD_MONITOR (pad);
2343   GstFlowReturn ret;
2344
2345   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
2346   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
2347
2348   GST_DEBUG_OBJECT (pad, "event %p %s", event, GST_EVENT_TYPE_NAME (event));
2349
2350   if (gst_validate_pad_monitor_event_is_tracked (pad_monitor, event)) {
2351     GstClockTime last_ts = GST_CLOCK_TIME_NONE;
2352     if (GST_CLOCK_TIME_IS_VALID (pad_monitor->current_timestamp)) {
2353       last_ts = pad_monitor->current_timestamp;
2354       if (GST_CLOCK_TIME_IS_VALID (pad_monitor->current_duration)) {
2355         last_ts += pad_monitor->current_duration;
2356       }
2357     }
2358     gst_validate_pad_monitor_otherpad_add_pending_serialized_event (pad_monitor,
2359         event, last_ts);
2360   }
2361
2362   ret =
2363       gst_validate_pad_monitor_downstream_event_check (pad_monitor, parent,
2364       event, pad_monitor->event_func);
2365
2366   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
2367   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
2368   return ret;
2369 }
2370
2371 static gboolean
2372 gst_validate_pad_monitor_sink_event_func (GstPad * pad, GstObject * parent,
2373     GstEvent * event)
2374 {
2375   if (gst_validate_pad_monitor_sink_event_full_func (pad, parent,
2376           event) == GST_FLOW_OK)
2377     return TRUE;
2378   return FALSE;
2379 }
2380
2381 static gboolean
2382 gst_validate_pad_monitor_src_event_func (GstPad * pad, GstObject * parent,
2383     GstEvent * event)
2384 {
2385   GstValidatePadMonitor *pad_monitor = _GET_PAD_MONITOR (pad);
2386   gboolean ret;
2387
2388   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
2389   ret = gst_validate_pad_monitor_src_event_check (pad_monitor, parent, event,
2390       pad_monitor->event_func);
2391   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
2392   return ret;
2393 }
2394
2395 static gboolean
2396 gst_validate_pad_monitor_query_func (GstPad * pad, GstObject * parent,
2397     GstQuery * query)
2398 {
2399   GstValidatePadMonitor *pad_monitor = _GET_PAD_MONITOR (pad);
2400   gboolean ret;
2401
2402   gst_validate_pad_monitor_query_overrides (pad_monitor, query);
2403   ret = pad_monitor->query_func (pad, parent, query);
2404
2405   if (ret) {
2406     switch (GST_QUERY_TYPE (query)) {
2407       case GST_QUERY_ACCEPT_CAPS:
2408       {
2409         gboolean result;
2410
2411         gst_caps_replace (&pad_monitor->last_refused_caps, NULL);
2412         gst_query_parse_accept_caps_result (query, &result);
2413         if (!result) {
2414           GstCaps *refused_caps;
2415
2416           gst_query_parse_accept_caps (query, &refused_caps);
2417           pad_monitor->last_refused_caps = gst_caps_copy (refused_caps);
2418
2419         }
2420
2421         break;
2422       }
2423       case GST_QUERY_CAPS:{
2424         GstCaps *res;
2425         GstCaps *filter;
2426
2427         /* We shouldn't need to lock the parent as this doesn't modify
2428          * other monitors, just does some peer_pad_caps */
2429         GST_VALIDATE_MONITOR_LOCK (pad_monitor);
2430
2431         gst_query_parse_caps (query, &filter);
2432         gst_query_parse_caps_result (query, &res);
2433
2434         gst_caps_replace (&pad_monitor->last_query_res, NULL);
2435         gst_caps_replace (&pad_monitor->last_query_filter, NULL);
2436         pad_monitor->last_query_res =
2437             res ? gst_caps_copy (res) : gst_caps_ref (GST_CAPS_NONE);
2438         pad_monitor->last_query_filter =
2439             filter ? gst_caps_copy (filter) : gst_caps_ref (GST_CAPS_NONE);
2440
2441         if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
2442           gst_validate_pad_monitor_check_caps_fields_proxied (pad_monitor, res,
2443               filter);
2444         }
2445         GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
2446         break;
2447       }
2448       default:
2449         break;
2450     }
2451   }
2452
2453   return ret;
2454 }
2455
2456 static gboolean
2457 gst_validate_pad_monitor_activatemode_func (GstPad * pad, GstObject * parent,
2458     GstPadMode mode, gboolean active)
2459 {
2460   GstValidatePadMonitor *pad_monitor = _GET_PAD_MONITOR (pad);
2461   gboolean ret = TRUE;
2462
2463   /* TODO add overrides for activate func */
2464   GST_DEBUG_OBJECT (pad, "active:%d", active);
2465
2466   if (pad_monitor->activatemode_func)
2467     ret = pad_monitor->activatemode_func (pad, parent, mode, active);
2468   if (ret && active == FALSE) {
2469     GST_VALIDATE_MONITOR_LOCK (pad_monitor);
2470     gst_validate_pad_monitor_reset (pad_monitor);
2471     GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
2472   }
2473
2474   return ret;
2475 }
2476
2477 static GstFlowReturn
2478 gst_validate_pad_monitor_get_range_func (GstPad * pad, GstObject * parent,
2479     guint64 offset, guint length, GstBuffer ** buffer)
2480 {
2481   GstValidatePadMonitor *pad_monitor = _GET_PAD_MONITOR (pad);
2482
2483   if (pad_monitor->get_range_func) {
2484     GstPad *peer = gst_pad_get_peer (pad);
2485     GstTask *task = NULL;
2486     GThread *thread = NULL;
2487
2488     if (peer) {
2489       GST_OBJECT_LOCK (peer);
2490       task = GST_PAD_TASK (peer);
2491       if (task && GST_TASK_STATE (task) == GST_TASK_STARTED) {
2492         GST_OBJECT_LOCK (task);
2493         /* Only doing pointer comparison, no need to hold a ref */
2494         thread = task->thread;
2495         GST_OBJECT_UNLOCK (task);
2496       }
2497       GST_OBJECT_UNLOCK (peer);
2498
2499       if (thread && thread != g_thread_self ()) {
2500         GST_VALIDATE_REPORT (pad_monitor, PULL_RANGE_FROM_WRONG_THREAD,
2501             "Pulling from wrong thread, expected pad thread: %p, got %p",
2502             task->thread, g_thread_self ());
2503       }
2504
2505       gst_object_unref (peer);
2506     }
2507
2508     return pad_monitor->get_range_func (pad, parent, offset, length, buffer);
2509   }
2510
2511   return GST_FLOW_NOT_SUPPORTED;
2512
2513 }
2514
2515 /* The interval between two buffer frequency checks */
2516 #define BUF_FREQ_CHECK_INTERVAL (GST_SECOND)
2517
2518 static void
2519 gst_validate_pad_monitor_check_buffer_freq (GstValidatePadMonitor * monitor,
2520     GstPad * pad)
2521 {
2522   GstClockTime ts;
2523
2524   if (!GST_PAD_IS_SRC (pad))
2525     return;
2526
2527   if (!monitor->min_buf_freq)
2528     return;
2529
2530   ts = gst_util_get_timestamp ();
2531   monitor->buffers_pushed++;
2532
2533   /* Same logic as in fpsdisplaysink to compute the buffer frequency */
2534   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID
2535           (monitor->min_buf_freq_first_buffer_ts))) {
2536     monitor->min_buf_freq_first_buffer_ts = ts;
2537     monitor->min_buf_freq_interval_ts = ts;
2538     return;
2539   }
2540
2541   if (GST_CLOCK_DIFF (monitor->min_buf_freq_interval_ts,
2542           ts) > BUF_FREQ_CHECK_INTERVAL) {
2543     guint time_diff;
2544     gdouble fps;
2545
2546     time_diff = (gdouble) (ts - monitor->min_buf_freq_interval_ts) / GST_SECOND;
2547     fps =
2548         (gdouble) (monitor->buffers_pushed -
2549         monitor->last_buffers_pushed) / time_diff;
2550
2551     if (fps < monitor->min_buf_freq) {
2552       if (GST_CLOCK_TIME_IS_VALID (monitor->min_buf_freq_start) &&
2553           GST_CLOCK_DIFF (monitor->min_buf_freq_first_buffer_ts,
2554               ts) < monitor->min_buf_freq_start) {
2555         GST_DEBUG_OBJECT (pad,
2556             "buffer frequency is too low (%.2f) but ignore for now (buffer-frequency-start =%"
2557             GST_TIME_FORMAT ")", fps,
2558             GST_TIME_ARGS (monitor->min_buf_freq_start));
2559       } else {
2560         GST_VALIDATE_REPORT (monitor, CONFIG_BUFFER_FREQUENCY_TOO_LOW,
2561             "Buffers are not pushed fast enough on this pad: %.2f/sec (minimum: %.2f)",
2562             fps, monitor->min_buf_freq);
2563       }
2564     }
2565
2566     monitor->last_buffers_pushed = monitor->buffers_pushed;
2567     monitor->min_buf_freq_interval_ts = ts;
2568   }
2569 }
2570
2571 static gboolean
2572 gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer,
2573     gpointer udata, gboolean pull_mode)
2574 {
2575   GstValidatePadMonitor *monitor = udata;
2576
2577   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor);
2578   GST_VALIDATE_MONITOR_LOCK (monitor);
2579
2580   if (!pull_mode)
2581     gst_validate_pad_monitor_check_discont (monitor, buffer);
2582   gst_validate_pad_monitor_check_first_buffer (monitor, buffer);
2583   gst_validate_pad_monitor_update_buffer_data (monitor, buffer);
2584   gst_validate_pad_monitor_check_eos (monitor, buffer);
2585
2586   if (PAD_PARENT_IS_DECODER (monitor) || PAD_PARENT_IS_ENCODER (monitor)) {
2587     GstClockTime tolerance = 0;
2588
2589     if (monitor->caps_is_audio)
2590       tolerance = AUDIO_TIMESTAMP_TOLERANCE;
2591
2592     gst_validate_pad_monitor_check_buffer_timestamp_in_received_range (monitor,
2593         buffer, tolerance);
2594   }
2595
2596   gst_validate_pad_monitor_check_late_serialized_events (monitor,
2597       GST_BUFFER_TIMESTAMP (buffer));
2598
2599   /* a GstValidatePadMonitor parent must be a GstValidateElementMonitor */
2600   if (PAD_PARENT_IS_DECODER (monitor)) {
2601
2602     /* should not push out of segment data */
2603     if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer)) &&
2604         GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer)) &&
2605         ((!gst_segment_clip (&monitor->segment, monitor->segment.format,
2606                     GST_BUFFER_TIMESTAMP (buffer),
2607                     GST_BUFFER_TIMESTAMP (buffer) +
2608                     GST_BUFFER_DURATION (buffer), NULL, NULL)) ||
2609             /* In the case of raw data, buffers should be strictly contained inside the
2610              * segment */
2611             (monitor->caps_is_raw &&
2612                 GST_BUFFER_PTS (buffer) + GST_BUFFER_DURATION (buffer) <
2613                 monitor->segment.start))
2614         ) {
2615       /* TODO is this a timestamp issue? */
2616       GST_VALIDATE_REPORT (monitor, BUFFER_IS_OUT_OF_SEGMENT,
2617           "buffer is out of segment and shouldn't be pushed. Timestamp: %"
2618           GST_TIME_FORMAT " - Duration: %" GST_TIME_FORMAT ". Range: %"
2619           GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2620           GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
2621           GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)),
2622           GST_TIME_ARGS (monitor->segment.start),
2623           GST_TIME_ARGS (monitor->segment.stop));
2624     }
2625   }
2626
2627   gst_validate_pad_monitor_check_buffer_freq (monitor, pad);
2628
2629   GST_VALIDATE_MONITOR_UNLOCK (monitor);
2630   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (monitor);
2631   gst_validate_pad_monitor_buffer_probe_overrides (monitor, buffer);
2632   return TRUE;
2633 }
2634
2635 static void
2636 gst_validate_pad_monitor_event_probe (GstPad * pad, GstEvent * event,
2637     gpointer udata)
2638 {
2639   GstValidatePadMonitor *monitor = GST_VALIDATE_PAD_MONITOR_CAST (udata);
2640
2641   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor);
2642   GST_VALIDATE_MONITOR_LOCK (monitor);
2643
2644   GST_DEBUG_OBJECT (pad, "event %p %s", event, GST_EVENT_TYPE_NAME (event));
2645
2646   if (GST_EVENT_IS_SERIALIZED (event)) {
2647     gint i;
2648
2649     /* Detect if events the element received are being forwarded in the same order
2650      *
2651      * Several scenarios:
2652      * 1) The element pushes the event as-is
2653      * 2) The element consumes the event and does not forward it
2654      * 3) The element consumes the event and creates another one instead
2655      * 4) The element pushes other serialized event before pushing out the
2656      *    one it received
2657      *
2658      * For each pad we have two lists to track serialized events:
2659      *  1) We received on input and expect to see (serialized_events)
2660      *  2) We received on input but don't expect to see (expired_events)
2661      *
2662      * To detect events that are pushed in a different order from the one they were
2663      * received in we check that:
2664      *
2665      * For each event being outputted:
2666      *   If it is in the expired_events list:
2667      *     RAISE WARNING
2668      *   If it is in the serialized_events list:
2669      *     If there are other events that were received before:
2670      *        Put those events on the expired_events list
2671      *     Remove that event and any previous ones from the serialized_events list
2672      *
2673      * Clear expired events list when flushing or on pad deactivation
2674      *
2675      */
2676
2677     if (g_list_find (monitor->expired_events, event)) {
2678       gchar *event_str = _get_event_string (event);
2679       /* If it's the expired events, we've failed */
2680       GST_WARNING_OBJECT (pad, "Did not expect event %p %s", event,
2681           GST_EVENT_TYPE_NAME (event));
2682       GST_VALIDATE_REPORT (monitor, EVENT_SERIALIZED_OUT_OF_ORDER,
2683           "Serialized event was pushed out of order: %s", event_str);
2684
2685       g_free (event_str);
2686       monitor->expired_events = g_list_remove (monitor->expired_events, event);
2687       gst_event_unref (event);  /* remove the ref that was on the list */
2688     } else if (monitor->serialized_events->len) {
2689       for (i = 0; i < monitor->serialized_events->len; i++) {
2690         SerializedEventData *next_event =
2691             g_ptr_array_index (monitor->serialized_events, i);
2692         GST_DEBUG_OBJECT (pad, "Checking against stored event #%d: %p %s", i,
2693             next_event->event, GST_EVENT_TYPE_NAME (next_event->event));
2694
2695         if (event == next_event->event
2696             || GST_EVENT_TYPE (event) == GST_EVENT_TYPE (next_event->event)) {
2697           /* We have found our event */
2698           GST_DEBUG_OBJECT (pad, "Found matching event");
2699
2700           while (monitor->serialized_events->len > i
2701               && GST_EVENT_TYPE (event) == GST_EVENT_TYPE (next_event->event)) {
2702             /* Swallow all expected events of the same type */
2703             g_ptr_array_remove_index (monitor->serialized_events, i);
2704             next_event = g_ptr_array_index (monitor->serialized_events, i);
2705           }
2706
2707           /* Move all previous events to expired events */
2708           if (G_UNLIKELY (i > 0)) {
2709             GST_DEBUG_OBJECT (pad,
2710                 "Moving previous expected events to expired list");
2711             while (i--) {
2712               next_event = g_ptr_array_index (monitor->serialized_events, 0);
2713               monitor->expired_events =
2714                   g_list_append (monitor->expired_events,
2715                   gst_event_ref (next_event->event));
2716               g_ptr_array_remove_index (monitor->serialized_events, 0);
2717             }
2718           }
2719           debug_pending_event (pad, monitor->serialized_events);
2720           break;
2721         }
2722       }
2723     }
2724   }
2725
2726   /* This so far is just like an event that is flowing downstream,
2727    * so we do the same checks as a sinkpad event handler */
2728   gst_validate_pad_monitor_downstream_event_check (monitor, NULL, event, NULL);
2729   GST_VALIDATE_MONITOR_UNLOCK (monitor);
2730   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (monitor);
2731 }
2732
2733 static GstPadProbeReturn
2734 gst_validate_pad_monitor_pad_probe (GstPad * pad, GstPadProbeInfo * info,
2735     gpointer udata)
2736 {
2737   if (info->type & GST_PAD_PROBE_TYPE_BUFFER)
2738     gst_validate_pad_monitor_buffer_probe (pad, info->data, udata,
2739         GST_PAD_PROBE_INFO_TYPE (info) & GST_PAD_PROBE_TYPE_PULL);
2740   else if (info->type & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM)
2741     gst_validate_pad_monitor_event_probe (pad, info->data, udata);
2742
2743   return GST_PAD_PROBE_OK;
2744 }
2745
2746 static void
2747 gst_validate_pad_monitor_update_caps_info (GstValidatePadMonitor * pad_monitor,
2748     GstCaps * caps)
2749 {
2750   GstStructure *structure;
2751
2752   g_return_if_fail (gst_caps_is_fixed (caps));
2753
2754   pad_monitor->caps_is_audio = FALSE;
2755   pad_monitor->caps_is_video = FALSE;
2756
2757   structure = gst_caps_get_structure (caps, 0);
2758   if (g_str_has_prefix (gst_structure_get_name (structure), "audio/")) {
2759     pad_monitor->caps_is_audio = TRUE;
2760   } else if (g_str_has_prefix (gst_structure_get_name (structure), "video/")) {
2761     pad_monitor->caps_is_video = TRUE;
2762   }
2763
2764   if (g_str_has_prefix (gst_structure_get_name (structure), "audio/x-raw") ||
2765       g_str_has_prefix (gst_structure_get_name (structure), "video/x-raw")) {
2766     pad_monitor->caps_is_raw = TRUE;
2767   } else {
2768     pad_monitor->caps_is_raw = FALSE;
2769   }
2770 }
2771
2772 static void
2773 gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor,
2774     GstCaps * caps)
2775 {
2776   GstStructure *structure;
2777   GstPad *pad =
2778       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
2779           (pad_monitor)));
2780
2781   /* Check if caps are identical to last caps and complain if so
2782    * Only checked for sink pads as src pads might push the same caps
2783    * multiple times during unlinked/autoplugging scenarios */
2784   if (GST_PAD_IS_SINK (pad) && pad_monitor->last_caps
2785       && gst_caps_is_equal (caps, pad_monitor->last_caps)) {
2786     gchar *caps_str = gst_caps_to_string (caps);
2787
2788     GST_VALIDATE_REPORT (pad_monitor, EVENT_CAPS_DUPLICATE, "%s", caps_str);
2789     g_free (caps_str);
2790
2791   }
2792
2793   gst_validate_pad_monitor_check_caps_complete (pad_monitor, caps);
2794
2795   if (caps) {
2796     structure = gst_caps_get_structure (caps, 0);
2797     if (gst_structure_n_fields (pad_monitor->pending_setcaps_fields)) {
2798       gint i;
2799       for (i = 0;
2800           i < gst_structure_n_fields (pad_monitor->pending_setcaps_fields);
2801           i++) {
2802         const gchar *name =
2803             gst_structure_nth_field_name (pad_monitor->pending_setcaps_fields,
2804             i);
2805         const GValue *v = gst_structure_get_value (structure, name);
2806         const GValue *otherv =
2807             gst_structure_get_value (pad_monitor->pending_setcaps_fields, name);
2808
2809         if (v == NULL) {
2810           gchar *caps_str = gst_caps_to_string (caps);
2811
2812           GST_VALIDATE_REPORT (pad_monitor, CAPS_EXPECTED_FIELD_NOT_FOUND,
2813               "Field %s is missing from setcaps caps '%s'", name, caps_str);
2814           g_free (caps_str);
2815         } else if (gst_value_compare (v, otherv) != GST_VALUE_EQUAL) {
2816           gchar *caps_str = gst_caps_to_string (caps),
2817               *pending_setcaps_fields_str =
2818               gst_structure_to_string (pad_monitor->pending_setcaps_fields);
2819
2820
2821           GST_VALIDATE_REPORT (pad_monitor, CAPS_FIELD_UNEXPECTED_VALUE,
2822               "Field %s from setcaps caps '%s' is different "
2823               "from expected value in caps '%s'", name, caps_str,
2824               pending_setcaps_fields_str);
2825
2826           g_free (pending_setcaps_fields_str);
2827           g_free (caps_str);
2828         }
2829       }
2830     }
2831
2832     if (GST_PAD_IS_SINK (pad) &&
2833         gst_validate_pad_monitor_pad_should_proxy_othercaps (pad_monitor)) {
2834       if (_structure_is_video (structure)) {
2835         GST_DEBUG_OBJECT (pad,
2836             "Adding video common pending fields to other pad: %" GST_PTR_FORMAT,
2837             structure);
2838         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2839             structure, "width");
2840         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2841             structure, "height");
2842         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2843             structure, "framerate");
2844         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2845             structure, "pixel-aspect-ratio");
2846       } else if (_structure_is_audio (structure)) {
2847         GST_DEBUG_OBJECT (pad,
2848             "Adding audio common pending fields to other pad: %" GST_PTR_FORMAT,
2849             structure);
2850         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2851             structure, "rate");
2852         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2853             structure, "channels");
2854       }
2855     }
2856   }
2857
2858   gst_structure_free (pad_monitor->pending_setcaps_fields);
2859   pad_monitor->pending_setcaps_fields =
2860       gst_structure_new_empty (PENDING_FIELDS);
2861   gst_object_unref (pad);
2862
2863   gst_validate_pad_monitor_setcaps_overrides (pad_monitor, caps);
2864 }
2865
2866 static void
2867 gst_validate_pad_monitor_setcaps_post (GstValidatePadMonitor * pad_monitor,
2868     GstCaps * caps, gboolean ret)
2869 {
2870   if (!ret)
2871     gst_validate_pad_monitor_otherpad_clear_pending_fields (pad_monitor);
2872   else {
2873     if (pad_monitor->last_caps) {
2874       gst_caps_unref (pad_monitor->last_caps);
2875     }
2876     pad_monitor->last_caps = gst_caps_ref (caps);
2877     gst_validate_pad_monitor_update_caps_info (pad_monitor, caps);
2878   }
2879 }
2880
2881 static void
2882 gst_validate_pad_monitor_get_min_buffer_frequency (GstValidatePadMonitor *
2883     monitor, GstPad * pad)
2884 {
2885   GList *config, *l;
2886
2887   if (!GST_PAD_IS_SRC (pad))
2888     return;
2889
2890   config = gst_validate_plugin_get_config (NULL);
2891   for (l = config; l != NULL; l = g_list_next (l)) {
2892     GstStructure *s = l->data;
2893     gdouble min_buf_freq;
2894     const gchar *pad_name;
2895     GstElement *element = NULL;
2896
2897     if (!gst_structure_get_double (s, "min-buffer-frequency", &min_buf_freq)) {
2898       gint max_int;
2899
2900       if (!gst_structure_get_int (s, "min-buffer-frequency", &max_int))
2901         goto next;
2902
2903       min_buf_freq = max_int;
2904     }
2905
2906     pad_name = gst_structure_get_string (s, "name");
2907     if (!pad_name)
2908       pad_name = "src";
2909
2910     if (g_strcmp0 (GST_PAD_NAME (pad), pad_name))
2911       goto next;
2912
2913     element = gst_pad_get_parent_element (pad);
2914
2915     if (!gst_validate_element_matches_target (element, s))
2916       goto next;
2917
2918     monitor->min_buf_freq = min_buf_freq;
2919
2920     gst_validate_utils_get_clocktime (s, "buffer-frequency-start",
2921         &monitor->min_buf_freq_start);
2922
2923     GST_DEBUG_OBJECT (pad, "pad has a minimum buffer frequency of %f",
2924         min_buf_freq);
2925   next:
2926     g_clear_object (&element);
2927   }
2928 }
2929
2930 static gboolean
2931 gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor)
2932 {
2933   GstValidatePadMonitor *pad_monitor = GST_VALIDATE_PAD_MONITOR_CAST (monitor);
2934   GstPad *pad = (gpointer) gst_validate_monitor_get_target (monitor);
2935
2936   if (!GST_IS_PAD (pad)) {
2937     GST_WARNING_OBJECT (monitor, "Trying to create pad monitor with other "
2938         "type of object");
2939     gst_object_unref (pad);
2940     return FALSE;
2941   }
2942
2943   if (_GET_PAD_MONITOR (pad)) {
2944     GST_WARNING_OBJECT (pad_monitor,
2945         "Pad already has a validate-monitor associated");
2946     gst_object_unref (pad);
2947     return FALSE;
2948   }
2949
2950   _SET_PAD_MONITOR (pad, pad_monitor);
2951
2952   pad_monitor->event_func = GST_PAD_EVENTFUNC (pad);
2953   pad_monitor->event_full_func = GST_PAD_EVENTFULLFUNC (pad);
2954   pad_monitor->query_func = GST_PAD_QUERYFUNC (pad);
2955   pad_monitor->activatemode_func = GST_PAD_ACTIVATEMODEFUNC (pad);
2956   pad_monitor->get_range_func = GST_PAD_GETRANGEFUNC (pad);
2957   if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
2958
2959     pad_monitor->chain_func = GST_PAD_CHAINFUNC (pad);
2960     if (pad_monitor->chain_func)
2961       gst_pad_set_chain_function (pad, gst_validate_pad_monitor_chain_func);
2962
2963     if (pad_monitor->event_full_func)
2964       gst_pad_set_event_full_function (pad,
2965           gst_validate_pad_monitor_sink_event_full_func);
2966     else
2967       gst_pad_set_event_function (pad,
2968           gst_validate_pad_monitor_sink_event_func);
2969   } else {
2970     gst_pad_set_event_function (pad, gst_validate_pad_monitor_src_event_func);
2971
2972     /* add buffer/event probes */
2973     pad_monitor->pad_probe_id =
2974         gst_pad_add_probe (pad,
2975         GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM |
2976         GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2977         (GstPadProbeCallback) gst_validate_pad_monitor_pad_probe, pad_monitor,
2978         NULL);
2979   }
2980   gst_pad_set_query_function (pad, gst_validate_pad_monitor_query_func);
2981   gst_pad_set_activatemode_function (pad,
2982       gst_validate_pad_monitor_activatemode_func);
2983
2984   if (GST_PAD_IS_SRC (pad)) {
2985     gst_pad_set_getrange_function (pad,
2986         gst_validate_pad_monitor_get_range_func);
2987   }
2988
2989   gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (monitor),
2990       g_strdup_printf ("%s:%s", GST_DEBUG_PAD_NAME (pad)));
2991
2992   if (G_UNLIKELY (GST_PAD_PARENT (pad) == NULL))
2993     GST_FIXME ("Saw a pad not belonging to any object");
2994
2995   gst_validate_pad_monitor_get_min_buffer_frequency (pad_monitor, pad);
2996
2997   gst_object_unref (pad);
2998   return TRUE;
2999 }