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