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