pad-monitor: add two useful macros for readability
[platform/upstream/gstreamer.git] / validate / gst / validate / gst-validate-pad-monitor.c
1 /* GStreamer
2  *
3  * Copyright (C) 2013 Collabora Ltd.
4  *  Author: Thiago Sousa Santos <thiago.sousa.santos@collabora.com>
5  *
6  * gst-validate-pad-monitor.c - Validate PadMonitor class
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27
28 #include "gst-validate-internal.h"
29 #include "gst-validate-pad-monitor.h"
30 #include "gst-validate-element-monitor.h"
31 #include "gst-validate-reporter.h"
32 #include <string.h>
33 #include <stdarg.h>
34
35 /**
36  * SECTION:gst-validate-pad-monitor
37  * @short_description: Class that wraps a #GstPad for Validate checks
38  *
39  * TODO
40  */
41
42 #define gst_validate_pad_monitor_parent_class parent_class
43 G_DEFINE_TYPE (GstValidatePadMonitor, gst_validate_pad_monitor,
44     GST_TYPE_VALIDATE_MONITOR);
45
46 #define PENDING_FIELDS "pending-fields"
47
48 #define PAD_PARENT_IS_DEMUXER(m) \
49     (GST_VALIDATE_MONITOR_GET_PARENT(m) ? \
50         GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DEMUXER ( \
51             GST_VALIDATE_MONITOR_GET_PARENT(m)) : \
52         FALSE)
53
54 #define PAD_PARENT_IS_DECODER(m) \
55     (GST_VALIDATE_MONITOR_GET_PARENT(m) ? \
56         GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DECODER ( \
57             GST_VALIDATE_MONITOR_GET_PARENT(m)) : \
58         FALSE)
59
60 /*
61  * Locking the parent should always be done before locking the
62  * pad-monitor to prevent deadlocks in case another monitor from
63  * another pad on the same element starts an operation that also
64  * requires locking itself and some other monitors from internally
65  * linked pads.
66  *
67  * An example:
68  * An element has a sink and a src pad. Some test starts running at sinkpad
69  * and it locks the parent, and then it locks itself. In case it needs to get
70  * some information from the srcpad, it is able to lock the srcpad and get it
71  * because the srcpad should never lock itself before locking the parent (which
72  * it won't be able as sinkpad already locked it).
73  *
74  * As a side one, it is possible that srcpad locks itself without locking the
75  * parent in case it wants to do a check that won't need to use other internally
76  * linked pads (sinkpad). But in this case it might lock and unlock freely without
77  * causing deadlocks.
78  */
79 #define GST_VALIDATE_PAD_MONITOR_PARENT_LOCK(m)                  \
80 G_STMT_START {                                             \
81   if (G_LIKELY (GST_VALIDATE_MONITOR_GET_PARENT (m))) {          \
82     GST_VALIDATE_MONITOR_LOCK (GST_VALIDATE_MONITOR_GET_PARENT (m));   \
83   } else {                                                 \
84     GST_WARNING_OBJECT (m, "No parent found, can't lock"); \
85   }                                                        \
86 } G_STMT_END
87
88 #define GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK(m)                  \
89 G_STMT_START {                                               \
90   if (G_LIKELY (GST_VALIDATE_MONITOR_GET_PARENT (m))) {            \
91     GST_VALIDATE_MONITOR_UNLOCK (GST_VALIDATE_MONITOR_GET_PARENT (m));   \
92   } else {                                                   \
93     GST_WARNING_OBJECT (m, "No parent found, can't unlock"); \
94   }                                                          \
95 } G_STMT_END
96
97 typedef struct
98 {
99   GstClockTime timestamp;
100   GstEvent *event;
101 } SerializedEventData;
102
103 static void
104 _serialized_event_data_free (SerializedEventData * serialized_event)
105 {
106   gst_event_unref (serialized_event->event);
107   g_slice_free (SerializedEventData, serialized_event);
108 }
109
110 static gboolean gst_validate_pad_monitor_do_setup (GstValidateMonitor *
111     monitor);
112 static GstElement *gst_validate_pad_monitor_get_element (GstValidateMonitor *
113     monitor);
114 static void
115 gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor,
116     GstCaps * caps);
117 static void gst_validate_pad_monitor_setcaps_post (GstValidatePadMonitor *
118     pad_monitor, GstCaps * caps, gboolean ret);
119
120 #define PAD_IS_IN_PUSH_MODE(p) ((p)->mode == GST_PAD_MODE_PUSH)
121
122 static gboolean
123 _structure_is_raw_video (GstStructure * structure)
124 {
125   return gst_structure_has_name (structure, "video/x-raw");
126 }
127
128 static gboolean
129 _structure_is_raw_audio (GstStructure * structure)
130 {
131   return gst_structure_has_name (structure, "audio/x-raw");
132 }
133
134 static void
135 _check_field_type (GstValidatePadMonitor * monitor, GstStructure * structure,
136     const gchar * field, ...)
137 {
138   va_list var_args;
139   GType type;
140   gchar *joined_types = NULL;
141   const gchar *rejected_types[5];
142   gint rejected_types_index = 0;
143
144   if (!gst_structure_has_field (structure, field)) {
145     GST_VALIDATE_REPORT (monitor, CAPS_IS_MISSING_FIELD,
146         "Field '%s' is missing from structure: %" GST_PTR_FORMAT, field,
147         structure);
148     return;
149   }
150
151   memset (rejected_types, 0, sizeof (rejected_types));
152   va_start (var_args, field);
153   while ((type = va_arg (var_args, GType)) != 0) {
154     if (gst_structure_has_field_typed (structure, field, type)) {
155       va_end (var_args);
156       return;
157     }
158     rejected_types[rejected_types_index++] = g_type_name (type);
159   }
160   va_end (var_args);
161
162   joined_types = g_strjoinv (" / ", (gchar **) rejected_types);
163   GST_VALIDATE_REPORT (monitor, CAPS_FIELD_HAS_BAD_TYPE,
164       "Field '%s' has wrong type %s in structure '%" GST_PTR_FORMAT
165       "'. Expected: %s", field,
166       g_type_name (gst_structure_get_field_type (structure, field)), structure,
167       joined_types);
168   g_free (joined_types);
169 }
170
171 static void
172 gst_validate_pad_monitor_check_raw_video_caps_complete (GstValidatePadMonitor *
173     monitor, GstStructure * structure)
174 {
175   _check_field_type (monitor, structure, "width", G_TYPE_INT,
176       GST_TYPE_INT_RANGE, 0);
177   _check_field_type (monitor, structure, "height", G_TYPE_INT,
178       GST_TYPE_INT_RANGE, 0);
179   _check_field_type (monitor, structure, "framerate", GST_TYPE_FRACTION,
180       GST_TYPE_FRACTION_RANGE, 0);
181   _check_field_type (monitor, structure, "pixel-aspect-ratio",
182       GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE, 0);
183   _check_field_type (monitor, structure, "format", G_TYPE_STRING,
184       GST_TYPE_LIST);
185 }
186
187 static void
188 gst_validate_pad_monitor_check_raw_audio_caps_complete (GstValidatePadMonitor *
189     monitor, GstStructure * structure)
190 {
191   _check_field_type (monitor, structure, "format", G_TYPE_STRING, GST_TYPE_LIST,
192       0);
193   _check_field_type (monitor, structure, "layout", G_TYPE_STRING, GST_TYPE_LIST,
194       0);
195   _check_field_type (monitor, structure, "rate", G_TYPE_INT, GST_TYPE_LIST,
196       GST_TYPE_INT_RANGE, 0);
197   _check_field_type (monitor, structure, "channels", G_TYPE_INT, GST_TYPE_LIST,
198       GST_TYPE_INT_RANGE, 0);
199   _check_field_type (monitor, structure, "channel-mask", GST_TYPE_BITMASK,
200       GST_TYPE_LIST, 0);
201 }
202
203 static void
204 gst_validate_pad_monitor_check_caps_complete (GstValidatePadMonitor * monitor,
205     GstCaps * caps)
206 {
207   GstStructure *structure;
208   gint i;
209
210   GST_DEBUG_OBJECT (monitor, "Checking caps %" GST_PTR_FORMAT, caps);
211
212   for (i = 0; i < gst_caps_get_size (caps); i++) {
213     structure = gst_caps_get_structure (caps, i);
214
215     if (_structure_is_raw_video (structure)) {
216       gst_validate_pad_monitor_check_raw_video_caps_complete (monitor,
217           structure);
218
219     } else if (_structure_is_raw_audio (structure)) {
220       gst_validate_pad_monitor_check_raw_audio_caps_complete (monitor,
221           structure);
222     }
223   }
224 }
225
226 static GstCaps *
227 gst_validate_pad_monitor_get_othercaps (GstValidatePadMonitor * monitor)
228 {
229   GstCaps *caps = gst_caps_new_empty ();
230   GstIterator *iter;
231   gboolean done;
232   GstPad *otherpad;
233   GstCaps *peercaps;
234
235   iter =
236       gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
237       (monitor));
238   done = FALSE;
239   while (!done) {
240     GValue value = { 0, };
241     switch (gst_iterator_next (iter, &value)) {
242       case GST_ITERATOR_OK:
243         otherpad = g_value_get_object (&value);
244
245         /* TODO What would be the correct caps operation to merge the caps in
246          * case one sink is internally linked to multiple srcs? */
247         peercaps = gst_pad_peer_query_caps (otherpad, NULL);
248         if (peercaps)
249           caps = gst_caps_merge (caps, peercaps);
250
251         g_value_reset (&value);
252         break;
253       case GST_ITERATOR_RESYNC:
254         gst_iterator_resync (iter);
255         gst_caps_replace (&caps, gst_caps_new_empty ());
256         break;
257       case GST_ITERATOR_ERROR:
258         GST_WARNING_OBJECT (monitor, "Internal links pad iteration error");
259         done = TRUE;
260         break;
261       case GST_ITERATOR_DONE:
262         done = TRUE;
263         break;
264     }
265   }
266   gst_iterator_free (iter);
267
268   GST_DEBUG_OBJECT (monitor, "Otherpad caps: %" GST_PTR_FORMAT, caps);
269
270   return caps;
271 }
272
273 static gboolean
274 _structure_is_video (GstStructure * structure)
275 {
276   const gchar *name = gst_structure_get_name (structure);
277
278   return g_strstr_len (name, 6, "video/")
279       && strcmp (name, "video/quicktime") != 0;
280 }
281
282 static gboolean
283 _structure_is_audio (GstStructure * structure)
284 {
285   const gchar *name = gst_structure_get_name (structure);
286
287   return g_strstr_len (name, 6, "audio/") != NULL;
288 }
289
290 static gboolean
291 gst_validate_pad_monitor_pad_should_proxy_othercaps (GstValidatePadMonitor *
292     monitor)
293 {
294   GstValidateMonitor *parent = GST_VALIDATE_MONITOR_GET_PARENT (monitor);
295
296   if (!parent)
297     return FALSE;
298
299   /* We only know how to handle othercaps checks for codecs so far */
300   return GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DECODER (parent) ||
301       GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_ENCODER (parent);
302 }
303
304
305 /* Check if the field @f from @s2 (if present) is represented in @s1
306  * Represented here means either equal or @s1's value is in a list/range
307  * from @s2
308  */
309 static gboolean
310 _structures_field_is_contained (GstStructure * s1, GstStructure * s2,
311     const gchar * f)
312 {
313   const GValue *v1;
314   const GValue *v2;
315
316   v2 = gst_structure_get_value (s2, f);
317   if (!v2)
318     return TRUE;                /* nothing to compare to */
319
320   v1 = gst_structure_get_value (s1, f);
321   if (!v1)
322     return FALSE;
323
324   if (gst_value_compare (v1, v2) == GST_VALUE_EQUAL)
325     return TRUE;
326
327   if (GST_VALUE_HOLDS_LIST (v2)) {
328     gint i;
329     for (i = 0; i < gst_value_list_get_size (v2); i++) {
330       const GValue *v2_subvalue = gst_value_list_get_value (v2, i);
331       if (gst_value_compare (v1, v2_subvalue) == GST_VALUE_EQUAL)
332         return TRUE;
333     }
334   }
335
336   if (GST_VALUE_HOLDS_ARRAY (v2)) {
337     gint i;
338     for (i = 0; i < gst_value_array_get_size (v2); i++) {
339       const GValue *v2_subvalue = gst_value_array_get_value (v2, i);
340       if (gst_value_compare (v1, v2_subvalue) == GST_VALUE_EQUAL)
341         return TRUE;
342     }
343   }
344
345   if (GST_VALUE_HOLDS_INT_RANGE (v2)) {
346     gint min, max;
347
348     min = gst_value_get_int_range_min (v2);
349     max = gst_value_get_int_range_max (v2);
350
351     if (G_VALUE_HOLDS_INT (v1)) {
352       gint v = g_value_get_int (v1);
353
354       return v >= min && v <= max;
355     } else {
356       /* TODO compare int ranges with int ranges
357        * or with lists if useful */
358     }
359   }
360
361   if (GST_VALUE_HOLDS_FRACTION_RANGE (v2)) {
362     const GValue *min, *max;
363
364     min = gst_value_get_fraction_range_min (v2);
365     max = gst_value_get_fraction_range_max (v2);
366
367     if (GST_VALUE_HOLDS_FRACTION (v1)) {
368       gint v_min = gst_value_compare (v1, min);
369       gint v_max = gst_value_compare (v1, max);
370
371       return (v_min == GST_VALUE_EQUAL || v_min == GST_VALUE_GREATER_THAN) &&
372           (v_max == GST_VALUE_EQUAL || v_max == GST_VALUE_LESS_THAN);
373     } else {
374       /* TODO compare fraction ranges with fraction ranges
375        * or with lists if useful */
376     }
377   }
378
379   return FALSE;
380 }
381
382 static void
383 gst_validate_pad_monitor_check_caps_fields_proxied (GstValidatePadMonitor *
384     monitor, GstCaps * caps)
385 {
386   GstStructure *structure;
387   GstStructure *otherstructure;
388   GstCaps *othercaps;
389   gint i, j;
390
391   if (!gst_validate_pad_monitor_pad_should_proxy_othercaps (monitor))
392     return;
393
394   othercaps = gst_validate_pad_monitor_get_othercaps (monitor);
395
396   for (i = 0; i < gst_caps_get_size (othercaps); i++) {
397     gboolean found = FALSE;
398     gboolean type_match = FALSE;
399
400     otherstructure = gst_caps_get_structure (othercaps, i);
401
402     /* look for a proxied version of 'otherstructure' */
403     if (_structure_is_video (otherstructure)) {
404       for (j = 0; j < gst_caps_get_size (caps); j++) {
405         structure = gst_caps_get_structure (caps, j);
406         if (_structure_is_video (structure)) {
407           type_match = TRUE;
408           if (_structures_field_is_contained (structure, otherstructure,
409                   "width")
410               && _structures_field_is_contained (structure, otherstructure,
411                   "height")
412               && _structures_field_is_contained (structure, otherstructure,
413                   "framerate")
414               && _structures_field_is_contained (structure, otherstructure,
415                   "pixel-aspect-ratio")) {
416             found = TRUE;
417             break;
418           }
419         }
420       }
421     } else if (_structure_is_audio (otherstructure)) {
422       for (j = 0; j < gst_caps_get_size (caps); j++) {
423         structure = gst_caps_get_structure (caps, j);
424         if (_structure_is_audio (structure)) {
425           type_match = TRUE;
426           if (_structures_field_is_contained (structure, otherstructure, "rate")
427               && _structures_field_is_contained (structure, otherstructure,
428                   "channels")) {
429             found = TRUE;
430             break;
431           }
432         }
433       }
434     }
435
436     if (type_match && !found) {
437       GST_VALIDATE_REPORT (monitor, GET_CAPS_NOT_PROXYING_FIELDS,
438           "Peer pad structure '%" GST_PTR_FORMAT "' has no similar version "
439           "on pad's caps '%" GST_PTR_FORMAT "'", otherstructure, caps);
440     }
441   }
442 }
443
444 static void
445 gst_validate_pad_monitor_check_late_serialized_events (GstValidatePadMonitor *
446     monitor, GstClockTime ts)
447 {
448   gint i;
449   if (!GST_CLOCK_TIME_IS_VALID (ts))
450     return;
451
452   for (i = 0; i < monitor->serialized_events->len; i++) {
453     SerializedEventData *data =
454         g_ptr_array_index (monitor->serialized_events, i);
455     if (data->timestamp < ts) {
456       GST_VALIDATE_REPORT (monitor, SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME,
457           "Serialized event %" GST_PTR_FORMAT " wasn't pushed before expected "
458           "timestamp %" GST_TIME_FORMAT " on pad %s:%s", data->event,
459           GST_TIME_ARGS (data->timestamp),
460           GST_DEBUG_PAD_NAME (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor)));
461     } else {
462       /* events should be ordered by ts */
463       break;
464     }
465   }
466
467   if (i)
468     g_ptr_array_remove_range (monitor->serialized_events, 0, i);
469 }
470
471 static void
472 gst_validate_pad_monitor_dispose (GObject * object)
473 {
474   GstValidatePadMonitor *monitor = GST_VALIDATE_PAD_MONITOR_CAST (object);
475   GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor);
476
477   if (pad) {
478     if (monitor->pad_probe_id)
479       gst_pad_remove_probe (pad, monitor->pad_probe_id);
480   }
481
482   if (monitor->expected_segment)
483     gst_event_unref (monitor->expected_segment);
484
485   gst_structure_free (monitor->pending_setcaps_fields);
486   g_ptr_array_unref (monitor->serialized_events);
487
488   G_OBJECT_CLASS (parent_class)->dispose (object);
489 }
490
491 static void
492 gst_validate_pad_monitor_class_init (GstValidatePadMonitorClass * klass)
493 {
494   GObjectClass *gobject_class;
495   GstValidateMonitorClass *monitor_klass;
496
497   gobject_class = G_OBJECT_CLASS (klass);
498   monitor_klass = GST_VALIDATE_MONITOR_CLASS (klass);
499
500   gobject_class->dispose = gst_validate_pad_monitor_dispose;
501
502   monitor_klass->setup = gst_validate_pad_monitor_do_setup;
503   monitor_klass->get_element = gst_validate_pad_monitor_get_element;
504 }
505
506 static void
507 gst_validate_pad_monitor_init (GstValidatePadMonitor * pad_monitor)
508 {
509   pad_monitor->pending_setcaps_fields =
510       gst_structure_new_empty (PENDING_FIELDS);
511   pad_monitor->serialized_events =
512       g_ptr_array_new_with_free_func ((GDestroyNotify)
513       _serialized_event_data_free);
514   gst_segment_init (&pad_monitor->segment, GST_FORMAT_BYTES);
515   pad_monitor->first_buffer = TRUE;
516
517   pad_monitor->timestamp_range_start = GST_CLOCK_TIME_NONE;
518   pad_monitor->timestamp_range_end = GST_CLOCK_TIME_NONE;
519 }
520
521 /**
522  * gst_validate_pad_monitor_new:
523  * @pad: (transfer-none): a #GstPad to run Validate on
524  */
525 GstValidatePadMonitor *
526 gst_validate_pad_monitor_new (GstPad * pad, GstValidateRunner * runner,
527     GstValidateElementMonitor * parent)
528 {
529   GstValidatePadMonitor *monitor = g_object_new (GST_TYPE_VALIDATE_PAD_MONITOR,
530       "object", pad, "qa-runner", runner, "qa-parent",
531       parent, NULL);
532
533   if (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor) == NULL) {
534     g_object_unref (monitor);
535     return NULL;
536   }
537   return monitor;
538 }
539
540 static GstElement *
541 gst_validate_pad_monitor_get_element (GstValidateMonitor * monitor)
542 {
543   GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor);
544
545   return GST_PAD_PARENT (pad);
546 }
547
548 static void
549 gst_validate_pad_monitor_event_overrides (GstValidatePadMonitor * pad_monitor,
550     GstEvent * event)
551 {
552   GList *iter;
553
554   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
555   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
556       iter = g_list_next (iter)) {
557     GstValidateOverride *override = iter->data;
558
559     gst_validate_override_event_handler (override,
560         GST_VALIDATE_MONITOR_CAST (pad_monitor), event);
561   }
562   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
563 }
564
565 static void
566 gst_validate_pad_monitor_buffer_overrides (GstValidatePadMonitor * pad_monitor,
567     GstBuffer * buffer)
568 {
569   GList *iter;
570
571   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
572   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
573       iter = g_list_next (iter)) {
574     GstValidateOverride *override = iter->data;
575
576     gst_validate_override_buffer_handler (override,
577         GST_VALIDATE_MONITOR_CAST (pad_monitor), buffer);
578   }
579   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
580 }
581
582 static void
583 gst_validate_pad_monitor_buffer_probe_overrides (GstValidatePadMonitor *
584     pad_monitor, GstBuffer * buffer)
585 {
586   GList *iter;
587
588   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
589   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
590       iter = g_list_next (iter)) {
591     GstValidateOverride *override = iter->data;
592
593     gst_validate_override_buffer_probe_handler (override,
594         GST_VALIDATE_MONITOR_CAST (pad_monitor), buffer);
595   }
596   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
597 }
598
599 static void
600 gst_validate_pad_monitor_query_overrides (GstValidatePadMonitor * pad_monitor,
601     GstQuery * query)
602 {
603   GList *iter;
604
605   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
606   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
607       iter = g_list_next (iter)) {
608     GstValidateOverride *override = iter->data;
609
610     gst_validate_override_query_handler (override,
611         GST_VALIDATE_MONITOR_CAST (pad_monitor), query);
612   }
613   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
614 }
615
616 static void
617 gst_validate_pad_monitor_setcaps_overrides (GstValidatePadMonitor * pad_monitor,
618     GstCaps * caps)
619 {
620   GList *iter;
621
622   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
623   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
624       iter = g_list_next (iter)) {
625     GstValidateOverride *override = iter->data;
626
627     gst_validate_override_setcaps_handler (override,
628         GST_VALIDATE_MONITOR_CAST (pad_monitor), caps);
629   }
630   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
631 }
632
633 static gboolean
634 gst_validate_pad_monitor_timestamp_is_in_received_range (GstValidatePadMonitor *
635     monitor, GstClockTime ts)
636 {
637   GST_DEBUG_OBJECT (monitor, "Checking if timestamp %" GST_TIME_FORMAT
638       " is in range: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT " for pad "
639       "%s:%s", GST_TIME_ARGS (ts),
640       GST_TIME_ARGS (monitor->timestamp_range_start),
641       GST_TIME_ARGS (monitor->timestamp_range_end),
642       GST_DEBUG_PAD_NAME (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor)));
643   return !GST_CLOCK_TIME_IS_VALID (monitor->timestamp_range_start) ||
644       !GST_CLOCK_TIME_IS_VALID (monitor->timestamp_range_end) ||
645       (monitor->timestamp_range_start <= ts
646       && ts <= monitor->timestamp_range_end);
647 }
648
649 /* Iterates over internal links (sinkpads) to check that this buffer has
650  * a timestamp that is in the range of the lastly received buffers */
651 static void
652     gst_validate_pad_monitor_check_buffer_timestamp_in_received_range
653     (GstValidatePadMonitor * monitor, GstBuffer * buffer)
654 {
655   GstClockTime ts;
656   GstClockTime ts_end;
657   GstIterator *iter;
658   gboolean has_one = FALSE;
659   gboolean found = FALSE;
660   gboolean done;
661   GstPad *otherpad;
662   GstValidatePadMonitor *othermonitor;
663
664   if (!GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))
665       || !GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) {
666     GST_DEBUG_OBJECT (monitor,
667         "Can't check buffer timestamps range as "
668         "buffer has no valid timestamp/duration");
669     return;
670   }
671   ts = GST_BUFFER_TIMESTAMP (buffer);
672   ts_end = ts + GST_BUFFER_DURATION (buffer);
673
674   iter =
675       gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
676       (monitor));
677   done = FALSE;
678   while (!done) {
679     GValue value = { 0, };
680     switch (gst_iterator_next (iter, &value)) {
681       case GST_ITERATOR_OK:
682         otherpad = g_value_get_object (&value);
683         GST_DEBUG_OBJECT (monitor, "Checking pad %s:%s input timestamps",
684             GST_DEBUG_PAD_NAME (otherpad));
685         othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor");
686         GST_VALIDATE_MONITOR_LOCK (othermonitor);
687         if (gst_validate_pad_monitor_timestamp_is_in_received_range
688             (othermonitor, ts)
689             &&
690             gst_validate_pad_monitor_timestamp_is_in_received_range
691             (othermonitor, ts_end)) {
692           done = TRUE;
693           found = TRUE;
694         }
695         GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
696         g_value_reset (&value);
697         has_one = TRUE;
698         break;
699       case GST_ITERATOR_RESYNC:
700         gst_iterator_resync (iter);
701         has_one = FALSE;
702         found = FALSE;
703         break;
704       case GST_ITERATOR_ERROR:
705         GST_WARNING_OBJECT (monitor, "Internal links pad iteration error");
706         done = TRUE;
707         break;
708       case GST_ITERATOR_DONE:
709         done = TRUE;
710         break;
711     }
712   }
713   gst_iterator_free (iter);
714
715   if (!has_one) {
716     GST_DEBUG_OBJECT (monitor, "Skipping timestamp in range check as no "
717         "internal linked pad was found");
718     return;
719   }
720   if (!found) {
721     GST_VALIDATE_REPORT (monitor, BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE,
722         "Timestamp %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT
723         " is out of range of received input", GST_TIME_ARGS (ts),
724         GST_TIME_ARGS (ts_end));
725   }
726 }
727
728 static void
729 gst_validate_pad_monitor_check_first_buffer (GstValidatePadMonitor *
730     pad_monitor, GstBuffer * buffer)
731 {
732   if (G_UNLIKELY (pad_monitor->first_buffer)) {
733     pad_monitor->first_buffer = FALSE;
734
735     if (!pad_monitor->has_segment
736         && PAD_IS_IN_PUSH_MODE (GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor)))
737     {
738       GST_VALIDATE_REPORT (pad_monitor, BUFFER_BEFORE_SEGMENT,
739           "Received buffer before Segment event");
740     }
741     if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) {
742       gint64 running_time = gst_segment_to_running_time (&pad_monitor->segment,
743           pad_monitor->segment.format, GST_BUFFER_TIMESTAMP (buffer));
744       if (running_time != 0) {
745         GST_VALIDATE_REPORT (pad_monitor, FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO,
746             "First buffer running time is not 0, it is: %" GST_TIME_FORMAT,
747             GST_TIME_ARGS (running_time));
748       }
749     }
750   }
751 }
752
753 static void
754 gst_validate_pad_monitor_update_buffer_data (GstValidatePadMonitor *
755     pad_monitor, GstBuffer * buffer)
756 {
757   pad_monitor->current_timestamp = GST_BUFFER_TIMESTAMP (buffer);
758   pad_monitor->current_duration = GST_BUFFER_DURATION (buffer);
759   if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) {
760     if (GST_CLOCK_TIME_IS_VALID (pad_monitor->timestamp_range_start)) {
761       pad_monitor->timestamp_range_start =
762           MIN (pad_monitor->timestamp_range_start,
763           GST_BUFFER_TIMESTAMP (buffer));
764     } else {
765       pad_monitor->timestamp_range_start = GST_BUFFER_TIMESTAMP (buffer);
766     }
767
768     if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) {
769       GstClockTime endts =
770           GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer);
771       if (GST_CLOCK_TIME_IS_VALID (pad_monitor->timestamp_range_end)) {
772         pad_monitor->timestamp_range_end =
773             MAX (pad_monitor->timestamp_range_end, endts);
774       } else {
775         pad_monitor->timestamp_range_end = endts;
776       }
777     }
778   }
779   GST_DEBUG_OBJECT (pad_monitor, "Current stored range: %" GST_TIME_FORMAT
780       " - %" GST_TIME_FORMAT,
781       GST_TIME_ARGS (pad_monitor->timestamp_range_start),
782       GST_TIME_ARGS (pad_monitor->timestamp_range_end));
783 }
784
785 static GstFlowReturn
786 _combine_flows (GstFlowReturn ret1, GstFlowReturn ret2)
787 {
788   if (ret1 == ret2)
789     return ret1;
790   if (ret1 <= GST_FLOW_NOT_NEGOTIATED)
791     return ret1;
792   if (ret2 <= GST_FLOW_NOT_NEGOTIATED)
793     return ret2;
794   if (ret1 == GST_FLOW_FLUSHING || ret2 == GST_FLOW_FLUSHING)
795     return GST_FLOW_FLUSHING;
796   if (ret1 == GST_FLOW_OK || ret2 == GST_FLOW_OK)
797     return GST_FLOW_OK;
798   return ret2;
799 }
800
801 static void
802 gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor *
803     monitor, GstFlowReturn ret)
804 {
805   GstIterator *iter;
806   gboolean done;
807   GstPad *otherpad;
808   GstPad *peerpad;
809   GstValidatePadMonitor *othermonitor;
810   GstFlowReturn aggregated = GST_FLOW_NOT_LINKED;
811   gboolean found_a_pad = FALSE;
812
813   iter =
814       gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
815       (monitor));
816   done = FALSE;
817   while (!done) {
818     GValue value = { 0, };
819     switch (gst_iterator_next (iter, &value)) {
820       case GST_ITERATOR_OK:
821         otherpad = g_value_get_object (&value);
822         peerpad = gst_pad_get_peer (otherpad);
823         if (peerpad) {
824           othermonitor = g_object_get_data ((GObject *) peerpad, "qa-monitor");
825           if (othermonitor) {
826             found_a_pad = TRUE;
827             GST_VALIDATE_MONITOR_LOCK (othermonitor);
828             aggregated =
829                 _combine_flows (aggregated, othermonitor->last_flow_return);
830             GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
831           }
832
833           gst_object_unref (peerpad);
834         }
835         g_value_reset (&value);
836         break;
837       case GST_ITERATOR_RESYNC:
838         gst_iterator_resync (iter);
839         break;
840       case GST_ITERATOR_ERROR:
841         GST_WARNING_OBJECT (monitor, "Internal links pad iteration error");
842         done = TRUE;
843         break;
844       case GST_ITERATOR_DONE:
845         done = TRUE;
846         break;
847     }
848   }
849   gst_iterator_free (iter);
850   if (!found_a_pad) {
851     /* no peer pad found, nothing to do */
852     return;
853   }
854   if (aggregated == GST_FLOW_OK || aggregated == GST_FLOW_EOS) {
855     /* those are acceptable situations */
856
857     if (monitor->is_eos && ret == GST_FLOW_EOS) {
858       /* this element received eos and returned eos */
859       return;
860     }
861
862     if (PAD_PARENT_IS_DEMUXER (monitor) && ret == GST_FLOW_EOS) {
863       /* a demuxer can return EOS when the samples end */
864       return;
865     }
866   }
867
868   if (aggregated != ret) {
869     GST_VALIDATE_REPORT (monitor, WRONG_FLOW_RETURN,
870         "Wrong combined flow return %s(%d). Expected: %s(%d)",
871         gst_flow_get_name (ret), ret, gst_flow_get_name (aggregated),
872         aggregated);
873   }
874 }
875
876 static void
877     gst_validate_pad_monitor_otherpad_add_pending_serialized_event
878     (GstValidatePadMonitor * monitor, GstEvent * event, GstClockTime last_ts)
879 {
880   GstIterator *iter;
881   gboolean done;
882   GstPad *otherpad;
883   GstValidatePadMonitor *othermonitor;
884
885   if (!GST_EVENT_IS_SERIALIZED (event))
886     return;
887
888   iter =
889       gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
890       (monitor));
891   if (iter == NULL) {
892     /* inputselector will return NULL if the sinkpad is not the active one .... */
893     GST_FIXME_OBJECT (GST_VALIDATE_PAD_MONITOR_GET_PAD
894         (monitor), "No iterator");
895     return;
896   }
897   done = FALSE;
898   while (!done) {
899     GValue value = { 0, };
900     switch (gst_iterator_next (iter, &value)) {
901       case GST_ITERATOR_OK:
902         otherpad = g_value_get_object (&value);
903         othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor");
904         if (othermonitor) {
905           SerializedEventData *data = g_slice_new0 (SerializedEventData);
906           data->timestamp = last_ts;
907           data->event = gst_event_ref (event);
908           GST_VALIDATE_MONITOR_LOCK (othermonitor);
909           g_ptr_array_add (othermonitor->serialized_events, data);
910           GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
911         }
912         g_value_reset (&value);
913         break;
914       case GST_ITERATOR_RESYNC:
915         gst_iterator_resync (iter);
916         break;
917       case GST_ITERATOR_ERROR:
918         GST_WARNING_OBJECT (monitor, "Internal links pad iteration error");
919         done = TRUE;
920         break;
921       case GST_ITERATOR_DONE:
922         done = TRUE;
923         break;
924     }
925   }
926   gst_iterator_free (iter);
927 }
928
929 static void
930 gst_validate_pad_monitor_otherpad_add_pending_field (GstValidatePadMonitor *
931     monitor, GstStructure * structure, const gchar * field)
932 {
933   GstIterator *iter;
934   gboolean done;
935   GstPad *otherpad;
936   GstValidatePadMonitor *othermonitor;
937   const GValue *v;
938
939   v = gst_structure_get_value (structure, field);
940   if (v == NULL) {
941     GST_DEBUG_OBJECT (monitor, "Not adding pending field %s as it isn't "
942         "present on structure %" GST_PTR_FORMAT, field, structure);
943     return;
944   }
945
946   iter =
947       gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
948       (monitor));
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         othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor");
956         if (othermonitor) {
957           GST_VALIDATE_MONITOR_LOCK (othermonitor);
958           g_assert (othermonitor->pending_setcaps_fields != NULL);
959           gst_structure_set_value (othermonitor->pending_setcaps_fields,
960               field, v);
961           GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
962         }
963         g_value_reset (&value);
964         break;
965       case GST_ITERATOR_RESYNC:
966         gst_iterator_resync (iter);
967         break;
968       case GST_ITERATOR_ERROR:
969         GST_WARNING_OBJECT (monitor, "Internal links pad iteration error");
970         done = TRUE;
971         break;
972       case GST_ITERATOR_DONE:
973         done = TRUE;
974         break;
975     }
976   }
977   gst_iterator_free (iter);
978 }
979
980 static void
981 gst_validate_pad_monitor_otherpad_clear_pending_fields (GstValidatePadMonitor *
982     monitor)
983 {
984   GstIterator *iter;
985   gboolean done;
986   GstPad *otherpad;
987   GstValidatePadMonitor *othermonitor;
988
989   iter =
990       gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
991       (monitor));
992   done = FALSE;
993   while (!done) {
994     GValue value = { 0, };
995     switch (gst_iterator_next (iter, &value)) {
996       case GST_ITERATOR_OK:
997         otherpad = g_value_get_object (&value);
998         othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor");
999         if (othermonitor) {
1000           GST_VALIDATE_MONITOR_LOCK (othermonitor);
1001           g_assert (othermonitor->pending_setcaps_fields != NULL);
1002           gst_structure_free (othermonitor->pending_setcaps_fields);
1003           othermonitor->pending_setcaps_fields =
1004               gst_structure_new_empty (PENDING_FIELDS);
1005           GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1006         }
1007         g_value_reset (&value);
1008         break;
1009       case GST_ITERATOR_RESYNC:
1010         gst_iterator_resync (iter);
1011         break;
1012       case GST_ITERATOR_ERROR:
1013         GST_WARNING_OBJECT (monitor, "Internal links pad iteration error");
1014         done = TRUE;
1015         break;
1016       case GST_ITERATOR_DONE:
1017         done = TRUE;
1018         break;
1019     }
1020   }
1021   gst_iterator_free (iter);
1022 }
1023
1024 static void
1025 gst_validate_pad_monitor_add_expected_newsegment (GstValidatePadMonitor *
1026     monitor, GstEvent * event)
1027 {
1028   GstIterator *iter;
1029   gboolean done;
1030   GstPad *otherpad;
1031   GstValidatePadMonitor *othermonitor;
1032
1033   iter =
1034       gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
1035       (monitor));
1036   done = FALSE;
1037   while (!done) {
1038     GValue value = { 0, };
1039     switch (gst_iterator_next (iter, &value)) {
1040       case GST_ITERATOR_OK:
1041         otherpad = g_value_get_object (&value);
1042         othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor");
1043         GST_VALIDATE_MONITOR_LOCK (othermonitor);
1044         if (othermonitor->expected_segment) {
1045           GST_VALIDATE_REPORT (othermonitor, EVENT_NEWSEGMENT_NOT_PUSHED, "");
1046           gst_event_unref (othermonitor->expected_segment);
1047         }
1048         othermonitor->expected_segment = gst_event_ref (event);
1049         GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1050         g_value_reset (&value);
1051         break;
1052       case GST_ITERATOR_RESYNC:
1053         gst_iterator_resync (iter);
1054         break;
1055       case GST_ITERATOR_ERROR:
1056         GST_WARNING_OBJECT (monitor, "Internal links pad iteration error");
1057         done = TRUE;
1058         break;
1059       case GST_ITERATOR_DONE:
1060         done = TRUE;
1061         break;
1062     }
1063   }
1064   gst_iterator_free (iter);
1065 }
1066
1067 static void
1068 gst_validate_pad_monitor_flush (GstValidatePadMonitor * pad_monitor)
1069 {
1070   pad_monitor->current_timestamp = GST_CLOCK_TIME_NONE;
1071   pad_monitor->current_duration = GST_CLOCK_TIME_NONE;
1072   pad_monitor->timestamp_range_start = GST_CLOCK_TIME_NONE;
1073   pad_monitor->timestamp_range_end = GST_CLOCK_TIME_NONE;
1074   pad_monitor->has_segment = FALSE;
1075   pad_monitor->is_eos = FALSE;
1076   gst_caps_replace (&pad_monitor->last_caps, NULL);
1077 }
1078
1079 /* common checks for both sink and src event functions */
1080 static void
1081 gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor *
1082     pad_monitor, GstEvent * event)
1083 {
1084   guint32 seqnum = gst_event_get_seqnum (event);
1085
1086   switch (GST_EVENT_TYPE (event)) {
1087     case GST_EVENT_FLUSH_START:
1088     {
1089       if (pad_monitor->pending_flush_start_seqnum) {
1090         if (seqnum == pad_monitor->pending_flush_start_seqnum) {
1091           pad_monitor->pending_flush_start_seqnum = 0;
1092         } else {
1093           GST_VALIDATE_REPORT (pad_monitor, EVENT_HAS_WRONG_SEQNUM,
1094               "The expected flush-start seqnum should be the same as the "
1095               "one from the event that caused it (probably a seek). Got: %u."
1096               " Expected: %u", seqnum, pad_monitor->pending_flush_start_seqnum);
1097         }
1098       }
1099
1100       if (pad_monitor->pending_flush_stop) {
1101         GST_VALIDATE_REPORT (pad_monitor, EVENT_FLUSH_START_UNEXPECTED,
1102             "Received flush-start from " " when flush-stop was expected");
1103       }
1104       pad_monitor->pending_flush_stop = TRUE;
1105     }
1106       break;
1107     case GST_EVENT_FLUSH_STOP:
1108     {
1109       if (pad_monitor->pending_flush_stop_seqnum) {
1110         if (seqnum == pad_monitor->pending_flush_stop_seqnum) {
1111           pad_monitor->pending_flush_stop_seqnum = 0;
1112         } else {
1113           GST_VALIDATE_REPORT (pad_monitor, EVENT_HAS_WRONG_SEQNUM,
1114               "The expected flush-stop seqnum should be the same as the "
1115               "one from the event that caused it (probably a seek). Got: %u."
1116               " Expected: %u", seqnum, pad_monitor->pending_flush_stop_seqnum);
1117         }
1118       }
1119
1120       if (!pad_monitor->pending_flush_stop) {
1121         GST_VALIDATE_REPORT (pad_monitor, EVENT_FLUSH_STOP_UNEXPECTED,
1122             "Unexpected flush-stop %p" GST_PTR_FORMAT, event);
1123       }
1124       pad_monitor->pending_flush_stop = FALSE;
1125
1126       /* cleanup our data */
1127       gst_validate_pad_monitor_flush (pad_monitor);
1128     }
1129       break;
1130     default:
1131       break;
1132   }
1133 }
1134
1135 static gboolean
1136 gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor *
1137     pad_monitor, GstObject * parent, GstEvent * event,
1138     GstPadEventFunction handler)
1139 {
1140   gboolean ret = TRUE;
1141   const GstSegment *segment;
1142   guint32 seqnum = gst_event_get_seqnum (event);
1143   GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor);
1144
1145   gst_validate_pad_monitor_common_event_check (pad_monitor, event);
1146
1147   /* pre checks */
1148   switch (GST_EVENT_TYPE (event)) {
1149     case GST_EVENT_SEGMENT:
1150       /* parse segment data to be used if event is handled */
1151       gst_event_parse_segment (event, &segment);
1152
1153       if (pad_monitor->pending_newsegment_seqnum) {
1154         if (pad_monitor->pending_newsegment_seqnum == seqnum) {
1155           pad_monitor->pending_newsegment_seqnum = 0;
1156         } else {
1157           /* TODO is this an error? could be a segment from the start
1158            * received just before the seek segment */
1159         }
1160       }
1161
1162       if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
1163         gst_validate_pad_monitor_add_expected_newsegment (pad_monitor, event);
1164       } else {
1165         /* check if this segment is the expected one */
1166         if (pad_monitor->expected_segment) {
1167           const GstSegment *exp_segment;
1168
1169           if (pad_monitor->expected_segment != event) {
1170             gst_event_parse_segment (pad_monitor->expected_segment,
1171                 &exp_segment);
1172             if (segment->format == exp_segment->format) {
1173               if ((exp_segment->rate * exp_segment->applied_rate !=
1174                       segment->rate * segment->applied_rate)
1175                   || exp_segment->start != segment->start
1176                   || exp_segment->stop != segment->stop
1177                   || exp_segment->position != segment->position) {
1178                 GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH,
1179                     "Expected segment didn't match received segment event");
1180               }
1181             }
1182           }
1183           gst_event_replace (&pad_monitor->expected_segment, NULL);
1184         }
1185       }
1186       break;
1187     case GST_EVENT_EOS:
1188       pad_monitor->is_eos = TRUE;
1189       /*
1190        * TODO add end of stream checks for
1191        *  - events not pushed
1192        *  - buffer data not pushed
1193        *  - pending events not received
1194        */
1195       break;
1196
1197       /* both flushes are handled by the common event function */
1198     case GST_EVENT_FLUSH_START:
1199     case GST_EVENT_FLUSH_STOP:
1200     case GST_EVENT_TAG:
1201     case GST_EVENT_SINK_MESSAGE:
1202     default:
1203       break;
1204   }
1205
1206   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1207   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
1208   gst_validate_pad_monitor_event_overrides (pad_monitor, event);
1209   if (handler) {
1210     gst_event_ref (event);
1211     ret = pad_monitor->event_func (pad, parent, event);
1212   }
1213   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
1214   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1215
1216   /* post checks */
1217   switch (GST_EVENT_TYPE (event)) {
1218     case GST_EVENT_SEGMENT:
1219       if (ret) {
1220         if (!pad_monitor->has_segment
1221             && pad_monitor->segment.format != segment->format) {
1222           gst_segment_init (&pad_monitor->segment, segment->format);
1223         }
1224         gst_segment_copy_into (segment, &pad_monitor->segment);
1225         pad_monitor->has_segment = TRUE;
1226       }
1227       break;
1228     case GST_EVENT_FLUSH_START:
1229     case GST_EVENT_FLUSH_STOP:
1230     case GST_EVENT_EOS:
1231     case GST_EVENT_TAG:
1232     case GST_EVENT_SINK_MESSAGE:
1233     default:
1234       break;
1235   }
1236
1237   if (handler)
1238     gst_event_unref (event);
1239   return ret;
1240 }
1241
1242 static gboolean
1243 gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor,
1244     GstObject * parent, GstEvent * event, GstPadEventFunction handler)
1245 {
1246   gboolean ret = TRUE;
1247   gdouble rate;
1248   GstFormat format;
1249   gint64 start, stop;
1250   GstSeekFlags seek_flags;
1251   GstSeekType start_type, stop_type;
1252   guint32 seqnum = gst_event_get_seqnum (event);
1253   GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor);
1254
1255   gst_validate_pad_monitor_common_event_check (pad_monitor, event);
1256
1257   /* pre checks */
1258   switch (GST_EVENT_TYPE (event)) {
1259     case GST_EVENT_SEEK:
1260     {
1261       gst_event_parse_seek (event, &rate, &format, &seek_flags, &start_type,
1262           &start, &stop_type, &stop);
1263       /* upstream seek - store the seek event seqnum to check
1264        * flushes and newsegments share the same */
1265
1266       /* TODO we might need to use a list as multiple seeks can be sent
1267        * before the flushes arrive here */
1268       if (seek_flags & GST_SEEK_FLAG_FLUSH) {
1269         pad_monitor->pending_flush_start_seqnum = seqnum;
1270         pad_monitor->pending_flush_stop_seqnum = seqnum;
1271       }
1272       pad_monitor->pending_newsegment_seqnum = seqnum;
1273     }
1274       break;
1275       /* both flushes are handled by the common event handling function */
1276     case GST_EVENT_FLUSH_START:
1277     case GST_EVENT_FLUSH_STOP:
1278     case GST_EVENT_NAVIGATION:
1279     case GST_EVENT_LATENCY:
1280     case GST_EVENT_STEP:
1281     case GST_EVENT_QOS:
1282     default:
1283       break;
1284   }
1285
1286   if (handler) {
1287     GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1288     gst_event_ref (event);
1289     ret = pad_monitor->event_func (pad, parent, event);
1290     GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1291   }
1292
1293   /* post checks */
1294   switch (GST_EVENT_TYPE (event)) {
1295     case GST_EVENT_FLUSH_START:
1296     case GST_EVENT_FLUSH_STOP:
1297     case GST_EVENT_QOS:
1298     case GST_EVENT_SEEK:
1299     case GST_EVENT_NAVIGATION:
1300     case GST_EVENT_LATENCY:
1301     case GST_EVENT_STEP:
1302     default:
1303       break;
1304   }
1305
1306   if (handler)
1307     gst_event_unref (event);
1308   return ret;
1309 }
1310
1311 static GstFlowReturn
1312 gst_validate_pad_monitor_chain_func (GstPad * pad, GstObject * parent,
1313     GstBuffer * buffer)
1314 {
1315   GstValidatePadMonitor *pad_monitor =
1316       g_object_get_data ((GObject *) pad, "qa-monitor");
1317   GstFlowReturn ret;
1318
1319   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
1320   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1321
1322   gst_validate_pad_monitor_check_first_buffer (pad_monitor, buffer);
1323   gst_validate_pad_monitor_update_buffer_data (pad_monitor, buffer);
1324
1325   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1326   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
1327
1328   gst_validate_pad_monitor_buffer_overrides (pad_monitor, buffer);
1329
1330   ret = pad_monitor->chain_func (pad, parent, buffer);
1331
1332   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
1333   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1334
1335   pad_monitor->last_flow_return = ret;
1336   gst_validate_pad_monitor_check_aggregated_return (pad_monitor, ret);
1337
1338   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1339   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
1340
1341   return ret;
1342 }
1343
1344 static gboolean
1345 gst_validate_pad_monitor_sink_event_func (GstPad * pad, GstObject * parent,
1346     GstEvent * event)
1347 {
1348   GstValidatePadMonitor *pad_monitor =
1349       g_object_get_data ((GObject *) pad, "qa-monitor");
1350   gboolean ret;
1351
1352   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
1353   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1354
1355   if (GST_EVENT_IS_SERIALIZED (event)) {
1356     GstClockTime last_ts;
1357     if (GST_CLOCK_TIME_IS_VALID (pad_monitor->current_timestamp)) {
1358       last_ts = pad_monitor->current_timestamp;
1359       if (GST_CLOCK_TIME_IS_VALID (pad_monitor->current_duration)) {
1360         last_ts += pad_monitor->current_duration;
1361       }
1362     } else {
1363       last_ts = 0;
1364     }
1365     gst_validate_pad_monitor_otherpad_add_pending_serialized_event (pad_monitor,
1366         event, last_ts);
1367   }
1368
1369   /* pre checks */
1370   switch (GST_EVENT_TYPE (event)) {
1371     case GST_EVENT_CAPS:{
1372       GstCaps *caps;
1373
1374       gst_event_parse_caps (event, &caps);
1375       gst_validate_pad_monitor_setcaps_pre (pad_monitor, caps);
1376       break;
1377     }
1378     default:
1379       break;
1380   }
1381   ret =
1382       gst_validate_pad_monitor_downstream_event_check (pad_monitor, parent,
1383       event, pad_monitor->event_func);
1384   /* post checks */
1385   switch (GST_EVENT_TYPE (event)) {
1386     case GST_EVENT_CAPS:{
1387       GstCaps *caps;
1388
1389       gst_event_parse_caps (event, &caps);
1390       gst_validate_pad_monitor_setcaps_post (pad_monitor, caps, ret);
1391       break;
1392     }
1393     default:
1394       break;
1395   }
1396
1397   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1398   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
1399   return ret;
1400 }
1401
1402 static gboolean
1403 gst_validate_pad_monitor_src_event_func (GstPad * pad, GstObject * parent,
1404     GstEvent * event)
1405 {
1406   GstValidatePadMonitor *pad_monitor =
1407       g_object_get_data ((GObject *) pad, "qa-monitor");
1408   gboolean ret;
1409
1410   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1411   ret = gst_validate_pad_monitor_src_event_check (pad_monitor, parent, event,
1412       pad_monitor->event_func);
1413   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1414   return ret;
1415 }
1416
1417 static gboolean
1418 gst_validate_pad_monitor_query_func (GstPad * pad, GstObject * parent,
1419     GstQuery * query)
1420 {
1421   GstValidatePadMonitor *pad_monitor =
1422       g_object_get_data ((GObject *) pad, "qa-monitor");
1423   gboolean ret;
1424
1425   gst_validate_pad_monitor_query_overrides (pad_monitor, query);
1426
1427   ret = pad_monitor->query_func (pad, parent, query);
1428
1429   if (ret) {
1430     switch (GST_QUERY_TYPE (query)) {
1431       case GST_QUERY_CAPS:{
1432         GstCaps *res;
1433         /* We shouldn't need to lock the parent as this doesn't modify
1434          * other monitors, just does some peer_pad_caps */
1435         GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1436
1437         gst_query_parse_caps_result (query, &res);
1438         if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
1439           gst_validate_pad_monitor_check_caps_fields_proxied (pad_monitor, res);
1440         }
1441         GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1442         break;
1443       }
1444       default:
1445         break;
1446     }
1447   }
1448
1449   return ret;
1450 }
1451
1452 static gboolean
1453 gst_validate_pad_get_range_func (GstPad * pad, GstObject * parent,
1454     guint64 offset, guint size, GstBuffer ** buffer)
1455 {
1456   GstValidatePadMonitor *pad_monitor =
1457       g_object_get_data ((GObject *) pad, "qa-monitor");
1458   gboolean ret;
1459   ret = pad_monitor->getrange_func (pad, parent, offset, size, buffer);
1460   return ret;
1461 }
1462
1463 static gboolean
1464 gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer,
1465     gpointer udata)
1466 {
1467   GstValidatePadMonitor *monitor = udata;
1468   GstValidateMonitor *parent = GST_VALIDATE_MONITOR_GET_PARENT (monitor);
1469
1470   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor);
1471   GST_VALIDATE_MONITOR_LOCK (monitor);
1472
1473   gst_validate_pad_monitor_check_first_buffer (monitor, buffer);
1474   gst_validate_pad_monitor_update_buffer_data (monitor, buffer);
1475
1476   gst_validate_pad_monitor_check_buffer_timestamp_in_received_range (monitor,
1477       buffer);
1478
1479   gst_validate_pad_monitor_check_late_serialized_events (monitor,
1480       GST_BUFFER_TIMESTAMP (buffer));
1481
1482   /* a GstValidatePadMonitor parent must be a GstValidateElementMonitor */
1483   if (PAD_PARENT_IS_DECODER (parent)) {
1484     /* should not push out of segment data */
1485     if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer)) &&
1486         GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer)) &&
1487         !gst_segment_clip (&monitor->segment, monitor->segment.format,
1488             GST_BUFFER_TIMESTAMP (buffer), GST_BUFFER_TIMESTAMP (buffer) +
1489             GST_BUFFER_DURATION (buffer), NULL, NULL)) {
1490       /* TODO is this a timestamp issue? */
1491       GST_VALIDATE_REPORT (monitor, BUFFER_IS_OUT_OF_SEGMENT,
1492           "buffer is out of segment and shouldn't be pushed. Timestamp: %"
1493           GST_TIME_FORMAT " - duration: %" GST_TIME_FORMAT ". Range: %"
1494           GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
1495           GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
1496           GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)),
1497           GST_TIME_ARGS (monitor->segment.start),
1498           GST_TIME_ARGS (monitor->segment.stop));
1499     }
1500   }
1501
1502   GST_VALIDATE_MONITOR_UNLOCK (monitor);
1503   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (monitor);
1504   gst_validate_pad_monitor_buffer_probe_overrides (monitor, buffer);
1505   return TRUE;
1506 }
1507
1508 static gboolean
1509 gst_validate_pad_monitor_event_probe (GstPad * pad, GstEvent * event,
1510     gpointer udata)
1511 {
1512   GstValidatePadMonitor *monitor = GST_VALIDATE_PAD_MONITOR_CAST (udata);
1513   gboolean ret;
1514
1515   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor);
1516   GST_VALIDATE_MONITOR_LOCK (monitor);
1517
1518   if (GST_EVENT_IS_SERIALIZED (event)) {
1519     gint i;
1520
1521     if (monitor->serialized_events->len > 0) {
1522       SerializedEventData *next_event =
1523           g_ptr_array_index (monitor->serialized_events, 0);
1524
1525       if (event == next_event->event
1526           || GST_EVENT_TYPE (event) == GST_EVENT_TYPE (next_event->event)) {
1527         g_ptr_array_remove_index (monitor->serialized_events, 0);
1528       }
1529     } else {
1530       /* if the event is not the first, it might be out of order */
1531       for (i = 0; i < monitor->serialized_events->len; i++) {
1532         SerializedEventData *stored_event =
1533             g_ptr_array_index (monitor->serialized_events, i);
1534
1535         if (event == stored_event->event
1536             || GST_EVENT_TYPE (event) == GST_EVENT_TYPE (stored_event->event)) {
1537           GST_VALIDATE_REPORT (monitor, EVENT_SERIALIZED_OUT_OF_ORDER,
1538               "Serialized event %" GST_PTR_FORMAT " was pushed out of original "
1539               "serialization order in pad %s:%s", event,
1540               GST_DEBUG_PAD_NAME (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor)));
1541         }
1542       }
1543     }
1544   }
1545
1546   /* This so far is just like an event that is flowing downstream,
1547    * so we do the same checks as a sinkpad event handler */
1548   ret =
1549       gst_validate_pad_monitor_downstream_event_check (monitor, NULL, event,
1550       NULL);
1551   GST_VALIDATE_MONITOR_UNLOCK (monitor);
1552   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (monitor);
1553
1554   return ret;
1555 }
1556
1557 static GstPadProbeReturn
1558 gst_validate_pad_monitor_pad_probe (GstPad * pad, GstPadProbeInfo * info,
1559     gpointer udata)
1560 {
1561   if (info->type & GST_PAD_PROBE_TYPE_BUFFER)
1562     gst_validate_pad_monitor_buffer_probe (pad, info->data, udata);
1563   else if (info->type & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM)
1564     gst_validate_pad_monitor_event_probe (pad, info->data, udata);
1565
1566   return GST_PAD_PROBE_OK;
1567 }
1568
1569 static void
1570 gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor,
1571     GstCaps * caps)
1572 {
1573   GstStructure *structure;
1574
1575   /* Check if caps are identical to last caps and complain if so */
1576   if (pad_monitor->last_caps
1577       && gst_caps_is_equal (caps, pad_monitor->last_caps)) {
1578     GST_VALIDATE_REPORT (pad_monitor, EVENT_CAPS_DUPLICATE, "%" GST_PTR_FORMAT,
1579         caps);
1580   }
1581
1582   gst_validate_pad_monitor_check_caps_complete (pad_monitor, caps);
1583
1584   if (caps) {
1585     structure = gst_caps_get_structure (caps, 0);
1586     if (gst_structure_n_fields (pad_monitor->pending_setcaps_fields)) {
1587       gint i;
1588       for (i = 0;
1589           i < gst_structure_n_fields (pad_monitor->pending_setcaps_fields);
1590           i++) {
1591         const gchar *name =
1592             gst_structure_nth_field_name (pad_monitor->pending_setcaps_fields,
1593             i);
1594         const GValue *v = gst_structure_get_value (structure, name);
1595         const GValue *otherv =
1596             gst_structure_get_value (pad_monitor->pending_setcaps_fields, name);
1597
1598         if (v == NULL) {
1599           GST_VALIDATE_REPORT (pad_monitor, CAPS_EXPECTED_FIELD_NOT_FOUND,
1600               "Field %s is missing from setcaps caps '%" GST_PTR_FORMAT "'",
1601               name, caps);
1602         } else if (gst_value_compare (v, otherv) != GST_VALUE_EQUAL) {
1603           GST_VALIDATE_REPORT (pad_monitor, CAPS_FIELD_UNEXPECTED_VALUE,
1604               "Field %s from setcaps caps '%" GST_PTR_FORMAT "' is different "
1605               "from expected value in caps '%" GST_PTR_FORMAT "'", name, caps,
1606               pad_monitor->pending_setcaps_fields);
1607         }
1608       }
1609     }
1610
1611     if (gst_validate_pad_monitor_pad_should_proxy_othercaps (pad_monitor)) {
1612       if (_structure_is_video (structure)) {
1613         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
1614             structure, "width");
1615         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
1616             structure, "height");
1617         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
1618             structure, "framerate");
1619         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
1620             structure, "pixel-aspect-ratio");
1621       } else if (_structure_is_audio (structure)) {
1622         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
1623             structure, "rate");
1624         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
1625             structure, "channels");
1626       }
1627     }
1628   }
1629
1630   gst_structure_free (pad_monitor->pending_setcaps_fields);
1631   pad_monitor->pending_setcaps_fields =
1632       gst_structure_new_empty (PENDING_FIELDS);
1633
1634   gst_validate_pad_monitor_setcaps_overrides (pad_monitor, caps);
1635 }
1636
1637 static void
1638 gst_validate_pad_monitor_setcaps_post (GstValidatePadMonitor * pad_monitor,
1639     GstCaps * caps, gboolean ret)
1640 {
1641   if (!ret)
1642     gst_validate_pad_monitor_otherpad_clear_pending_fields (pad_monitor);
1643   else {
1644     if (pad_monitor->last_caps) {
1645       gst_caps_unref (pad_monitor->last_caps);
1646     }
1647     pad_monitor->last_caps = gst_caps_ref (caps);
1648   }
1649 }
1650
1651 static gboolean
1652 gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor)
1653 {
1654   GstValidatePadMonitor *pad_monitor = GST_VALIDATE_PAD_MONITOR_CAST (monitor);
1655   GstPad *pad;
1656   if (!GST_IS_PAD (GST_VALIDATE_MONITOR_GET_OBJECT (monitor))) {
1657     GST_WARNING_OBJECT (monitor, "Trying to create pad monitor with other "
1658         "type of object");
1659     return FALSE;
1660   }
1661
1662   pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor);
1663
1664   if (g_object_get_data ((GObject *) pad, "qa-monitor")) {
1665     GST_WARNING_OBJECT (pad_monitor, "Pad already has a qa-monitor associated");
1666     return FALSE;
1667   }
1668
1669   g_object_set_data ((GObject *) pad, "qa-monitor", pad_monitor);
1670
1671   pad_monitor->pad = pad;
1672
1673   pad_monitor->event_func = GST_PAD_EVENTFUNC (pad);
1674   pad_monitor->query_func = GST_PAD_QUERYFUNC (pad);
1675   if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
1676
1677     pad_monitor->chain_func = GST_PAD_CHAINFUNC (pad);
1678     if (pad_monitor->chain_func)
1679       gst_pad_set_chain_function (pad, gst_validate_pad_monitor_chain_func);
1680
1681     gst_pad_set_event_function (pad, gst_validate_pad_monitor_sink_event_func);
1682   } else {
1683     pad_monitor->getrange_func = GST_PAD_GETRANGEFUNC (pad);
1684     if (pad_monitor->getrange_func)
1685       gst_pad_set_getrange_function (pad, gst_validate_pad_get_range_func);
1686
1687     gst_pad_set_event_function (pad, gst_validate_pad_monitor_src_event_func);
1688
1689     /* add buffer/event probes */
1690     pad_monitor->pad_probe_id =
1691         gst_pad_add_probe (pad,
1692         GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM |
1693         GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1694         (GstPadProbeCallback) gst_validate_pad_monitor_pad_probe, pad_monitor,
1695         NULL);
1696   }
1697   gst_pad_set_query_function (pad, gst_validate_pad_monitor_query_func);
1698
1699   gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (monitor),
1700       g_strdup_printf ("%s:%s", GST_DEBUG_PAD_NAME (pad)));
1701
1702   if (G_UNLIKELY (GST_PAD_PARENT (pad) == NULL))
1703     GST_FIXME ("Saw a pad not belonging to any object");
1704
1705   return TRUE;
1706 }