pad-monitor: do not enforce caps querying rules for converters
[platform/upstream/gstreamer.git] / validate / gst / validate / gst-validate-pad-monitor.c
1 /* GStreamer
2  *
3  * Copyright (C) 2013 Collabora Ltd.
4  *  Author: Thiago Sousa Santos <thiago.sousa.santos@collabora.com>
5  *
6  * gst-validate-pad-monitor.c - Validate PadMonitor class
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27
28 #include "gst-validate-internal.h"
29 #include "gst-validate-pad-monitor.h"
30 #include "gst-validate-element-monitor.h"
31 #include "gst-validate-reporter.h"
32 #include <string.h>
33 #include <stdarg.h>
34
35 /**
36  * SECTION:gst-validate-pad-monitor
37  * @short_description: Class that wraps a #GstPad for Validate checks
38  *
39  * TODO
40  */
41
42 static GstValidateInterceptionReturn
43 gst_validate_pad_monitor_intercept_report (GstValidateReporter * reporter,
44     GstValidateReport * report);
45
46 #define _do_init \
47   G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, _reporter_iface_init)
48
49 static void
50 _reporter_iface_init (GstValidateReporterInterface * iface)
51 {
52   iface->intercept_report = gst_validate_pad_monitor_intercept_report;
53 }
54
55 #define gst_validate_pad_monitor_parent_class parent_class
56 G_DEFINE_TYPE_WITH_CODE (GstValidatePadMonitor, gst_validate_pad_monitor,
57     GST_TYPE_VALIDATE_MONITOR, _do_init);
58
59 #define PENDING_FIELDS "pending-fields"
60 #define AUDIO_TIMESTAMP_TOLERANCE (GST_MSECOND * 100)
61
62 #define PAD_PARENT_IS_DEMUXER(m) \
63     (GST_VALIDATE_MONITOR_GET_PARENT(m) ? \
64         GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DEMUXER ( \
65             GST_VALIDATE_MONITOR_GET_PARENT(m)) : \
66         FALSE)
67
68 #define PAD_PARENT_IS_DECODER(m) \
69     (GST_VALIDATE_MONITOR_GET_PARENT(m) ? \
70         GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DECODER ( \
71             GST_VALIDATE_MONITOR_GET_PARENT(m)) : \
72         FALSE)
73
74 #define PAD_PARENT_IS_ENCODER(m) \
75     (GST_VALIDATE_MONITOR_GET_PARENT(m) ? \
76         GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_ENCODER ( \
77             GST_VALIDATE_MONITOR_GET_PARENT(m)) : \
78         FALSE)
79
80
81 /*
82  * Locking the parent should always be done before locking the
83  * pad-monitor to prevent deadlocks in case another monitor from
84  * another pad on the same element starts an operation that also
85  * requires locking itself and some other monitors from internally
86  * linked pads.
87  *
88  * An example:
89  * An element has a sink and a src pad. Some test starts running at sinkpad
90  * and it locks the parent, and then it locks itself. In case it needs to get
91  * some information from the srcpad, it is able to lock the srcpad and get it
92  * because the srcpad should never lock itself before locking the parent (which
93  * it won't be able as sinkpad already locked it).
94  *
95  * As a side one, it is possible that srcpad locks itself without locking the
96  * parent in case it wants to do a check that won't need to use other internally
97  * linked pads (sinkpad). But in this case it might lock and unlock freely without
98  * causing deadlocks.
99  */
100 #define GST_VALIDATE_PAD_MONITOR_PARENT_LOCK(m)                  \
101 G_STMT_START {                                             \
102   if (G_LIKELY (GST_VALIDATE_MONITOR_GET_PARENT (m))) {          \
103     GST_VALIDATE_MONITOR_LOCK (GST_VALIDATE_MONITOR_GET_PARENT (m));   \
104   } else {                                                 \
105     GST_WARNING_OBJECT (m, "No parent found, can't lock"); \
106   }                                                        \
107 } G_STMT_END
108
109 #define GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK(m)                  \
110 G_STMT_START {                                               \
111   if (G_LIKELY (GST_VALIDATE_MONITOR_GET_PARENT (m))) {            \
112     GST_VALIDATE_MONITOR_UNLOCK (GST_VALIDATE_MONITOR_GET_PARENT (m));   \
113   } else {                                                   \
114     GST_WARNING_OBJECT (m, "No parent found, can't unlock"); \
115   }                                                          \
116 } G_STMT_END
117
118 typedef struct
119 {
120   GstClockTime timestamp;
121   GstEvent *event;
122 } SerializedEventData;
123
124 static GstPad *
125 _get_actual_pad (GstPad * pad)
126 {
127   GstPad *tmp_pad;
128
129   gst_object_ref (pad);
130
131   /* We don't monitor ghost pads */
132   while (GST_IS_GHOST_PAD (pad)) {
133     tmp_pad = pad;
134     pad = gst_ghost_pad_get_target ((GstGhostPad *) pad);
135     gst_object_unref (tmp_pad);
136   }
137
138   while (GST_IS_PROXY_PAD (pad)) {
139     tmp_pad = pad;
140     pad = gst_pad_get_peer (pad);
141     gst_object_unref (tmp_pad);
142   }
143
144   return pad;
145 }
146
147 static gboolean
148 _find_master_report_on_pad (GstPad * pad, GstValidateReport * report)
149 {
150   GstValidatePadMonitor *pad_monitor;
151   GstValidateReport *prev_report;
152   gboolean result = FALSE;
153   GstPad *tmppad = pad;
154
155   pad = _get_actual_pad (pad);
156   if (pad == NULL) {
157     GST_ERROR_OBJECT (tmppad, "Does not have a target yet");
158
159     return FALSE;
160   }
161
162   pad_monitor = g_object_get_data ((GObject *) pad, "validate-monitor");
163
164   /* For some reason this pad isn't monitored */
165   if (pad_monitor == NULL)
166     goto done;
167
168   prev_report = gst_validate_reporter_get_report ((GstValidateReporter *)
169       pad_monitor, report->issue->issue_id);
170
171   if (prev_report) {
172     if (prev_report->master_report)
173       result = gst_validate_report_set_master_report (report,
174           prev_report->master_report);
175     else
176       result = gst_validate_report_set_master_report (report, prev_report);
177   }
178
179 done:
180   gst_object_unref (pad);
181
182   return result;
183 }
184
185 static gboolean
186 _find_master_report_for_sink_pad (GstValidatePadMonitor * pad_monitor,
187     GstValidateReport * report)
188 {
189   GstPad *peerpad;
190   gboolean result = FALSE;
191
192   peerpad = gst_pad_get_peer (pad_monitor->pad);
193
194   /* If the peer src pad already has a similar report no need to look
195    * any further */
196   if (peerpad && _find_master_report_on_pad (peerpad, report))
197     result = TRUE;
198
199   if (peerpad)
200     gst_object_unref (peerpad);
201
202   return result;
203 }
204
205 static gboolean
206 _find_master_report_for_src_pad (GstValidatePadMonitor * pad_monitor,
207     GstValidateReport * report)
208 {
209   GstIterator *iter;
210   gboolean done;
211   GstPad *pad;
212   gboolean result = FALSE;
213
214   iter =
215       gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
216       (pad_monitor));
217   done = FALSE;
218   while (!done) {
219     GValue value = { 0, };
220     switch (gst_iterator_next (iter, &value)) {
221       case GST_ITERATOR_OK:
222         pad = g_value_get_object (&value);
223
224         if (_find_master_report_on_pad (pad, report)) {
225           result = TRUE;
226           done = TRUE;
227         }
228
229         g_value_reset (&value);
230         break;
231       case GST_ITERATOR_RESYNC:
232         gst_iterator_resync (iter);
233         break;
234       case GST_ITERATOR_ERROR:
235         GST_WARNING_OBJECT (pad_monitor->pad,
236             "Internal links pad iteration error");
237         done = TRUE;
238         break;
239       case GST_ITERATOR_DONE:
240         done = TRUE;
241         break;
242     }
243   }
244   gst_iterator_free (iter);
245
246   return result;
247 }
248
249 static GstValidateInterceptionReturn
250 _concatenate_issues (GstValidatePadMonitor * pad_monitor,
251     GstValidateReport * report)
252 {
253   if (GST_PAD_IS_SINK (pad_monitor->pad)
254       && _find_master_report_for_sink_pad (pad_monitor, report))
255     return GST_VALIDATE_REPORTER_KEEP;
256   else if (GST_PAD_IS_SRC (pad_monitor->pad)
257       && _find_master_report_for_src_pad (pad_monitor, report))
258     return GST_VALIDATE_REPORTER_KEEP;
259
260   return GST_VALIDATE_REPORTER_REPORT;
261 }
262
263 static GstValidateInterceptionReturn
264 gst_validate_pad_monitor_intercept_report (GstValidateReporter *
265     reporter, GstValidateReport * report)
266 {
267   GstValidateReporterInterface *iface_class, *old_iface_class;
268   GstValidatePadMonitor *pad_monitor = GST_VALIDATE_PAD_MONITOR (reporter);
269   GstValidateReportingDetails monitor_reporting_level;
270   GstValidateInterceptionReturn ret;
271
272   monitor_reporting_level =
273       gst_validate_reporter_get_reporting_level (reporter);
274
275   iface_class =
276       G_TYPE_INSTANCE_GET_INTERFACE (reporter, GST_TYPE_VALIDATE_REPORTER,
277       GstValidateReporterInterface);
278   old_iface_class = g_type_interface_peek_parent (iface_class);
279
280   old_iface_class->intercept_report (reporter, report);
281
282   switch (monitor_reporting_level) {
283     case GST_VALIDATE_SHOW_NONE:
284       ret = GST_VALIDATE_REPORTER_DROP;
285       break;
286     case GST_VALIDATE_SHOW_UNKNOWN:
287       ret = _concatenate_issues (pad_monitor, report);
288       break;
289     default:
290       ret = GST_VALIDATE_REPORTER_REPORT;
291       break;
292   }
293
294   gst_validate_report_set_reporting_level (report, monitor_reporting_level);
295   return ret;
296 }
297
298 static void
299 debug_pending_event (GstPad * pad, GPtrArray * array)
300 {
301   guint i, len;
302
303   len = array->len;
304   for (i = 0; i < len; i++) {
305     SerializedEventData *data = g_ptr_array_index (array, i);
306     GST_DEBUG_OBJECT (pad, "event #%d %" GST_TIME_FORMAT " %s %p",
307         i, GST_TIME_ARGS (data->timestamp),
308         GST_EVENT_TYPE_NAME (data->event), data->event);
309   }
310 }
311
312 static void
313 _serialized_event_data_free (SerializedEventData * serialized_event)
314 {
315   gst_event_unref (serialized_event->event);
316   g_slice_free (SerializedEventData, serialized_event);
317 }
318
319 static gboolean gst_validate_pad_monitor_do_setup (GstValidateMonitor *
320     monitor);
321 static GstElement *gst_validate_pad_monitor_get_element (GstValidateMonitor *
322     monitor);
323 static void
324 gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor,
325     GstCaps * caps);
326 static void gst_validate_pad_monitor_setcaps_post (GstValidatePadMonitor *
327     pad_monitor, GstCaps * caps, gboolean ret);
328
329 #define PAD_IS_IN_PUSH_MODE(p) ((p)->mode == GST_PAD_MODE_PUSH)
330
331 static gboolean
332 _structure_is_raw_video (GstStructure * structure)
333 {
334   return gst_structure_has_name (structure, "video/x-raw");
335 }
336
337 static gboolean
338 _structure_is_raw_audio (GstStructure * structure)
339 {
340   return gst_structure_has_name (structure, "audio/x-raw");
341 }
342
343 static gchar *
344 _get_event_string (GstEvent * event)
345 {
346   const GstStructure *st;
347
348   if ((st = gst_event_get_structure (event)))
349     return gst_structure_to_string (st);
350   else
351     return g_strdup_printf ("%s", GST_EVENT_TYPE_NAME (event));
352 }
353
354 static void
355 _check_field_type (GstValidatePadMonitor * monitor,
356     GstStructure * structure, gboolean mandatory, const gchar * field, ...)
357 {
358   va_list var_args;
359   GType type;
360   gchar *joined_types = NULL;
361   const gchar *rejected_types[5];
362   gint rejected_types_index = 0;
363   gchar *struct_str;
364
365   if (!gst_structure_has_field (structure, field)) {
366     if (mandatory) {
367       gchar *str = gst_structure_to_string (structure);
368
369       GST_VALIDATE_REPORT (monitor, CAPS_IS_MISSING_FIELD,
370           "Field '%s' is missing from structure: %s", field, str);
371       g_free (str);
372     } else {
373       GST_DEBUG_OBJECT (monitor, "Field %s is missing but is not mandatory",
374           field);
375     }
376     return;
377   }
378
379   memset (rejected_types, 0, sizeof (rejected_types));
380   va_start (var_args, field);
381   while ((type = va_arg (var_args, GType)) != 0) {
382     if (gst_structure_has_field_typed (structure, field, type)) {
383       va_end (var_args);
384       return;
385     }
386     rejected_types[rejected_types_index++] = g_type_name (type);
387   }
388   va_end (var_args);
389
390   joined_types = g_strjoinv (" / ", (gchar **) rejected_types);
391   struct_str = gst_structure_to_string (structure);
392   GST_VALIDATE_REPORT (monitor, CAPS_FIELD_HAS_BAD_TYPE,
393       "Field '%s' has wrong type %s in structure '%s'. Expected: %s", field,
394       g_type_name (gst_structure_get_field_type (structure, field)), struct_str,
395       joined_types);
396   g_free (joined_types);
397   g_free (struct_str);
398 }
399
400 static void
401 gst_validate_pad_monitor_check_raw_video_caps_complete (GstValidatePadMonitor *
402     monitor, GstStructure * structure)
403 {
404   _check_field_type (monitor, structure, TRUE, "width", G_TYPE_INT,
405       GST_TYPE_INT_RANGE, 0);
406   _check_field_type (monitor, structure, TRUE, "height", G_TYPE_INT,
407       GST_TYPE_INT_RANGE, 0);
408   _check_field_type (monitor, structure, TRUE, "framerate", GST_TYPE_FRACTION,
409       GST_TYPE_FRACTION_RANGE, 0);
410   _check_field_type (monitor, structure, FALSE, "pixel-aspect-ratio",
411       GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE, 0);
412   _check_field_type (monitor, structure, TRUE, "format", G_TYPE_STRING,
413       GST_TYPE_LIST);
414 }
415
416 static void
417 gst_validate_pad_monitor_check_raw_audio_caps_complete (GstValidatePadMonitor *
418     monitor, GstStructure * structure)
419 {
420   gint channels;
421   _check_field_type (monitor, structure, TRUE, "format", G_TYPE_STRING,
422       GST_TYPE_LIST, 0);
423   _check_field_type (monitor, structure, TRUE, "layout", G_TYPE_STRING,
424       GST_TYPE_LIST, 0);
425   _check_field_type (monitor, structure, TRUE, "rate", G_TYPE_INT,
426       GST_TYPE_LIST, GST_TYPE_INT_RANGE, 0);
427   _check_field_type (monitor, structure, TRUE, "channels", G_TYPE_INT,
428       GST_TYPE_LIST, GST_TYPE_INT_RANGE, 0);
429   if (gst_structure_get_int (structure, "channels", &channels)) {
430     if (channels > 2)
431       _check_field_type (monitor, structure, TRUE, "channel-mask",
432           GST_TYPE_BITMASK, GST_TYPE_LIST, 0);
433   }
434 }
435
436 static void
437 gst_validate_pad_monitor_check_caps_complete (GstValidatePadMonitor * monitor,
438     GstCaps * caps)
439 {
440   GstStructure *structure;
441   gint i;
442
443   GST_DEBUG_OBJECT (monitor->pad, "Checking caps %" GST_PTR_FORMAT, caps);
444
445   for (i = 0; i < gst_caps_get_size (caps); i++) {
446     structure = gst_caps_get_structure (caps, i);
447
448     if (_structure_is_raw_video (structure)) {
449       gst_validate_pad_monitor_check_raw_video_caps_complete (monitor,
450           structure);
451
452     } else if (_structure_is_raw_audio (structure)) {
453       gst_validate_pad_monitor_check_raw_audio_caps_complete (monitor,
454           structure);
455     }
456   }
457 }
458
459 static GstCaps *
460 gst_validate_pad_monitor_get_othercaps (GstValidatePadMonitor * monitor)
461 {
462   GstCaps *caps = gst_caps_new_empty ();
463   GstIterator *iter;
464   gboolean done;
465   GstPad *otherpad;
466   GstCaps *peercaps;
467
468   iter =
469       gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
470       (monitor));
471   done = FALSE;
472   while (!done) {
473     GValue value = { 0, };
474     switch (gst_iterator_next (iter, &value)) {
475       case GST_ITERATOR_OK:
476         otherpad = g_value_get_object (&value);
477
478         /* TODO What would be the correct caps operation to merge the caps in
479          * case one sink is internally linked to multiple srcs? */
480         peercaps = gst_pad_get_current_caps (otherpad);
481         if (peercaps)
482           caps = gst_caps_merge (caps, peercaps);
483
484         g_value_reset (&value);
485         break;
486       case GST_ITERATOR_RESYNC:
487         gst_iterator_resync (iter);
488         gst_caps_replace (&caps, gst_caps_new_empty ());
489         break;
490       case GST_ITERATOR_ERROR:
491         GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error");
492         done = TRUE;
493         break;
494       case GST_ITERATOR_DONE:
495         done = TRUE;
496         break;
497     }
498   }
499   gst_iterator_free (iter);
500
501   GST_DEBUG_OBJECT (monitor->pad, "Otherpad caps: %" GST_PTR_FORMAT, caps);
502
503   return caps;
504 }
505
506 static gboolean
507 _structure_is_video (GstStructure * structure)
508 {
509   const gchar *name = gst_structure_get_name (structure);
510
511   return g_strstr_len (name, 6, "video/")
512       && strcmp (name, "video/quicktime") != 0;
513 }
514
515 static gboolean
516 _structure_is_audio (GstStructure * structure)
517 {
518   const gchar *name = gst_structure_get_name (structure);
519
520   return g_strstr_len (name, 6, "audio/") != NULL;
521 }
522
523 static gboolean
524 gst_validate_pad_monitor_pad_should_proxy_othercaps (GstValidatePadMonitor *
525     monitor)
526 {
527   GstValidateMonitor *parent = GST_VALIDATE_MONITOR_GET_PARENT (monitor);
528
529   if (!parent)
530     return FALSE;
531
532   /* We only know how to handle othercaps checks for codecs so far */
533   return (GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DECODER (parent) ||
534       GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_ENCODER (parent)) &&
535       !GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_CONVERTER (parent);
536 }
537
538
539 /* Check if the field @f from @s2 (if present) is represented in @s1
540  * Represented here means either equal or @s1's value is in a list/range
541  * from @s2
542  */
543 static gboolean
544 _structures_field_is_contained (GstStructure * s1, GstStructure * s2,
545     gboolean mandatory, const gchar * f)
546 {
547   const GValue *v1;
548   const GValue *v2;
549
550   v2 = gst_structure_get_value (s2, f);
551   if (!v2)
552     return TRUE;                /* nothing to compare to */
553
554   v1 = gst_structure_get_value (s1, f);
555   if (!v1)
556     return !mandatory;
557
558   if (!gst_value_is_fixed (v1))
559     return TRUE;
560
561   if (gst_value_compare (v1, v2) == GST_VALUE_EQUAL)
562     return TRUE;
563
564   if (GST_VALUE_HOLDS_LIST (v2)) {
565     gint i;
566     for (i = 0; i < gst_value_list_get_size (v2); i++) {
567       const GValue *v2_subvalue = gst_value_list_get_value (v2, i);
568       if (gst_value_compare (v1, v2_subvalue) == GST_VALUE_EQUAL)
569         return TRUE;
570     }
571   }
572
573   if (GST_VALUE_HOLDS_ARRAY (v2)) {
574     gint i;
575     for (i = 0; i < gst_value_array_get_size (v2); i++) {
576       const GValue *v2_subvalue = gst_value_array_get_value (v2, i);
577       if (gst_value_compare (v1, v2_subvalue) == GST_VALUE_EQUAL)
578         return TRUE;
579     }
580   }
581
582   if (GST_VALUE_HOLDS_INT_RANGE (v2)) {
583     gint min, max;
584
585     min = gst_value_get_int_range_min (v2);
586     max = gst_value_get_int_range_max (v2);
587
588     if (G_VALUE_HOLDS_INT (v1)) {
589       gint v = g_value_get_int (v1);
590
591       return v >= min && v <= max;
592     } else {
593       /* TODO compare int ranges with int ranges
594        * or with lists if useful */
595     }
596   }
597
598   if (GST_VALUE_HOLDS_FRACTION_RANGE (v2)) {
599     const GValue *min, *max;
600
601     min = gst_value_get_fraction_range_min (v2);
602     max = gst_value_get_fraction_range_max (v2);
603
604     if (GST_VALUE_HOLDS_FRACTION (v1)) {
605       gint v_min = gst_value_compare (v1, min);
606       gint v_max = gst_value_compare (v1, max);
607
608       return (v_min == GST_VALUE_EQUAL || v_min == GST_VALUE_GREATER_THAN) &&
609           (v_max == GST_VALUE_EQUAL || v_max == GST_VALUE_LESS_THAN);
610     } else {
611       /* TODO compare fraction ranges with fraction ranges
612        * or with lists if useful */
613     }
614   }
615
616   return FALSE;
617 }
618
619 static void
620 gst_validate_pad_monitor_check_caps_fields_proxied (GstValidatePadMonitor *
621     monitor, GstCaps * caps)
622 {
623   GstStructure *structure;
624   GstStructure *otherstructure;
625   GstCaps *othercaps;
626   gint i, j;
627
628   if (!gst_validate_pad_monitor_pad_should_proxy_othercaps (monitor))
629     return;
630
631   othercaps = gst_validate_pad_monitor_get_othercaps (monitor);
632
633   for (i = 0; i < gst_caps_get_size (othercaps); i++) {
634     gboolean found = FALSE;
635     gboolean type_match = FALSE;
636
637     otherstructure = gst_caps_get_structure (othercaps, i);
638
639     /* look for a proxied version of 'otherstructure' */
640     if (_structure_is_video (otherstructure)) {
641       for (j = 0; j < gst_caps_get_size (caps); j++) {
642         structure = gst_caps_get_structure (caps, j);
643         if (_structure_is_video (structure)) {
644           type_match = TRUE;
645           if (_structures_field_is_contained (structure, otherstructure, TRUE,
646                   "width")
647               && _structures_field_is_contained (structure, otherstructure,
648                   TRUE, "height")
649               && _structures_field_is_contained (structure, otherstructure,
650                   TRUE, "framerate")
651               && _structures_field_is_contained (structure, otherstructure,
652                   FALSE, "pixel-aspect-ratio")) {
653             found = TRUE;
654             break;
655           }
656         }
657       }
658     } else if (_structure_is_audio (otherstructure)) {
659       for (j = 0; j < gst_caps_get_size (caps); j++) {
660         structure = gst_caps_get_structure (caps, j);
661         if (_structure_is_audio (structure)) {
662           type_match = TRUE;
663           if (_structures_field_is_contained (structure, otherstructure, TRUE,
664                   "rate")
665               && _structures_field_is_contained (structure, otherstructure,
666                   TRUE, "channels")) {
667             found = TRUE;
668             break;
669           }
670         }
671       }
672     }
673
674     if (type_match && !found) {
675       gchar *otherstruct_str = gst_structure_to_string (otherstructure),
676           *caps_str = gst_caps_to_string (caps);
677
678       GST_VALIDATE_REPORT (monitor, GET_CAPS_NOT_PROXYING_FIELDS,
679           "Peer pad structure '%s' has no similar version "
680           "on pad's caps '%s'", otherstruct_str, caps_str);
681
682       g_free (otherstruct_str);
683       g_free (caps_str);
684     }
685   }
686 }
687
688 static void
689 gst_validate_pad_monitor_check_late_serialized_events (GstValidatePadMonitor *
690     monitor, GstClockTime ts)
691 {
692   gint i;
693
694   if (!GST_CLOCK_TIME_IS_VALID (ts))
695     return;
696
697   GST_DEBUG_OBJECT (monitor->pad, "Timestamp to check %" GST_TIME_FORMAT,
698       GST_TIME_ARGS (ts));
699
700   for (i = 0; i < monitor->serialized_events->len; i++) {
701     SerializedEventData *data =
702         g_ptr_array_index (monitor->serialized_events, i);
703
704     GST_DEBUG_OBJECT (monitor->pad, "Event #%d (%s) ts: %" GST_TIME_FORMAT,
705         i, GST_EVENT_TYPE_NAME (data->event), GST_TIME_ARGS (data->timestamp));
706
707     if (GST_CLOCK_TIME_IS_VALID (data->timestamp) && data->timestamp < ts) {
708       gchar *event_str = _get_event_string (data->event);
709
710       GST_VALIDATE_REPORT (monitor, SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME,
711           "Serialized event %s wasn't pushed before expected " "timestamp %"
712           GST_TIME_FORMAT " on pad %s:%s", event_str,
713           GST_TIME_ARGS (data->timestamp),
714           GST_DEBUG_PAD_NAME (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor)));
715
716       g_free (event_str);
717     } else {
718       /* events should be ordered by ts */
719       break;
720     }
721   }
722
723   if (i) {
724     debug_pending_event (monitor->pad, monitor->serialized_events);
725     g_ptr_array_remove_range (monitor->serialized_events, 0, i);
726   }
727 }
728
729 static void
730 gst_validate_pad_monitor_dispose (GObject * object)
731 {
732   GstValidatePadMonitor *monitor = GST_VALIDATE_PAD_MONITOR_CAST (object);
733   GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor);
734
735   if (pad) {
736     if (monitor->pad_probe_id)
737       gst_pad_remove_probe (pad, monitor->pad_probe_id);
738   }
739
740   if (monitor->expected_segment)
741     gst_event_unref (monitor->expected_segment);
742
743   gst_structure_free (monitor->pending_setcaps_fields);
744   g_ptr_array_unref (monitor->serialized_events);
745   g_list_free_full (monitor->expired_events, (GDestroyNotify) gst_event_unref);
746
747   G_OBJECT_CLASS (parent_class)->dispose (object);
748 }
749
750 static void
751 gst_validate_pad_monitor_class_init (GstValidatePadMonitorClass * klass)
752 {
753   GObjectClass *gobject_class;
754   GstValidateMonitorClass *monitor_klass;
755
756   gobject_class = G_OBJECT_CLASS (klass);
757   monitor_klass = GST_VALIDATE_MONITOR_CLASS (klass);
758
759   gobject_class->dispose = gst_validate_pad_monitor_dispose;
760
761   monitor_klass->setup = gst_validate_pad_monitor_do_setup;
762   monitor_klass->get_element = gst_validate_pad_monitor_get_element;
763 }
764
765 static void
766 gst_validate_pad_monitor_init (GstValidatePadMonitor * pad_monitor)
767 {
768   pad_monitor->pending_setcaps_fields =
769       gst_structure_new_empty (PENDING_FIELDS);
770   pad_monitor->serialized_events =
771       g_ptr_array_new_with_free_func ((GDestroyNotify)
772       _serialized_event_data_free);
773   pad_monitor->expired_events = NULL;
774   gst_segment_init (&pad_monitor->segment, GST_FORMAT_BYTES);
775   pad_monitor->first_buffer = TRUE;
776
777   pad_monitor->timestamp_range_start = GST_CLOCK_TIME_NONE;
778   pad_monitor->timestamp_range_end = GST_CLOCK_TIME_NONE;
779 }
780
781 /**
782  * gst_validate_pad_monitor_new:
783  * @pad: (transfer-none): a #GstPad to run Validate on
784  */
785 GstValidatePadMonitor *
786 gst_validate_pad_monitor_new (GstPad * pad, GstValidateRunner * runner,
787     GstValidateElementMonitor * parent)
788 {
789   GstValidatePadMonitor *monitor = g_object_new (GST_TYPE_VALIDATE_PAD_MONITOR,
790       "object", pad, "validate-runner", runner, "validate-parent",
791       parent, NULL);
792
793   if (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor) == NULL) {
794     g_object_unref (monitor);
795     return NULL;
796   }
797   return monitor;
798 }
799
800 static GstElement *
801 gst_validate_pad_monitor_get_element (GstValidateMonitor * monitor)
802 {
803   GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor);
804
805   return GST_PAD_PARENT (pad);
806 }
807
808 static void
809 gst_validate_pad_monitor_event_overrides (GstValidatePadMonitor * pad_monitor,
810     GstEvent * event)
811 {
812   GList *iter;
813
814   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
815   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
816       iter = g_list_next (iter)) {
817     GstValidateOverride *override = iter->data;
818
819     gst_validate_override_event_handler (override,
820         GST_VALIDATE_MONITOR_CAST (pad_monitor), event);
821   }
822   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
823 }
824
825 static void
826 gst_validate_pad_monitor_buffer_overrides (GstValidatePadMonitor * pad_monitor,
827     GstBuffer * buffer)
828 {
829   GList *iter;
830
831   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
832   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
833       iter = g_list_next (iter)) {
834     GstValidateOverride *override = iter->data;
835
836     gst_validate_override_buffer_handler (override,
837         GST_VALIDATE_MONITOR_CAST (pad_monitor), buffer);
838   }
839   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
840 }
841
842 static void
843 gst_validate_pad_monitor_buffer_probe_overrides (GstValidatePadMonitor *
844     pad_monitor, GstBuffer * buffer)
845 {
846   GList *iter;
847
848   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
849   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
850       iter = g_list_next (iter)) {
851     GstValidateOverride *override = iter->data;
852
853     gst_validate_override_buffer_probe_handler (override,
854         GST_VALIDATE_MONITOR_CAST (pad_monitor), buffer);
855   }
856   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
857 }
858
859 static void
860 gst_validate_pad_monitor_query_overrides (GstValidatePadMonitor * pad_monitor,
861     GstQuery * query)
862 {
863   GList *iter;
864
865   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
866   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
867       iter = g_list_next (iter)) {
868     GstValidateOverride *override = iter->data;
869
870     gst_validate_override_query_handler (override,
871         GST_VALIDATE_MONITOR_CAST (pad_monitor), query);
872   }
873   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
874 }
875
876 static void
877 gst_validate_pad_monitor_setcaps_overrides (GstValidatePadMonitor * pad_monitor,
878     GstCaps * caps)
879 {
880   GList *iter;
881
882   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
883   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
884       iter = g_list_next (iter)) {
885     GstValidateOverride *override = iter->data;
886
887     gst_validate_override_setcaps_handler (override,
888         GST_VALIDATE_MONITOR_CAST (pad_monitor), caps);
889   }
890   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
891 }
892
893 /* FIXME : This is a bit dubious, what's the point of this check ? */
894 static gboolean
895 gst_validate_pad_monitor_timestamp_is_in_received_range (GstValidatePadMonitor *
896     monitor, GstClockTime ts, GstClockTime tolerance)
897 {
898   GST_DEBUG_OBJECT (monitor->pad, "Checking if timestamp %" GST_TIME_FORMAT
899       " is in range: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT " for pad "
900       "%s:%s with tolerance: %" GST_TIME_FORMAT, GST_TIME_ARGS (ts),
901       GST_TIME_ARGS (monitor->timestamp_range_start),
902       GST_TIME_ARGS (monitor->timestamp_range_end),
903       GST_DEBUG_PAD_NAME (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor)),
904       GST_TIME_ARGS (tolerance));
905   return !GST_CLOCK_TIME_IS_VALID (monitor->timestamp_range_start) ||
906       !GST_CLOCK_TIME_IS_VALID (monitor->timestamp_range_end) ||
907       ((monitor->timestamp_range_start >= tolerance ?
908           monitor->timestamp_range_start - tolerance : 0) <= ts
909       && (ts >= tolerance ? ts - tolerance : 0) <=
910       monitor->timestamp_range_end);
911 }
912
913 /* Iterates over internal links (sinkpads) to check that this buffer has
914  * a timestamp that is in the range of the lastly received buffers */
915 static void
916     gst_validate_pad_monitor_check_buffer_timestamp_in_received_range
917     (GstValidatePadMonitor * monitor, GstBuffer * buffer,
918     GstClockTime tolerance)
919 {
920   GstClockTime ts;
921   GstClockTime ts_end;
922   GstIterator *iter;
923   gboolean has_one = FALSE;
924   gboolean found = FALSE;
925   gboolean done;
926   GstPad *otherpad;
927   GstValidatePadMonitor *othermonitor;
928
929   if (!GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))
930       || !GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) {
931     GST_DEBUG_OBJECT (monitor->pad,
932         "Can't check buffer timestamps range as "
933         "buffer has no valid timestamp/duration");
934     return;
935   }
936   ts = GST_BUFFER_TIMESTAMP (buffer);
937   ts_end = ts + GST_BUFFER_DURATION (buffer);
938
939   iter =
940       gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
941       (monitor));
942
943   if (iter == NULL) {
944     GST_WARNING_OBJECT (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor),
945         "No iterator available");
946     return;
947   }
948
949   done = FALSE;
950   while (!done) {
951     GValue value = { 0, };
952     switch (gst_iterator_next (iter, &value)) {
953       case GST_ITERATOR_OK:
954         otherpad = g_value_get_object (&value);
955         GST_DEBUG_OBJECT (monitor->pad, "Checking pad %s:%s input timestamps",
956             GST_DEBUG_PAD_NAME (otherpad));
957         othermonitor =
958             g_object_get_data ((GObject *) otherpad, "validate-monitor");
959         GST_VALIDATE_MONITOR_LOCK (othermonitor);
960         if (gst_validate_pad_monitor_timestamp_is_in_received_range
961             (othermonitor, ts, tolerance)
962             &&
963             gst_validate_pad_monitor_timestamp_is_in_received_range
964             (othermonitor, ts_end, tolerance)) {
965           done = TRUE;
966           found = TRUE;
967         }
968         GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
969         g_value_reset (&value);
970         has_one = TRUE;
971         break;
972       case GST_ITERATOR_RESYNC:
973         gst_iterator_resync (iter);
974         has_one = FALSE;
975         found = FALSE;
976         break;
977       case GST_ITERATOR_ERROR:
978         GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error");
979         done = TRUE;
980         break;
981       case GST_ITERATOR_DONE:
982         done = TRUE;
983         break;
984     }
985   }
986   gst_iterator_free (iter);
987
988   if (!has_one) {
989     GST_DEBUG_OBJECT (monitor->pad, "Skipping timestamp in range check as no "
990         "internal linked pad was found");
991     return;
992   }
993   if (!found) {
994     GST_VALIDATE_REPORT (monitor, BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE,
995         "Timestamp %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT
996         " is out of range of received input", GST_TIME_ARGS (ts),
997         GST_TIME_ARGS (ts_end));
998   }
999 }
1000
1001 static void
1002 gst_validate_pad_monitor_check_first_buffer (GstValidatePadMonitor *
1003     pad_monitor, GstBuffer * buffer)
1004 {
1005   if (G_UNLIKELY (pad_monitor->first_buffer)) {
1006     pad_monitor->first_buffer = FALSE;
1007
1008     if (!pad_monitor->has_segment
1009         && PAD_IS_IN_PUSH_MODE (GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor)))
1010     {
1011       GST_VALIDATE_REPORT (pad_monitor, BUFFER_BEFORE_SEGMENT,
1012           "Received buffer before Segment event");
1013     }
1014
1015     GST_DEBUG_OBJECT (pad_monitor->pad,
1016         "Checking first buffer (pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
1017         ")", GST_TIME_ARGS (GST_BUFFER_PTS (buffer)),
1018         GST_TIME_ARGS (GST_BUFFER_DTS (buffer)));
1019
1020   }
1021 }
1022
1023 static void
1024 gst_validate_pad_monitor_check_eos (GstValidatePadMonitor *
1025     pad_monitor, GstBuffer * buffer)
1026 {
1027   if (G_UNLIKELY (pad_monitor->is_eos)) {
1028     GST_VALIDATE_REPORT (pad_monitor, BUFFER_AFTER_EOS,
1029         "Received buffer %" GST_PTR_FORMAT " after EOS", buffer);
1030   }
1031 }
1032
1033 static void
1034 gst_validate_pad_monitor_update_buffer_data (GstValidatePadMonitor *
1035     pad_monitor, GstBuffer * buffer)
1036 {
1037   pad_monitor->current_timestamp = GST_BUFFER_TIMESTAMP (buffer);
1038   pad_monitor->current_duration = GST_BUFFER_DURATION (buffer);
1039   if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) {
1040     if (GST_CLOCK_TIME_IS_VALID (pad_monitor->timestamp_range_start)) {
1041       pad_monitor->timestamp_range_start =
1042           MIN (pad_monitor->timestamp_range_start,
1043           GST_BUFFER_TIMESTAMP (buffer));
1044     } else {
1045       pad_monitor->timestamp_range_start = GST_BUFFER_TIMESTAMP (buffer);
1046     }
1047
1048     if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) {
1049       GstClockTime endts =
1050           GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer);
1051       if (GST_CLOCK_TIME_IS_VALID (pad_monitor->timestamp_range_end)) {
1052         pad_monitor->timestamp_range_end =
1053             MAX (pad_monitor->timestamp_range_end, endts);
1054       } else {
1055         pad_monitor->timestamp_range_end = endts;
1056       }
1057     }
1058   }
1059   GST_DEBUG_OBJECT (pad_monitor->pad, "Current stored range: %" GST_TIME_FORMAT
1060       " - %" GST_TIME_FORMAT,
1061       GST_TIME_ARGS (pad_monitor->timestamp_range_start),
1062       GST_TIME_ARGS (pad_monitor->timestamp_range_end));
1063 }
1064
1065 static GstFlowReturn
1066 _combine_flows (GstFlowReturn ret1, GstFlowReturn ret2)
1067 {
1068   if (ret1 == ret2)
1069     return ret1;
1070   if (ret1 <= GST_FLOW_NOT_NEGOTIATED)
1071     return ret1;
1072   if (ret2 <= GST_FLOW_NOT_NEGOTIATED)
1073     return ret2;
1074   if (ret1 == GST_FLOW_FLUSHING || ret2 == GST_FLOW_FLUSHING)
1075     return GST_FLOW_FLUSHING;
1076   if (ret1 == GST_FLOW_OK || ret2 == GST_FLOW_OK)
1077     return GST_FLOW_OK;
1078   return ret2;
1079 }
1080
1081 static void
1082 gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor *
1083     monitor, GstFlowReturn ret)
1084 {
1085   GstIterator *iter;
1086   gboolean done;
1087   GstPad *otherpad;
1088   GstPad *peerpad;
1089   GstValidatePadMonitor *othermonitor;
1090   GstFlowReturn aggregated = GST_FLOW_NOT_LINKED;
1091   gboolean found_a_pad = FALSE;
1092   GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor);
1093
1094   iter = gst_pad_iterate_internal_links (pad);
1095   done = FALSE;
1096   while (!done) {
1097     GValue value = { 0, };
1098     switch (gst_iterator_next (iter, &value)) {
1099       case GST_ITERATOR_OK:
1100         otherpad = g_value_get_object (&value);
1101         peerpad = gst_pad_get_peer (otherpad);
1102         if (peerpad) {
1103           othermonitor =
1104               g_object_get_data ((GObject *) peerpad, "validate-monitor");
1105           if (othermonitor) {
1106             found_a_pad = TRUE;
1107             GST_VALIDATE_MONITOR_LOCK (othermonitor);
1108             aggregated =
1109                 _combine_flows (aggregated, othermonitor->last_flow_return);
1110             GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1111           }
1112
1113           gst_object_unref (peerpad);
1114         }
1115         g_value_reset (&value);
1116         break;
1117       case GST_ITERATOR_RESYNC:
1118         gst_iterator_resync (iter);
1119         break;
1120       case GST_ITERATOR_ERROR:
1121         GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error");
1122         done = TRUE;
1123         break;
1124       case GST_ITERATOR_DONE:
1125         done = TRUE;
1126         break;
1127     }
1128   }
1129   gst_iterator_free (iter);
1130   if (!found_a_pad) {
1131     /* no peer pad found, nothing to do */
1132     return;
1133   }
1134   if (aggregated == GST_FLOW_OK || aggregated == GST_FLOW_EOS) {
1135     /* those are acceptable situations */
1136
1137     if (GST_PAD_IS_FLUSHING (pad) && ret == GST_FLOW_FLUSHING) {
1138       /* pad is flushing, always acceptable to return flushing */
1139       return;
1140     }
1141
1142     if (monitor->is_eos && ret == GST_FLOW_EOS) {
1143       /* this element received eos and returned eos */
1144       return;
1145     }
1146
1147     if (PAD_PARENT_IS_DEMUXER (monitor) && ret == GST_FLOW_EOS) {
1148       /* a demuxer can return EOS when the samples end */
1149       return;
1150     }
1151   }
1152
1153   if (aggregated != ret) {
1154     GST_VALIDATE_REPORT (monitor, WRONG_FLOW_RETURN,
1155         "Wrong combined flow return %s(%d). Expected: %s(%d)",
1156         gst_flow_get_name (ret), ret, gst_flow_get_name (aggregated),
1157         aggregated);
1158   }
1159 }
1160
1161 static void
1162     gst_validate_pad_monitor_otherpad_add_pending_serialized_event
1163     (GstValidatePadMonitor * monitor, GstEvent * event, GstClockTime last_ts)
1164 {
1165   GstIterator *iter;
1166   gboolean done;
1167   GstPad *otherpad;
1168   GstValidatePadMonitor *othermonitor;
1169
1170   if (!GST_EVENT_IS_SERIALIZED (event))
1171     return;
1172
1173   iter =
1174       gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
1175       (monitor));
1176   if (iter == NULL) {
1177     /* inputselector will return NULL if the sinkpad is not the active one .... */
1178     GST_FIXME_OBJECT (GST_VALIDATE_PAD_MONITOR_GET_PAD
1179         (monitor), "No iterator");
1180     return;
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         othermonitor =
1189             g_object_get_data ((GObject *) otherpad, "validate-monitor");
1190         if (othermonitor) {
1191           SerializedEventData *data = g_slice_new0 (SerializedEventData);
1192           data->timestamp = last_ts;
1193           data->event = gst_event_ref (event);
1194           GST_VALIDATE_MONITOR_LOCK (othermonitor);
1195           GST_DEBUG_OBJECT (monitor->pad, "Storing for pad %s:%s event %p %s",
1196               GST_DEBUG_PAD_NAME (otherpad), event,
1197               GST_EVENT_TYPE_NAME (event));
1198           g_ptr_array_add (othermonitor->serialized_events, data);
1199           debug_pending_event (otherpad, othermonitor->serialized_events);
1200           GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1201         }
1202         g_value_reset (&value);
1203         break;
1204       case GST_ITERATOR_RESYNC:
1205         gst_iterator_resync (iter);
1206         break;
1207       case GST_ITERATOR_ERROR:
1208         GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error");
1209         done = TRUE;
1210         break;
1211       case GST_ITERATOR_DONE:
1212         done = TRUE;
1213         break;
1214     }
1215   }
1216   gst_iterator_free (iter);
1217 }
1218
1219 static void
1220 gst_validate_pad_monitor_otherpad_add_pending_field (GstValidatePadMonitor *
1221     monitor, GstStructure * structure, const gchar * field)
1222 {
1223   GstIterator *iter;
1224   gboolean done;
1225   GstPad *otherpad;
1226   GstValidatePadMonitor *othermonitor;
1227   const GValue *v;
1228
1229   v = gst_structure_get_value (structure, field);
1230   if (v == NULL) {
1231     GST_DEBUG_OBJECT (monitor->pad, "Not adding pending field %s as it isn't "
1232         "present on structure %" GST_PTR_FORMAT, field, structure);
1233     return;
1234   }
1235
1236   iter =
1237       gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
1238       (monitor));
1239   done = FALSE;
1240   while (!done) {
1241     GValue value = { 0, };
1242     switch (gst_iterator_next (iter, &value)) {
1243       case GST_ITERATOR_OK:
1244         otherpad = g_value_get_object (&value);
1245         othermonitor =
1246             g_object_get_data ((GObject *) otherpad, "validate-monitor");
1247         if (othermonitor) {
1248           GST_VALIDATE_MONITOR_LOCK (othermonitor);
1249           g_assert (othermonitor->pending_setcaps_fields != NULL);
1250           gst_structure_set_value (othermonitor->pending_setcaps_fields,
1251               field, v);
1252           GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1253         }
1254         g_value_reset (&value);
1255         break;
1256       case GST_ITERATOR_RESYNC:
1257         gst_iterator_resync (iter);
1258         break;
1259       case GST_ITERATOR_ERROR:
1260         GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error");
1261         done = TRUE;
1262         break;
1263       case GST_ITERATOR_DONE:
1264         done = TRUE;
1265         break;
1266     }
1267   }
1268   gst_iterator_free (iter);
1269 }
1270
1271 static void
1272 gst_validate_pad_monitor_otherpad_clear_pending_fields (GstValidatePadMonitor *
1273     monitor)
1274 {
1275   GstIterator *iter;
1276   gboolean done;
1277   GstPad *otherpad;
1278   GstValidatePadMonitor *othermonitor;
1279
1280   iter =
1281       gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
1282       (monitor));
1283
1284   if (iter == NULL) {
1285     GST_DEBUG_OBJECT (monitor, "No internally linked pad");
1286
1287     return;
1288   }
1289
1290   done = FALSE;
1291   while (!done) {
1292     GValue value = { 0, };
1293     switch (gst_iterator_next (iter, &value)) {
1294       case GST_ITERATOR_OK:
1295         otherpad = g_value_get_object (&value);
1296         othermonitor =
1297             g_object_get_data ((GObject *) otherpad, "validate-monitor");
1298         if (othermonitor) {
1299           GST_VALIDATE_MONITOR_LOCK (othermonitor);
1300           g_assert (othermonitor->pending_setcaps_fields != NULL);
1301           gst_structure_free (othermonitor->pending_setcaps_fields);
1302           othermonitor->pending_setcaps_fields =
1303               gst_structure_new_empty (PENDING_FIELDS);
1304           GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1305         }
1306         g_value_reset (&value);
1307         break;
1308       case GST_ITERATOR_RESYNC:
1309         gst_iterator_resync (iter);
1310         break;
1311       case GST_ITERATOR_ERROR:
1312         GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error");
1313         done = TRUE;
1314         break;
1315       case GST_ITERATOR_DONE:
1316         done = TRUE;
1317         break;
1318     }
1319   }
1320   gst_iterator_free (iter);
1321 }
1322
1323 static void
1324 gst_validate_pad_monitor_add_expected_newsegment (GstValidatePadMonitor *
1325     monitor, GstEvent * event)
1326 {
1327   GstIterator *iter;
1328   gboolean done;
1329   GstPad *otherpad;
1330   GstValidatePadMonitor *othermonitor;
1331
1332   iter =
1333       gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
1334       (monitor));
1335
1336   if (iter == NULL) {
1337     GST_DEBUG_OBJECT (monitor, "No internally linked pad");
1338     return;
1339   }
1340
1341   done = FALSE;
1342   while (!done) {
1343     GValue value = { 0, };
1344     switch (gst_iterator_next (iter, &value)) {
1345       case GST_ITERATOR_OK:
1346         otherpad = g_value_get_object (&value);
1347         if (!otherpad)
1348           continue;
1349         othermonitor =
1350             g_object_get_data ((GObject *) otherpad, "validate-monitor");
1351         GST_VALIDATE_MONITOR_LOCK (othermonitor);
1352         gst_event_replace (&othermonitor->expected_segment, event);
1353         GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1354         g_value_reset (&value);
1355         break;
1356       case GST_ITERATOR_RESYNC:
1357         gst_iterator_resync (iter);
1358         break;
1359       case GST_ITERATOR_ERROR:
1360         GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error");
1361         done = TRUE;
1362         break;
1363       case GST_ITERATOR_DONE:
1364         done = TRUE;
1365         break;
1366     }
1367   }
1368   gst_iterator_free (iter);
1369 }
1370
1371 static void
1372 gst_validate_pad_monitor_flush (GstValidatePadMonitor * pad_monitor)
1373 {
1374   pad_monitor->current_timestamp = GST_CLOCK_TIME_NONE;
1375   pad_monitor->current_duration = GST_CLOCK_TIME_NONE;
1376   pad_monitor->timestamp_range_start = GST_CLOCK_TIME_NONE;
1377   pad_monitor->timestamp_range_end = GST_CLOCK_TIME_NONE;
1378   pad_monitor->has_segment = FALSE;
1379   pad_monitor->is_eos = FALSE;
1380   pad_monitor->last_flow_return = GST_FLOW_OK;
1381   gst_caps_replace (&pad_monitor->last_caps, NULL);
1382   pad_monitor->caps_is_audio = pad_monitor->caps_is_video =
1383       pad_monitor->caps_is_raw = FALSE;
1384
1385   g_list_free_full (pad_monitor->expired_events,
1386       (GDestroyNotify) gst_event_unref);
1387   pad_monitor->expired_events = NULL;
1388
1389   if (pad_monitor->serialized_events->len)
1390     g_ptr_array_remove_range (pad_monitor->serialized_events, 0,
1391         pad_monitor->serialized_events->len);
1392 }
1393
1394 /* common checks for both sink and src event functions */
1395 static void
1396 gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor *
1397     pad_monitor, GstEvent * event)
1398 {
1399   guint32 seqnum = gst_event_get_seqnum (event);
1400
1401   switch (GST_EVENT_TYPE (event)) {
1402     case GST_EVENT_FLUSH_START:
1403     {
1404       if (pad_monitor->pending_flush_start_seqnum) {
1405         if (seqnum == pad_monitor->pending_flush_start_seqnum) {
1406           pad_monitor->pending_flush_start_seqnum = 0;
1407         } else {
1408           GST_VALIDATE_REPORT (pad_monitor, FLUSH_START_HAS_WRONG_SEQNUM,
1409               "Got: %u Expected: %u", seqnum,
1410               pad_monitor->pending_flush_start_seqnum);
1411         }
1412       }
1413
1414       if (pad_monitor->pending_flush_stop) {
1415         GST_VALIDATE_REPORT (pad_monitor, EVENT_FLUSH_START_UNEXPECTED,
1416             "Received flush-start from " " when flush-stop was expected");
1417       }
1418       pad_monitor->pending_flush_stop = TRUE;
1419     }
1420       break;
1421     case GST_EVENT_FLUSH_STOP:
1422     {
1423       if (pad_monitor->pending_flush_stop_seqnum) {
1424         if (seqnum == pad_monitor->pending_flush_stop_seqnum) {
1425           pad_monitor->pending_flush_stop_seqnum = 0;
1426         } else {
1427           GST_VALIDATE_REPORT (pad_monitor, FLUSH_STOP_HAS_WRONG_SEQNUM,
1428               "Got: %u Expected: %u", seqnum,
1429               pad_monitor->pending_flush_stop_seqnum);
1430         }
1431       }
1432
1433       pad_monitor->pending_newsegment_seqnum = seqnum;
1434       pad_monitor->pending_eos_seqnum = seqnum;
1435
1436       if (!pad_monitor->pending_flush_stop) {
1437         gchar *event_str = _get_event_string (event);
1438
1439         GST_VALIDATE_REPORT (pad_monitor, EVENT_FLUSH_STOP_UNEXPECTED,
1440             "Unexpected flush-stop %s", event_str);
1441         g_free (event_str);
1442       }
1443       pad_monitor->pending_flush_stop = FALSE;
1444
1445       /* cleanup our data */
1446       gst_validate_pad_monitor_flush (pad_monitor);
1447     }
1448       break;
1449     default:
1450       break;
1451   }
1452 }
1453
1454 static void
1455 mark_pads_eos (GstValidatePadMonitor * pad_monitor)
1456 {
1457   GstValidatePadMonitor *peer_monitor;
1458   GstPad *peer = gst_pad_get_peer (pad_monitor->pad);
1459   GstPad *real_peer;
1460
1461   pad_monitor->is_eos = TRUE;
1462   if (peer) {
1463     real_peer = _get_actual_pad (peer);
1464     peer_monitor =
1465         g_object_get_data ((GObject *) real_peer, "validate-monitor");
1466     if (peer_monitor)
1467       peer_monitor->is_eos = TRUE;
1468     gst_object_unref (peer);
1469     gst_object_unref (real_peer);
1470   }
1471 }
1472
1473 static inline gboolean
1474 _should_check_buffers (GstValidatePadMonitor * pad_monitor,
1475     gboolean force_checks)
1476 {
1477   GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor);
1478   GstValidateMonitor *monitor = GST_VALIDATE_MONITOR (pad_monitor);
1479
1480   if (pad_monitor->first_buffer || force_checks) {
1481     if (pad_monitor->segment.rate != 1.0) {
1482       GST_INFO_OBJECT (pad_monitor, "We do not support buffer checking"
1483           " for trick modes");
1484
1485       pad_monitor->check_buffers = FALSE;
1486     } else if (!PAD_PARENT_IS_DECODER (pad_monitor)) {
1487       GST_DEBUG_OBJECT (pad, "Not on a decoder => no buffer checking");
1488
1489       pad_monitor->check_buffers = FALSE;
1490     } else if (GST_PAD_DIRECTION (pad) != GST_PAD_SINK) {
1491       GST_DEBUG_OBJECT (pad, "Not a sinkpad => no buffer checking");
1492
1493       pad_monitor->check_buffers = FALSE;
1494     } else if (!pad_monitor->caps_is_video) {
1495       GST_DEBUG_OBJECT (pad, "Not working with video => no buffer checking");
1496
1497       pad_monitor->check_buffers = FALSE;
1498     } else if (monitor->media_descriptor == NULL) {
1499       GST_DEBUG_OBJECT (pad, "No media_descriptor set => no buffer checking");
1500
1501       pad_monitor->check_buffers = FALSE;
1502     } else if (!gst_media_descriptor_detects_frames (monitor->media_descriptor)) {
1503       GST_DEBUG_OBJECT (pad, "No frame detection media descriptor "
1504           "=> not buffer checking");
1505       pad_monitor->check_buffers = FALSE;
1506     } else if (pad_monitor->all_bufs == NULL &&
1507         !gst_media_descriptor_get_buffers (monitor->media_descriptor, pad, NULL,
1508             &pad_monitor->all_bufs)) {
1509
1510       GST_INFO_OBJECT (monitor,
1511           "The MediaInfo is marked as detecting frame, but getting frames"
1512           " from pad %" GST_PTR_FORMAT " did not work (some format conversion"
1513           " might be happening)", pad);
1514
1515       pad_monitor->check_buffers = FALSE;
1516     } else {
1517       if (!pad_monitor->current_buf)
1518         pad_monitor->current_buf = pad_monitor->all_bufs;
1519       pad_monitor->check_buffers = TRUE;
1520     }
1521   }
1522
1523   return pad_monitor->check_buffers;
1524 }
1525
1526 static void
1527 gst_validate_monitor_find_next_buffer (GstValidatePadMonitor * pad_monitor)
1528 {
1529   GList *tmp;
1530   gboolean passed_start = FALSE;
1531
1532   if (!_should_check_buffers (pad_monitor, TRUE))
1533     return;
1534
1535   for (tmp = g_list_last (pad_monitor->all_bufs); tmp; tmp = tmp->prev) {
1536     GstBuffer *cbuf = tmp->data;
1537     GstClockTime ts =
1538         GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DTS (cbuf)) ? GST_BUFFER_DTS (cbuf)
1539         : GST_BUFFER_PTS (cbuf);
1540
1541     if (!GST_CLOCK_TIME_IS_VALID (ts))
1542       continue;
1543
1544     if (ts <= pad_monitor->segment.start)
1545       passed_start = TRUE;
1546
1547     if (!passed_start)
1548       continue;
1549
1550     if (!GST_BUFFER_FLAG_IS_SET (cbuf, GST_BUFFER_FLAG_DELTA_UNIT)) {
1551       break;
1552     }
1553   }
1554
1555   if (tmp == NULL)
1556     pad_monitor->current_buf = pad_monitor->all_bufs;
1557   else
1558     pad_monitor->current_buf = tmp;
1559 }
1560
1561 static gboolean
1562 gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor *
1563     pad_monitor, GstObject * parent, GstEvent * event,
1564     GstPadEventFunction handler)
1565 {
1566   gboolean ret = TRUE;
1567   const GstSegment *segment;
1568   guint32 seqnum = gst_event_get_seqnum (event);
1569   GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor);
1570
1571   gst_validate_pad_monitor_common_event_check (pad_monitor, event);
1572
1573   /* pre checks */
1574   switch (GST_EVENT_TYPE (event)) {
1575     case GST_EVENT_SEGMENT:
1576       /* parse segment data to be used if event is handled */
1577       gst_event_parse_segment (event, &segment);
1578
1579       GST_DEBUG_OBJECT (pad_monitor->pad, "Got segment %" GST_SEGMENT_FORMAT,
1580           segment);
1581
1582       if (pad_monitor->pending_newsegment_seqnum) {
1583         if (pad_monitor->pending_newsegment_seqnum == seqnum) {
1584           pad_monitor->pending_newsegment_seqnum = 0;
1585         } else {
1586           GST_VALIDATE_REPORT (pad_monitor, SEGMENT_HAS_WRONG_SEQNUM,
1587               "Got: %u Expected: %u", seqnum, pad_monitor->pending_eos_seqnum);
1588         }
1589       }
1590
1591       pad_monitor->pending_eos_seqnum = seqnum;
1592
1593       if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
1594         gst_validate_pad_monitor_add_expected_newsegment (pad_monitor, event);
1595       } else {
1596         /* check if this segment is the expected one */
1597         if (pad_monitor->expected_segment) {
1598           const GstSegment *exp_segment;
1599
1600           if (pad_monitor->expected_segment != event) {
1601             gst_event_parse_segment (pad_monitor->expected_segment,
1602                 &exp_segment);
1603             if (segment->format == exp_segment->format) {
1604               if ((exp_segment->rate * exp_segment->applied_rate !=
1605                       segment->rate * segment->applied_rate))
1606                 GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH,
1607                     "Rate * applied_rate %d != expected %d",
1608                     segment->rate * segment->applied_rate,
1609                     exp_segment->rate * exp_segment->applied_rate);
1610               if (exp_segment->start != segment->start)
1611                 GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH,
1612                     "Start %" GST_TIME_FORMAT " != expected %" GST_TIME_FORMAT,
1613                     GST_TIME_ARGS (segment->start),
1614                     GST_TIME_ARGS (exp_segment->start));
1615               if (exp_segment->stop != segment->stop)
1616                 GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH,
1617                     "Stop %" GST_TIME_FORMAT " != expected %" GST_TIME_FORMAT,
1618                     GST_TIME_ARGS (segment->stop),
1619                     GST_TIME_ARGS (exp_segment->stop));
1620               if (exp_segment->position != segment->position)
1621                 GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH,
1622                     "Position %" GST_TIME_FORMAT " != expected %"
1623                     GST_TIME_FORMAT, GST_TIME_ARGS (segment->position),
1624                     GST_TIME_ARGS (exp_segment->position));
1625             }
1626           }
1627           gst_event_replace (&pad_monitor->expected_segment, NULL);
1628         }
1629       }
1630       break;
1631     case GST_EVENT_CAPS:{
1632       GstCaps *caps;
1633
1634       gst_event_parse_caps (event, &caps);
1635       gst_validate_pad_monitor_setcaps_pre (pad_monitor, caps);
1636       break;
1637     }
1638     case GST_EVENT_EOS:
1639       pad_monitor->is_eos = TRUE;
1640       if (pad_monitor->pending_eos_seqnum == 0) {
1641         GST_VALIDATE_REPORT (pad_monitor, EVENT_EOS_WITHOUT_SEGMENT,
1642             "EOS %" GST_PTR_FORMAT " received before a segment was received",
1643             event);
1644       } else if (pad_monitor->pending_eos_seqnum != seqnum) {
1645         GST_VALIDATE_REPORT (pad_monitor, EOS_HAS_WRONG_SEQNUM,
1646             "Got: %u. Expected: %u", seqnum, pad_monitor->pending_eos_seqnum);
1647       }
1648
1649       /*
1650        * TODO add end of stream checks for
1651        *  - events not pushed
1652        *  - buffer data not pushed
1653        *  - pending events not received
1654        */
1655       break;
1656
1657       /* both flushes are handled by the common event function */
1658     case GST_EVENT_FLUSH_START:
1659     case GST_EVENT_FLUSH_STOP:
1660     case GST_EVENT_TAG:
1661     case GST_EVENT_SINK_MESSAGE:
1662     default:
1663       break;
1664   }
1665
1666   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1667   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
1668   gst_validate_pad_monitor_event_overrides (pad_monitor, event);
1669   if (handler) {
1670     gst_event_ref (event);
1671     ret = pad_monitor->event_func (pad, parent, event);
1672   }
1673   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
1674   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1675
1676   /* post checks */
1677   switch (GST_EVENT_TYPE (event)) {
1678     case GST_EVENT_SEGMENT:
1679       if (ret) {
1680         if (!pad_monitor->has_segment
1681             && pad_monitor->segment.format != segment->format) {
1682           gst_segment_init (&pad_monitor->segment, segment->format);
1683         }
1684         gst_segment_copy_into (segment, &pad_monitor->segment);
1685         pad_monitor->has_segment = TRUE;
1686         gst_validate_monitor_find_next_buffer (pad_monitor);
1687       }
1688       break;
1689     case GST_EVENT_CAPS:{
1690       GstCaps *caps;
1691
1692       gst_event_parse_caps (event, &caps);
1693       gst_validate_pad_monitor_setcaps_post (pad_monitor, caps, ret);
1694       break;
1695     }
1696     case GST_EVENT_FLUSH_START:
1697     case GST_EVENT_FLUSH_STOP:
1698     case GST_EVENT_EOS:
1699     case GST_EVENT_TAG:
1700     case GST_EVENT_SINK_MESSAGE:
1701     default:
1702       break;
1703   }
1704
1705   if (handler)
1706     gst_event_unref (event);
1707   return ret;
1708 }
1709
1710 static gboolean
1711 gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor,
1712     GstObject * parent, GstEvent * event, GstPadEventFunction handler)
1713 {
1714   gboolean ret = TRUE;
1715   gdouble rate;
1716   GstFormat format;
1717   gint64 start, stop;
1718   GstSeekFlags seek_flags;
1719   GstSeekType start_type, stop_type;
1720   guint32 seqnum = gst_event_get_seqnum (event);
1721   GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor);
1722
1723   gst_validate_pad_monitor_common_event_check (pad_monitor, event);
1724
1725   /* pre checks */
1726   switch (GST_EVENT_TYPE (event)) {
1727     case GST_EVENT_SEEK:
1728     {
1729       gst_event_parse_seek (event, &rate, &format, &seek_flags, &start_type,
1730           &start, &stop_type, &stop);
1731       /* upstream seek - store the seek event seqnum to check
1732        * flushes and newsegments share the same */
1733
1734       /* TODO we might need to use a list as multiple seeks can be sent
1735        * before the flushes arrive here */
1736       if (seek_flags & GST_SEEK_FLAG_FLUSH) {
1737         pad_monitor->pending_flush_start_seqnum = seqnum;
1738         pad_monitor->pending_flush_stop_seqnum = seqnum;
1739       }
1740     }
1741       break;
1742       /* both flushes are handled by the common event handling function */
1743     case GST_EVENT_FLUSH_START:
1744     case GST_EVENT_FLUSH_STOP:
1745     case GST_EVENT_NAVIGATION:
1746     case GST_EVENT_LATENCY:
1747     case GST_EVENT_STEP:
1748     case GST_EVENT_QOS:
1749     default:
1750       break;
1751   }
1752
1753   if (handler) {
1754     GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1755     gst_event_ref (event);
1756     ret = pad_monitor->event_func (pad, parent, event);
1757     GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1758   }
1759
1760   /* post checks */
1761   switch (GST_EVENT_TYPE (event)) {
1762     case GST_EVENT_FLUSH_START:
1763     case GST_EVENT_FLUSH_STOP:
1764     case GST_EVENT_QOS:
1765     case GST_EVENT_SEEK:
1766     {
1767       if (ret == FALSE) {
1768         /* do not expect any of these events anymore */
1769         pad_monitor->pending_flush_start_seqnum = 0;
1770         pad_monitor->pending_flush_stop_seqnum = 0;
1771         pad_monitor->pending_newsegment_seqnum = 0;
1772         pad_monitor->pending_eos_seqnum = 0;
1773       }
1774     }
1775       break;
1776     case GST_EVENT_NAVIGATION:
1777     case GST_EVENT_LATENCY:
1778     case GST_EVENT_STEP:
1779     default:
1780       break;
1781   }
1782
1783   if (handler)
1784     gst_event_unref (event);
1785   return ret;
1786 }
1787
1788 static gboolean
1789 gst_validate_pad_monitor_check_right_buffer (GstValidatePadMonitor *
1790     pad_monitor, GstBuffer * buffer)
1791 {
1792   gchar *checksum;
1793   GstBuffer *wanted_buf;
1794   GstMapInfo map, wanted_map;
1795
1796   gboolean ret = TRUE;
1797   GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor);
1798
1799   if (_should_check_buffers (pad_monitor, FALSE) == FALSE)
1800     return FALSE;
1801
1802   if (pad_monitor->current_buf == NULL) {
1803     GST_INFO_OBJECT (pad, "No current buffer one pad, Why?");
1804     return FALSE;
1805   }
1806
1807   wanted_buf = pad_monitor->current_buf->data;
1808
1809   if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (wanted_buf)) &&
1810       GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (buffer)) &&
1811       GST_BUFFER_PTS (wanted_buf) != GST_BUFFER_PTS (buffer)) {
1812
1813     GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER,
1814         "buffer %" GST_PTR_FORMAT " PTS %ld"
1815         " different than expected: %ld", buffer,
1816         GST_BUFFER_PTS (buffer), GST_BUFFER_PTS (wanted_buf));
1817
1818     ret = FALSE;
1819   }
1820
1821   if (GST_BUFFER_DTS (wanted_buf) != GST_BUFFER_DTS (buffer)) {
1822     GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER,
1823         "buffer %" GST_PTR_FORMAT " DTS %" GST_TIME_FORMAT
1824         " different than expected: %" GST_TIME_FORMAT, buffer,
1825         GST_TIME_ARGS (GST_BUFFER_DTS (buffer)),
1826         GST_TIME_ARGS (GST_BUFFER_DTS (wanted_buf)));
1827     ret = FALSE;
1828   }
1829
1830   if (GST_BUFFER_DURATION (wanted_buf) != GST_BUFFER_DURATION (buffer)) {
1831     GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER,
1832         "buffer %" GST_PTR_FORMAT " DURATION %" GST_TIME_FORMAT
1833         " different than expected: %" GST_TIME_FORMAT, buffer,
1834         GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)),
1835         GST_TIME_ARGS (GST_BUFFER_DURATION (wanted_buf)));
1836     ret = FALSE;
1837   }
1838
1839   if (GST_BUFFER_FLAG_IS_SET (wanted_buf, GST_BUFFER_FLAG_DELTA_UNIT) !=
1840       GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)) {
1841     GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER,
1842         "buffer %" GST_PTR_FORMAT "  Delta unit is set to %s but expected %s",
1843         buffer, GST_BUFFER_FLAG_IS_SET (buffer,
1844             GST_BUFFER_FLAG_DELTA_UNIT) ? "True" : "False",
1845         GST_BUFFER_FLAG_IS_SET (wanted_buf,
1846             GST_BUFFER_FLAG_DELTA_UNIT) ? "True" : "False");
1847     ret = FALSE;
1848   }
1849
1850   g_assert (gst_buffer_map (wanted_buf, &wanted_map, GST_MAP_READ));
1851   g_assert (gst_buffer_map (buffer, &map, GST_MAP_READ));
1852
1853   checksum = g_compute_checksum_for_data (G_CHECKSUM_MD5,
1854       (const guchar *) map.data, map.size);
1855
1856   if (g_strcmp0 ((gchar *) wanted_map.data, checksum)) {
1857     GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER,
1858         "buffer %" GST_PTR_FORMAT " checksum %s different from expected: %s",
1859         buffer, checksum, wanted_map.data);
1860     ret = FALSE;
1861   }
1862
1863   gst_buffer_unmap (wanted_buf, &wanted_map);
1864   gst_buffer_unmap (buffer, &map);
1865   g_free (checksum);
1866
1867   pad_monitor->current_buf = pad_monitor->current_buf->next;
1868
1869   return ret;
1870 }
1871
1872 static GstFlowReturn
1873 gst_validate_pad_monitor_chain_func (GstPad * pad, GstObject * parent,
1874     GstBuffer * buffer)
1875 {
1876   GstValidatePadMonitor *pad_monitor =
1877       g_object_get_data ((GObject *) pad, "validate-monitor");
1878   GstFlowReturn ret;
1879
1880   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
1881   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1882
1883   gst_validate_pad_monitor_check_right_buffer (pad_monitor, buffer);
1884   gst_validate_pad_monitor_check_first_buffer (pad_monitor, buffer);
1885   gst_validate_pad_monitor_update_buffer_data (pad_monitor, buffer);
1886   gst_validate_pad_monitor_check_eos (pad_monitor, buffer);
1887
1888   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1889   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
1890
1891   gst_validate_pad_monitor_buffer_overrides (pad_monitor, buffer);
1892
1893   ret = pad_monitor->chain_func (pad, parent, buffer);
1894
1895   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
1896   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1897
1898   pad_monitor->last_flow_return = ret;
1899   if (ret == GST_FLOW_EOS) {
1900     mark_pads_eos (pad_monitor);
1901   }
1902   if (PAD_PARENT_IS_DEMUXER (pad_monitor))
1903     gst_validate_pad_monitor_check_aggregated_return (pad_monitor, ret);
1904
1905   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1906   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
1907
1908   return ret;
1909 }
1910
1911 static gboolean
1912 gst_validate_pad_monitor_event_is_tracked (GstValidatePadMonitor * monitor,
1913     GstEvent * event)
1914 {
1915   if (!GST_EVENT_IS_SERIALIZED (event)) {
1916     return FALSE;
1917   }
1918
1919   /* we don't track Tag events because they mutate too much and it is hard
1920    * to match a tag event pushed on a source pad with the one that was received
1921    * on a sink pad.
1922    * One idea would be to use seqnum, but it seems that it is undefined whether
1923    * seqnums should be maintained in tag events that are created from others
1924    * up to today. (2013-08-29)
1925    */
1926   if (GST_EVENT_TYPE (event) == GST_EVENT_TAG)
1927     return FALSE;
1928
1929   return TRUE;
1930 }
1931
1932 static gboolean
1933 gst_validate_pad_monitor_sink_event_func (GstPad * pad, GstObject * parent,
1934     GstEvent * event)
1935 {
1936   GstValidatePadMonitor *pad_monitor =
1937       g_object_get_data ((GObject *) pad, "validate-monitor");
1938   gboolean ret;
1939
1940   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
1941   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1942
1943   if (gst_validate_pad_monitor_event_is_tracked (pad_monitor, event)) {
1944     GstClockTime last_ts = GST_CLOCK_TIME_NONE;
1945     if (GST_CLOCK_TIME_IS_VALID (pad_monitor->current_timestamp)) {
1946       last_ts = pad_monitor->current_timestamp;
1947       if (GST_CLOCK_TIME_IS_VALID (pad_monitor->current_duration)) {
1948         last_ts += pad_monitor->current_duration;
1949       }
1950     }
1951     gst_validate_pad_monitor_otherpad_add_pending_serialized_event (pad_monitor,
1952         event, last_ts);
1953   }
1954
1955   ret =
1956       gst_validate_pad_monitor_downstream_event_check (pad_monitor, parent,
1957       event, pad_monitor->event_func);
1958
1959   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1960   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
1961   return ret;
1962 }
1963
1964 static gboolean
1965 gst_validate_pad_monitor_src_event_func (GstPad * pad, GstObject * parent,
1966     GstEvent * event)
1967 {
1968   GstValidatePadMonitor *pad_monitor =
1969       g_object_get_data ((GObject *) pad, "validate-monitor");
1970   gboolean ret;
1971
1972   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1973   ret = gst_validate_pad_monitor_src_event_check (pad_monitor, parent, event,
1974       pad_monitor->event_func);
1975   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1976   return ret;
1977 }
1978
1979 static gboolean
1980 gst_validate_pad_monitor_query_func (GstPad * pad, GstObject * parent,
1981     GstQuery * query)
1982 {
1983   GstValidatePadMonitor *pad_monitor =
1984       g_object_get_data ((GObject *) pad, "validate-monitor");
1985   gboolean ret;
1986
1987   gst_validate_pad_monitor_query_overrides (pad_monitor, query);
1988
1989   ret = pad_monitor->query_func (pad, parent, query);
1990
1991   if (ret) {
1992     switch (GST_QUERY_TYPE (query)) {
1993       case GST_QUERY_CAPS:{
1994         GstCaps *res;
1995         /* We shouldn't need to lock the parent as this doesn't modify
1996          * other monitors, just does some peer_pad_caps */
1997         GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1998
1999         gst_query_parse_caps_result (query, &res);
2000         if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
2001           gst_validate_pad_monitor_check_caps_fields_proxied (pad_monitor, res);
2002         }
2003         GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
2004         break;
2005       }
2006       default:
2007         break;
2008     }
2009   }
2010
2011   return ret;
2012 }
2013
2014 static gboolean
2015 gst_validate_pad_monitor_activatemode_func (GstPad * pad, GstObject * parent,
2016     GstPadMode mode, gboolean active)
2017 {
2018   GstValidatePadMonitor *pad_monitor =
2019       g_object_get_data ((GObject *) pad, "validate-monitor");
2020   gboolean ret = TRUE;
2021
2022   /* TODO add overrides for activate func */
2023
2024   if (pad_monitor->activatemode_func)
2025     ret = pad_monitor->activatemode_func (pad, parent, mode, active);
2026   if (ret && active == FALSE) {
2027     GST_VALIDATE_MONITOR_LOCK (pad_monitor);
2028     gst_validate_pad_monitor_flush (pad_monitor);
2029     GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
2030   }
2031
2032   return ret;
2033 }
2034
2035 static gboolean
2036 gst_validate_pad_get_range_func (GstPad * pad, GstObject * parent,
2037     guint64 offset, guint size, GstBuffer ** buffer)
2038 {
2039   GstValidatePadMonitor *pad_monitor =
2040       g_object_get_data ((GObject *) pad, "validate-monitor");
2041   gboolean ret;
2042   ret = pad_monitor->getrange_func (pad, parent, offset, size, buffer);
2043   return ret;
2044 }
2045
2046 static gboolean
2047 gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer,
2048     gpointer udata)
2049 {
2050   GstValidatePadMonitor *monitor = udata;
2051
2052   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor);
2053   GST_VALIDATE_MONITOR_LOCK (monitor);
2054
2055   gst_validate_pad_monitor_check_first_buffer (monitor, buffer);
2056   gst_validate_pad_monitor_update_buffer_data (monitor, buffer);
2057   gst_validate_pad_monitor_check_eos (monitor, buffer);
2058
2059   if (PAD_PARENT_IS_DECODER (monitor) || PAD_PARENT_IS_ENCODER (monitor)) {
2060     GstClockTime tolerance = 0;
2061
2062     if (monitor->caps_is_audio)
2063       tolerance = AUDIO_TIMESTAMP_TOLERANCE;
2064
2065     gst_validate_pad_monitor_check_buffer_timestamp_in_received_range (monitor,
2066         buffer, tolerance);
2067   }
2068
2069   gst_validate_pad_monitor_check_late_serialized_events (monitor,
2070       GST_BUFFER_TIMESTAMP (buffer));
2071
2072   /* a GstValidatePadMonitor parent must be a GstValidateElementMonitor */
2073   if (PAD_PARENT_IS_DECODER (monitor)) {
2074
2075     /* should not push out of segment data */
2076     if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer)) &&
2077         GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer)) &&
2078         ((!gst_segment_clip (&monitor->segment, monitor->segment.format,
2079                     GST_BUFFER_TIMESTAMP (buffer),
2080                     GST_BUFFER_TIMESTAMP (buffer) +
2081                     GST_BUFFER_DURATION (buffer), NULL, NULL)) ||
2082             /* In the case of raw data, buffers should be strictly contained inside the
2083              * segment */
2084             (monitor->caps_is_raw &&
2085                 GST_BUFFER_PTS (buffer) + GST_BUFFER_DURATION (buffer) <
2086                 monitor->segment.start))
2087         ) {
2088       /* TODO is this a timestamp issue? */
2089       GST_VALIDATE_REPORT (monitor, BUFFER_IS_OUT_OF_SEGMENT,
2090           "buffer is out of segment and shouldn't be pushed. Timestamp: %"
2091           GST_TIME_FORMAT " - duration: %" GST_TIME_FORMAT ". Range: %"
2092           GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2093           GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
2094           GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)),
2095           GST_TIME_ARGS (monitor->segment.start),
2096           GST_TIME_ARGS (monitor->segment.stop));
2097     }
2098   }
2099
2100   GST_VALIDATE_MONITOR_UNLOCK (monitor);
2101   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (monitor);
2102   gst_validate_pad_monitor_buffer_probe_overrides (monitor, buffer);
2103   return TRUE;
2104 }
2105
2106 static gboolean
2107 gst_validate_pad_monitor_event_probe (GstPad * pad, GstEvent * event,
2108     gpointer udata)
2109 {
2110   GstValidatePadMonitor *monitor = GST_VALIDATE_PAD_MONITOR_CAST (udata);
2111   gboolean ret;
2112
2113   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor);
2114   GST_VALIDATE_MONITOR_LOCK (monitor);
2115
2116   GST_DEBUG_OBJECT (pad, "event %p %s", event, GST_EVENT_TYPE_NAME (event));
2117
2118   if (GST_EVENT_IS_SERIALIZED (event)) {
2119     gint i;
2120
2121     /* Detect if events the element received are being forwarded in the same order
2122      *
2123      * Several scenarios:
2124      * 1) The element pushes the event as-is
2125      * 2) The element consumes the event and does not forward it
2126      * 3) The element consumes the event and creates another one instead
2127      * 4) The element pushes other serialized event before pushing out the
2128      *    one it received
2129      *
2130      * For each pad we have two lists to track serialized events:
2131      *  1) We received on input and expect to see (serialized_events)
2132      *  2) We received on input but don't expect to see (expired_events)
2133      *
2134      * To detect events that are pushed in a different order from the one they were
2135      * received in we check that:
2136      *
2137      * For each event being outputted:
2138      *   If it is in the expired_events list:
2139      *     RAISE WARNING
2140      *   If it is in the serialized_events list:
2141      *     If there are other events that were received before:
2142      *        Put those events on the expired_events list
2143      *     Remove that event and any previous ones from the serialized_events list
2144      *
2145      * Clear expired events list when flushing or on pad deactivation
2146      *
2147      */
2148
2149     if (g_list_find (monitor->expired_events, event)) {
2150       gchar *event_str = _get_event_string (event);
2151       /* If it's the expired events, we've failed */
2152       GST_WARNING_OBJECT (pad, "Did not expect event %p %s", event,
2153           GST_EVENT_TYPE_NAME (event));
2154       GST_VALIDATE_REPORT (monitor, EVENT_SERIALIZED_OUT_OF_ORDER,
2155           "Serialized event was pushed out of order: %s", event_str);
2156
2157       g_free (event_str);
2158       monitor->expired_events = g_list_remove (monitor->expired_events, event);
2159       gst_event_unref (event);  /* remove the ref that was on the list */
2160     } else if (monitor->serialized_events->len) {
2161       for (i = 0; i < monitor->serialized_events->len; i++) {
2162         SerializedEventData *next_event =
2163             g_ptr_array_index (monitor->serialized_events, i);
2164         GST_DEBUG_OBJECT (pad, "Checking against stored event #%d: %p %s", i,
2165             next_event->event, GST_EVENT_TYPE_NAME (next_event->event));
2166
2167         if (event == next_event->event
2168             || GST_EVENT_TYPE (event) == GST_EVENT_TYPE (next_event->event)) {
2169           /* We have found our event */
2170           GST_DEBUG_OBJECT (pad, "Found matching event");
2171
2172           while (monitor->serialized_events->len > i
2173               && GST_EVENT_TYPE (event) == GST_EVENT_TYPE (next_event->event)) {
2174             /* Swallow all expected events of the same type */
2175             g_ptr_array_remove_index (monitor->serialized_events, i);
2176             next_event = g_ptr_array_index (monitor->serialized_events, i);
2177           }
2178
2179           /* Move all previous events to expired events */
2180           if (G_UNLIKELY (i > 0)) {
2181             GST_DEBUG_OBJECT (pad,
2182                 "Moving previous expected events to expired list");
2183             while (i--) {
2184               next_event = g_ptr_array_index (monitor->serialized_events, 0);
2185               monitor->expired_events =
2186                   g_list_append (monitor->expired_events,
2187                   gst_event_ref (next_event->event));
2188               g_ptr_array_remove_index (monitor->serialized_events, 0);
2189             }
2190           }
2191           debug_pending_event (pad, monitor->serialized_events);
2192           break;
2193         }
2194       }
2195     }
2196   }
2197
2198   /* This so far is just like an event that is flowing downstream,
2199    * so we do the same checks as a sinkpad event handler */
2200   ret =
2201       gst_validate_pad_monitor_downstream_event_check (monitor, NULL, event,
2202       NULL);
2203   GST_VALIDATE_MONITOR_UNLOCK (monitor);
2204   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (monitor);
2205
2206   return ret;
2207 }
2208
2209 static GstPadProbeReturn
2210 gst_validate_pad_monitor_pad_probe (GstPad * pad, GstPadProbeInfo * info,
2211     gpointer udata)
2212 {
2213   if (info->type & GST_PAD_PROBE_TYPE_BUFFER)
2214     gst_validate_pad_monitor_buffer_probe (pad, info->data, udata);
2215   else if (info->type & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM)
2216     gst_validate_pad_monitor_event_probe (pad, info->data, udata);
2217
2218   return GST_PAD_PROBE_OK;
2219 }
2220
2221 static void
2222 gst_validate_pad_monitor_update_caps_info (GstValidatePadMonitor * pad_monitor,
2223     GstCaps * caps)
2224 {
2225   GstStructure *structure;
2226
2227   g_return_if_fail (gst_caps_is_fixed (caps));
2228
2229   pad_monitor->caps_is_audio = FALSE;
2230   pad_monitor->caps_is_video = FALSE;
2231
2232   structure = gst_caps_get_structure (caps, 0);
2233   if (g_str_has_prefix (gst_structure_get_name (structure), "audio/")) {
2234     pad_monitor->caps_is_audio = TRUE;
2235   } else if (g_str_has_prefix (gst_structure_get_name (structure), "video/")) {
2236     pad_monitor->caps_is_video = TRUE;
2237   }
2238
2239   if (g_str_has_prefix (gst_structure_get_name (structure), "audio/x-raw") ||
2240       g_str_has_prefix (gst_structure_get_name (structure), "video/x-raw")) {
2241     pad_monitor->caps_is_raw = TRUE;
2242   } else {
2243     pad_monitor->caps_is_raw = FALSE;
2244   }
2245 }
2246
2247 static void
2248 gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor,
2249     GstCaps * caps)
2250 {
2251   GstStructure *structure;
2252
2253   /* Check if caps are identical to last caps and complain if so
2254    * Only checked for sink pads as src pads might push the same caps
2255    * multiple times during unlinked/autoplugging scenarios */
2256   if (GST_PAD_IS_SINK (GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor)) &&
2257       pad_monitor->last_caps
2258       && gst_caps_is_equal (caps, pad_monitor->last_caps)) {
2259     gchar *caps_str = gst_caps_to_string (caps);
2260
2261     GST_VALIDATE_REPORT (pad_monitor, EVENT_CAPS_DUPLICATE, "%s", caps_str);
2262     g_free (caps_str);
2263
2264   }
2265
2266   gst_validate_pad_monitor_check_caps_complete (pad_monitor, caps);
2267
2268   if (caps) {
2269     structure = gst_caps_get_structure (caps, 0);
2270     if (gst_structure_n_fields (pad_monitor->pending_setcaps_fields)) {
2271       gint i;
2272       for (i = 0;
2273           i < gst_structure_n_fields (pad_monitor->pending_setcaps_fields);
2274           i++) {
2275         const gchar *name =
2276             gst_structure_nth_field_name (pad_monitor->pending_setcaps_fields,
2277             i);
2278         const GValue *v = gst_structure_get_value (structure, name);
2279         const GValue *otherv =
2280             gst_structure_get_value (pad_monitor->pending_setcaps_fields, name);
2281
2282         if (v == NULL) {
2283           gchar *caps_str = gst_caps_to_string (caps);
2284
2285           GST_VALIDATE_REPORT (pad_monitor, CAPS_EXPECTED_FIELD_NOT_FOUND,
2286               "Field %s is missing from setcaps caps '%s'", name, caps_str);
2287           g_free (caps_str);
2288         } else if (gst_value_compare (v, otherv) != GST_VALUE_EQUAL) {
2289           gchar *caps_str = gst_caps_to_string (caps),
2290               *pending_setcaps_fields_str =
2291               gst_structure_to_string (pad_monitor->pending_setcaps_fields);
2292
2293
2294           GST_VALIDATE_REPORT (pad_monitor, CAPS_FIELD_UNEXPECTED_VALUE,
2295               "Field %s from setcaps caps '%s' is different "
2296               "from expected value in caps '%s'", name, caps_str,
2297               pending_setcaps_fields_str);
2298
2299           g_free (pending_setcaps_fields_str);
2300           g_free (caps_str);
2301         }
2302       }
2303     }
2304
2305     if (gst_validate_pad_monitor_pad_should_proxy_othercaps (pad_monitor)) {
2306       if (_structure_is_video (structure)) {
2307         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2308             structure, "width");
2309         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2310             structure, "height");
2311         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2312             structure, "framerate");
2313         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2314             structure, "pixel-aspect-ratio");
2315       } else if (_structure_is_audio (structure)) {
2316         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2317             structure, "rate");
2318         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2319             structure, "channels");
2320       }
2321     }
2322   }
2323
2324   gst_structure_free (pad_monitor->pending_setcaps_fields);
2325   pad_monitor->pending_setcaps_fields =
2326       gst_structure_new_empty (PENDING_FIELDS);
2327
2328   gst_validate_pad_monitor_setcaps_overrides (pad_monitor, caps);
2329 }
2330
2331 static void
2332 gst_validate_pad_monitor_setcaps_post (GstValidatePadMonitor * pad_monitor,
2333     GstCaps * caps, gboolean ret)
2334 {
2335   if (!ret)
2336     gst_validate_pad_monitor_otherpad_clear_pending_fields (pad_monitor);
2337   else {
2338     if (pad_monitor->last_caps) {
2339       gst_caps_unref (pad_monitor->last_caps);
2340     }
2341     pad_monitor->last_caps = gst_caps_ref (caps);
2342     gst_validate_pad_monitor_update_caps_info (pad_monitor, caps);
2343   }
2344 }
2345
2346 static gboolean
2347 gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor)
2348 {
2349   GstValidatePadMonitor *pad_monitor = GST_VALIDATE_PAD_MONITOR_CAST (monitor);
2350   GstPad *pad;
2351   if (!GST_IS_PAD (GST_VALIDATE_MONITOR_GET_OBJECT (monitor))) {
2352     GST_WARNING_OBJECT (monitor, "Trying to create pad monitor with other "
2353         "type of object");
2354     return FALSE;
2355   }
2356
2357   pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor);
2358
2359   if (g_object_get_data ((GObject *) pad, "validate-monitor")) {
2360     GST_WARNING_OBJECT (pad_monitor,
2361         "Pad already has a validate-monitor associated");
2362     return FALSE;
2363   }
2364
2365   g_object_set_data ((GObject *) pad, "validate-monitor", pad_monitor);
2366
2367   pad_monitor->pad = pad;
2368
2369   pad_monitor->event_func = GST_PAD_EVENTFUNC (pad);
2370   pad_monitor->query_func = GST_PAD_QUERYFUNC (pad);
2371   pad_monitor->activatemode_func = GST_PAD_ACTIVATEMODEFUNC (pad);
2372   if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
2373
2374     pad_monitor->chain_func = GST_PAD_CHAINFUNC (pad);
2375     if (pad_monitor->chain_func)
2376       gst_pad_set_chain_function (pad, gst_validate_pad_monitor_chain_func);
2377
2378     gst_pad_set_event_function (pad, gst_validate_pad_monitor_sink_event_func);
2379   } else {
2380     pad_monitor->getrange_func = GST_PAD_GETRANGEFUNC (pad);
2381     if (pad_monitor->getrange_func)
2382       gst_pad_set_getrange_function (pad, gst_validate_pad_get_range_func);
2383
2384     gst_pad_set_event_function (pad, gst_validate_pad_monitor_src_event_func);
2385
2386     /* add buffer/event probes */
2387     pad_monitor->pad_probe_id =
2388         gst_pad_add_probe (pad,
2389         GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM |
2390         GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2391         (GstPadProbeCallback) gst_validate_pad_monitor_pad_probe, pad_monitor,
2392         NULL);
2393   }
2394   gst_pad_set_query_function (pad, gst_validate_pad_monitor_query_func);
2395   gst_pad_set_activatemode_function (pad,
2396       gst_validate_pad_monitor_activatemode_func);
2397
2398   gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (monitor),
2399       g_strdup_printf ("%s:%s", GST_DEBUG_PAD_NAME (pad)));
2400
2401   if (G_UNLIKELY (GST_PAD_PARENT (pad) == NULL))
2402     GST_FIXME ("Saw a pad not belonging to any object");
2403
2404   return TRUE;
2405 }