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