pad-monitor: only do combined return checks for demuxers
[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   if (PAD_PARENT_IS_DEMUXER (pad_monitor))
1337     gst_validate_pad_monitor_check_aggregated_return (pad_monitor, ret);
1338
1339   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1340   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
1341
1342   return ret;
1343 }
1344
1345 static gboolean
1346 gst_validate_pad_monitor_sink_event_func (GstPad * pad, GstObject * parent,
1347     GstEvent * event)
1348 {
1349   GstValidatePadMonitor *pad_monitor =
1350       g_object_get_data ((GObject *) pad, "qa-monitor");
1351   gboolean ret;
1352
1353   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
1354   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1355
1356   if (GST_EVENT_IS_SERIALIZED (event)) {
1357     GstClockTime last_ts;
1358     if (GST_CLOCK_TIME_IS_VALID (pad_monitor->current_timestamp)) {
1359       last_ts = pad_monitor->current_timestamp;
1360       if (GST_CLOCK_TIME_IS_VALID (pad_monitor->current_duration)) {
1361         last_ts += pad_monitor->current_duration;
1362       }
1363     } else {
1364       last_ts = 0;
1365     }
1366     gst_validate_pad_monitor_otherpad_add_pending_serialized_event (pad_monitor,
1367         event, last_ts);
1368   }
1369
1370   /* pre checks */
1371   switch (GST_EVENT_TYPE (event)) {
1372     case GST_EVENT_CAPS:{
1373       GstCaps *caps;
1374
1375       gst_event_parse_caps (event, &caps);
1376       gst_validate_pad_monitor_setcaps_pre (pad_monitor, caps);
1377       break;
1378     }
1379     default:
1380       break;
1381   }
1382   ret =
1383       gst_validate_pad_monitor_downstream_event_check (pad_monitor, parent,
1384       event, pad_monitor->event_func);
1385   /* post checks */
1386   switch (GST_EVENT_TYPE (event)) {
1387     case GST_EVENT_CAPS:{
1388       GstCaps *caps;
1389
1390       gst_event_parse_caps (event, &caps);
1391       gst_validate_pad_monitor_setcaps_post (pad_monitor, caps, ret);
1392       break;
1393     }
1394     default:
1395       break;
1396   }
1397
1398   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1399   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
1400   return ret;
1401 }
1402
1403 static gboolean
1404 gst_validate_pad_monitor_src_event_func (GstPad * pad, GstObject * parent,
1405     GstEvent * event)
1406 {
1407   GstValidatePadMonitor *pad_monitor =
1408       g_object_get_data ((GObject *) pad, "qa-monitor");
1409   gboolean ret;
1410
1411   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1412   ret = gst_validate_pad_monitor_src_event_check (pad_monitor, parent, event,
1413       pad_monitor->event_func);
1414   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1415   return ret;
1416 }
1417
1418 static gboolean
1419 gst_validate_pad_monitor_query_func (GstPad * pad, GstObject * parent,
1420     GstQuery * query)
1421 {
1422   GstValidatePadMonitor *pad_monitor =
1423       g_object_get_data ((GObject *) pad, "qa-monitor");
1424   gboolean ret;
1425
1426   gst_validate_pad_monitor_query_overrides (pad_monitor, query);
1427
1428   ret = pad_monitor->query_func (pad, parent, query);
1429
1430   if (ret) {
1431     switch (GST_QUERY_TYPE (query)) {
1432       case GST_QUERY_CAPS:{
1433         GstCaps *res;
1434         /* We shouldn't need to lock the parent as this doesn't modify
1435          * other monitors, just does some peer_pad_caps */
1436         GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1437
1438         gst_query_parse_caps_result (query, &res);
1439         if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
1440           gst_validate_pad_monitor_check_caps_fields_proxied (pad_monitor, res);
1441         }
1442         GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1443         break;
1444       }
1445       default:
1446         break;
1447     }
1448   }
1449
1450   return ret;
1451 }
1452
1453 static gboolean
1454 gst_validate_pad_get_range_func (GstPad * pad, GstObject * parent,
1455     guint64 offset, guint size, GstBuffer ** buffer)
1456 {
1457   GstValidatePadMonitor *pad_monitor =
1458       g_object_get_data ((GObject *) pad, "qa-monitor");
1459   gboolean ret;
1460   ret = pad_monitor->getrange_func (pad, parent, offset, size, buffer);
1461   return ret;
1462 }
1463
1464 static gboolean
1465 gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer,
1466     gpointer udata)
1467 {
1468   GstValidatePadMonitor *monitor = udata;
1469   GstValidateMonitor *parent = GST_VALIDATE_MONITOR_GET_PARENT (monitor);
1470
1471   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor);
1472   GST_VALIDATE_MONITOR_LOCK (monitor);
1473
1474   gst_validate_pad_monitor_check_first_buffer (monitor, buffer);
1475   gst_validate_pad_monitor_update_buffer_data (monitor, buffer);
1476
1477   gst_validate_pad_monitor_check_buffer_timestamp_in_received_range (monitor,
1478       buffer);
1479
1480   gst_validate_pad_monitor_check_late_serialized_events (monitor,
1481       GST_BUFFER_TIMESTAMP (buffer));
1482
1483   /* a GstValidatePadMonitor parent must be a GstValidateElementMonitor */
1484   if (PAD_PARENT_IS_DECODER (parent)) {
1485     /* should not push out of segment data */
1486     if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer)) &&
1487         GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer)) &&
1488         !gst_segment_clip (&monitor->segment, monitor->segment.format,
1489             GST_BUFFER_TIMESTAMP (buffer), GST_BUFFER_TIMESTAMP (buffer) +
1490             GST_BUFFER_DURATION (buffer), NULL, NULL)) {
1491       /* TODO is this a timestamp issue? */
1492       GST_VALIDATE_REPORT (monitor, BUFFER_IS_OUT_OF_SEGMENT,
1493           "buffer is out of segment and shouldn't be pushed. Timestamp: %"
1494           GST_TIME_FORMAT " - duration: %" GST_TIME_FORMAT ". Range: %"
1495           GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
1496           GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
1497           GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)),
1498           GST_TIME_ARGS (monitor->segment.start),
1499           GST_TIME_ARGS (monitor->segment.stop));
1500     }
1501   }
1502
1503   GST_VALIDATE_MONITOR_UNLOCK (monitor);
1504   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (monitor);
1505   gst_validate_pad_monitor_buffer_probe_overrides (monitor, buffer);
1506   return TRUE;
1507 }
1508
1509 static gboolean
1510 gst_validate_pad_monitor_event_probe (GstPad * pad, GstEvent * event,
1511     gpointer udata)
1512 {
1513   GstValidatePadMonitor *monitor = GST_VALIDATE_PAD_MONITOR_CAST (udata);
1514   gboolean ret;
1515
1516   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor);
1517   GST_VALIDATE_MONITOR_LOCK (monitor);
1518
1519   if (GST_EVENT_IS_SERIALIZED (event)) {
1520     gint i;
1521
1522     if (monitor->serialized_events->len > 0) {
1523       SerializedEventData *next_event =
1524           g_ptr_array_index (monitor->serialized_events, 0);
1525
1526       if (event == next_event->event
1527           || GST_EVENT_TYPE (event) == GST_EVENT_TYPE (next_event->event)) {
1528         g_ptr_array_remove_index (monitor->serialized_events, 0);
1529       }
1530     } else {
1531       /* if the event is not the first, it might be out of order */
1532       for (i = 0; i < monitor->serialized_events->len; i++) {
1533         SerializedEventData *stored_event =
1534             g_ptr_array_index (monitor->serialized_events, i);
1535
1536         if (event == stored_event->event
1537             || GST_EVENT_TYPE (event) == GST_EVENT_TYPE (stored_event->event)) {
1538           GST_VALIDATE_REPORT (monitor, EVENT_SERIALIZED_OUT_OF_ORDER,
1539               "Serialized event %" GST_PTR_FORMAT " was pushed out of original "
1540               "serialization order in pad %s:%s", event,
1541               GST_DEBUG_PAD_NAME (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor)));
1542         }
1543       }
1544     }
1545   }
1546
1547   /* This so far is just like an event that is flowing downstream,
1548    * so we do the same checks as a sinkpad event handler */
1549   ret =
1550       gst_validate_pad_monitor_downstream_event_check (monitor, NULL, event,
1551       NULL);
1552   GST_VALIDATE_MONITOR_UNLOCK (monitor);
1553   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (monitor);
1554
1555   return ret;
1556 }
1557
1558 static GstPadProbeReturn
1559 gst_validate_pad_monitor_pad_probe (GstPad * pad, GstPadProbeInfo * info,
1560     gpointer udata)
1561 {
1562   if (info->type & GST_PAD_PROBE_TYPE_BUFFER)
1563     gst_validate_pad_monitor_buffer_probe (pad, info->data, udata);
1564   else if (info->type & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM)
1565     gst_validate_pad_monitor_event_probe (pad, info->data, udata);
1566
1567   return GST_PAD_PROBE_OK;
1568 }
1569
1570 static void
1571 gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor,
1572     GstCaps * caps)
1573 {
1574   GstStructure *structure;
1575
1576   /* Check if caps are identical to last caps and complain if so */
1577   if (pad_monitor->last_caps
1578       && gst_caps_is_equal (caps, pad_monitor->last_caps)) {
1579     GST_VALIDATE_REPORT (pad_monitor, EVENT_CAPS_DUPLICATE, "%" GST_PTR_FORMAT,
1580         caps);
1581   }
1582
1583   gst_validate_pad_monitor_check_caps_complete (pad_monitor, caps);
1584
1585   if (caps) {
1586     structure = gst_caps_get_structure (caps, 0);
1587     if (gst_structure_n_fields (pad_monitor->pending_setcaps_fields)) {
1588       gint i;
1589       for (i = 0;
1590           i < gst_structure_n_fields (pad_monitor->pending_setcaps_fields);
1591           i++) {
1592         const gchar *name =
1593             gst_structure_nth_field_name (pad_monitor->pending_setcaps_fields,
1594             i);
1595         const GValue *v = gst_structure_get_value (structure, name);
1596         const GValue *otherv =
1597             gst_structure_get_value (pad_monitor->pending_setcaps_fields, name);
1598
1599         if (v == NULL) {
1600           GST_VALIDATE_REPORT (pad_monitor, CAPS_EXPECTED_FIELD_NOT_FOUND,
1601               "Field %s is missing from setcaps caps '%" GST_PTR_FORMAT "'",
1602               name, caps);
1603         } else if (gst_value_compare (v, otherv) != GST_VALUE_EQUAL) {
1604           GST_VALIDATE_REPORT (pad_monitor, CAPS_FIELD_UNEXPECTED_VALUE,
1605               "Field %s from setcaps caps '%" GST_PTR_FORMAT "' is different "
1606               "from expected value in caps '%" GST_PTR_FORMAT "'", name, caps,
1607               pad_monitor->pending_setcaps_fields);
1608         }
1609       }
1610     }
1611
1612     if (gst_validate_pad_monitor_pad_should_proxy_othercaps (pad_monitor)) {
1613       if (_structure_is_video (structure)) {
1614         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
1615             structure, "width");
1616         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
1617             structure, "height");
1618         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
1619             structure, "framerate");
1620         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
1621             structure, "pixel-aspect-ratio");
1622       } else if (_structure_is_audio (structure)) {
1623         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
1624             structure, "rate");
1625         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
1626             structure, "channels");
1627       }
1628     }
1629   }
1630
1631   gst_structure_free (pad_monitor->pending_setcaps_fields);
1632   pad_monitor->pending_setcaps_fields =
1633       gst_structure_new_empty (PENDING_FIELDS);
1634
1635   gst_validate_pad_monitor_setcaps_overrides (pad_monitor, caps);
1636 }
1637
1638 static void
1639 gst_validate_pad_monitor_setcaps_post (GstValidatePadMonitor * pad_monitor,
1640     GstCaps * caps, gboolean ret)
1641 {
1642   if (!ret)
1643     gst_validate_pad_monitor_otherpad_clear_pending_fields (pad_monitor);
1644   else {
1645     if (pad_monitor->last_caps) {
1646       gst_caps_unref (pad_monitor->last_caps);
1647     }
1648     pad_monitor->last_caps = gst_caps_ref (caps);
1649   }
1650 }
1651
1652 static gboolean
1653 gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor)
1654 {
1655   GstValidatePadMonitor *pad_monitor = GST_VALIDATE_PAD_MONITOR_CAST (monitor);
1656   GstPad *pad;
1657   if (!GST_IS_PAD (GST_VALIDATE_MONITOR_GET_OBJECT (monitor))) {
1658     GST_WARNING_OBJECT (monitor, "Trying to create pad monitor with other "
1659         "type of object");
1660     return FALSE;
1661   }
1662
1663   pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor);
1664
1665   if (g_object_get_data ((GObject *) pad, "qa-monitor")) {
1666     GST_WARNING_OBJECT (pad_monitor, "Pad already has a qa-monitor associated");
1667     return FALSE;
1668   }
1669
1670   g_object_set_data ((GObject *) pad, "qa-monitor", pad_monitor);
1671
1672   pad_monitor->pad = pad;
1673
1674   pad_monitor->event_func = GST_PAD_EVENTFUNC (pad);
1675   pad_monitor->query_func = GST_PAD_QUERYFUNC (pad);
1676   if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
1677
1678     pad_monitor->chain_func = GST_PAD_CHAINFUNC (pad);
1679     if (pad_monitor->chain_func)
1680       gst_pad_set_chain_function (pad, gst_validate_pad_monitor_chain_func);
1681
1682     gst_pad_set_event_function (pad, gst_validate_pad_monitor_sink_event_func);
1683   } else {
1684     pad_monitor->getrange_func = GST_PAD_GETRANGEFUNC (pad);
1685     if (pad_monitor->getrange_func)
1686       gst_pad_set_getrange_function (pad, gst_validate_pad_get_range_func);
1687
1688     gst_pad_set_event_function (pad, gst_validate_pad_monitor_src_event_func);
1689
1690     /* add buffer/event probes */
1691     pad_monitor->pad_probe_id =
1692         gst_pad_add_probe (pad,
1693         GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM |
1694         GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1695         (GstPadProbeCallback) gst_validate_pad_monitor_pad_probe, pad_monitor,
1696         NULL);
1697   }
1698   gst_pad_set_query_function (pad, gst_validate_pad_monitor_query_func);
1699
1700   gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (monitor),
1701       g_strdup_printf ("%s:%s", GST_DEBUG_PAD_NAME (pad)));
1702
1703   if (G_UNLIKELY (GST_PAD_PARENT (pad) == NULL))
1704     GST_FIXME ("Saw a pad not belonging to any object");
1705
1706   return TRUE;
1707 }