validate: Add a new issue to detect invalid event seqnum
[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-pipeline-monitor.h"
32 #include "gst-validate-reporter.h"
33 #include <string.h>
34 #include <stdarg.h>
35
36 /**
37  * SECTION:gst-validate-pad-monitor
38  * @short_description: Class that wraps a #GstPad for Validate checks
39  *
40  * TODO
41  */
42
43 static GstValidateInterceptionReturn
44 gst_validate_pad_monitor_intercept_report (GstValidateReporter * reporter,
45     GstValidateReport * report);
46
47 #define _do_init \
48   G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, _reporter_iface_init)
49
50 static void
51 _reporter_iface_init (GstValidateReporterInterface * iface)
52 {
53   iface->intercept_report = gst_validate_pad_monitor_intercept_report;
54 }
55
56 #define gst_validate_pad_monitor_parent_class parent_class
57 G_DEFINE_TYPE_WITH_CODE (GstValidatePadMonitor, gst_validate_pad_monitor,
58     GST_TYPE_VALIDATE_MONITOR, _do_init);
59
60 #define PENDING_FIELDS "pending-fields"
61 #define AUDIO_TIMESTAMP_TOLERANCE (GST_MSECOND * 100)
62
63 #define PAD_PARENT_IS_DEMUXER(m) \
64     (GST_VALIDATE_MONITOR_GET_PARENT(m) ? \
65         GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DEMUXER ( \
66             GST_VALIDATE_MONITOR_GET_PARENT(m)) : \
67         FALSE)
68
69 #define PAD_PARENT_IS_DECODER(m) \
70     (GST_VALIDATE_MONITOR_GET_PARENT(m) ? \
71         GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DECODER ( \
72             GST_VALIDATE_MONITOR_GET_PARENT(m)) : \
73         FALSE)
74
75 #define PAD_PARENT_IS_ENCODER(m) \
76     (GST_VALIDATE_MONITOR_GET_PARENT(m) ? \
77         GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_ENCODER ( \
78             GST_VALIDATE_MONITOR_GET_PARENT(m)) : \
79         FALSE)
80
81
82 /*
83  * Locking the parent should always be done before locking the
84  * pad-monitor to prevent deadlocks in case another monitor from
85  * another pad on the same element starts an operation that also
86  * requires locking itself and some other monitors from internally
87  * linked pads.
88  *
89  * An example:
90  * An element has a sink and a src pad. Some test starts running at sinkpad
91  * and it locks the parent, and then it locks itself. In case it needs to get
92  * some information from the srcpad, it is able to lock the srcpad and get it
93  * because the srcpad should never lock itself before locking the parent (which
94  * it won't be able as sinkpad already locked it).
95  *
96  * As a side one, it is possible that srcpad locks itself without locking the
97  * parent in case it wants to do a check that won't need to use other internally
98  * linked pads (sinkpad). But in this case it might lock and unlock freely without
99  * causing deadlocks.
100  */
101 #define GST_VALIDATE_PAD_MONITOR_PARENT_LOCK(m)                  \
102 G_STMT_START {                                             \
103   if (G_LIKELY (GST_VALIDATE_MONITOR_GET_PARENT (m))) {          \
104     GST_VALIDATE_MONITOR_LOCK (GST_VALIDATE_MONITOR_GET_PARENT (m));   \
105   } else {                                                 \
106     GST_WARNING_OBJECT (m, "No parent found, can't lock"); \
107   }                                                        \
108 } G_STMT_END
109
110 #define GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK(m)                  \
111 G_STMT_START {                                               \
112   if (G_LIKELY (GST_VALIDATE_MONITOR_GET_PARENT (m))) {            \
113     GST_VALIDATE_MONITOR_UNLOCK (GST_VALIDATE_MONITOR_GET_PARENT (m));   \
114   } else {                                                   \
115     GST_WARNING_OBJECT (m, "No parent found, can't unlock"); \
116   }                                                          \
117 } G_STMT_END
118
119 typedef struct
120 {
121   GstClockTime timestamp;
122   GstEvent *event;
123 } SerializedEventData;
124
125 static GstPad *
126 _get_actual_pad (GstPad * pad)
127 {
128   GstPad *tmp_pad;
129
130   gst_object_ref (pad);
131
132   /* We don't monitor ghost pads */
133   while (GST_IS_GHOST_PAD (pad)) {
134     tmp_pad = pad;
135     pad = gst_ghost_pad_get_target ((GstGhostPad *) pad);
136     gst_object_unref (tmp_pad);
137   }
138
139   while (GST_IS_PROXY_PAD (pad)) {
140     tmp_pad = pad;
141     pad = gst_pad_get_peer (pad);
142     gst_object_unref (tmp_pad);
143   }
144
145   return pad;
146 }
147
148 static gboolean
149 _find_master_report_on_pad (GstPad * pad, GstValidateReport * report)
150 {
151   GstValidatePadMonitor *pad_monitor;
152   GstValidateReport *prev_report;
153   gboolean result = FALSE;
154   GstPad *tmppad = pad;
155
156   pad = _get_actual_pad (pad);
157   if (pad == NULL) {
158     GST_ERROR_OBJECT (tmppad, "Does not have a target yet");
159
160     return FALSE;
161   }
162
163   pad_monitor = g_object_get_data ((GObject *) pad, "validate-monitor");
164
165   /* For some reason this pad isn't monitored */
166   if (pad_monitor == NULL)
167     goto done;
168
169   prev_report = gst_validate_reporter_get_report ((GstValidateReporter *)
170       pad_monitor, report->issue->issue_id);
171
172   if (prev_report) {
173     if (prev_report->master_report)
174       result = gst_validate_report_set_master_report (report,
175           prev_report->master_report);
176     else
177       result = gst_validate_report_set_master_report (report, prev_report);
178   }
179
180 done:
181   gst_object_unref (pad);
182
183   return result;
184 }
185
186 static gboolean
187 _find_master_report_for_sink_pad (GstValidatePadMonitor * pad_monitor,
188     GstValidateReport * report)
189 {
190   GstPad *peerpad;
191   gboolean result = FALSE;
192   GstPad *pad =
193       GST_PAD_CAST (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
194           (pad_monitor)));
195
196   peerpad = gst_pad_get_peer (pad);
197   gst_object_unref (pad);
198
199   /* If the peer src pad already has a similar report no need to look
200    * any further */
201   if (peerpad && _find_master_report_on_pad (peerpad, report))
202     result = TRUE;
203
204   if (peerpad)
205     gst_object_unref (peerpad);
206
207   return result;
208 }
209
210 static gboolean
211 _find_master_report_for_src_pad (GstValidatePadMonitor * pad_monitor,
212     GstValidateReport * report)
213 {
214   GstIterator *iter;
215   gboolean done;
216   gboolean result = FALSE;
217   GstPad *target =
218       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
219           (pad_monitor)));
220
221   iter = gst_pad_iterate_internal_links (target);
222   done = FALSE;
223   while (!done) {
224     GValue value = { 0, };
225     switch (gst_iterator_next (iter, &value)) {
226       case GST_ITERATOR_OK:
227       {
228         GstPad *pad = g_value_get_object (&value);
229
230         if (_find_master_report_on_pad (pad, report)) {
231           result = TRUE;
232           done = TRUE;
233         }
234
235         g_value_reset (&value);
236         break;
237       }
238       case GST_ITERATOR_RESYNC:
239         gst_iterator_resync (iter);
240         break;
241       case GST_ITERATOR_ERROR:
242         GST_WARNING_OBJECT (target, "Internal links pad iteration error");
243         done = TRUE;
244         break;
245       case GST_ITERATOR_DONE:
246         done = TRUE;
247         break;
248     }
249   }
250   gst_object_unref (target);
251   gst_iterator_free (iter);
252
253   return result;
254 }
255
256 static GstValidateInterceptionReturn
257 _concatenate_issues (GstValidatePadMonitor * pad_monitor,
258     GstValidateReport * report)
259 {
260   GstPad *pad =
261       GST_PAD_CAST (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
262           (pad_monitor)));
263
264   if (GST_PAD_IS_SINK (pad)
265       && _find_master_report_for_sink_pad (pad_monitor, report)) {
266     gst_object_unref (pad);
267     return GST_VALIDATE_REPORTER_KEEP;
268   } else if (GST_PAD_IS_SRC (pad)
269       && _find_master_report_for_src_pad (pad_monitor, report)) {
270     gst_object_unref (pad);
271     return GST_VALIDATE_REPORTER_KEEP;
272   }
273
274   gst_object_unref (pad);
275   return GST_VALIDATE_REPORTER_REPORT;
276 }
277
278 static GstValidateInterceptionReturn
279 gst_validate_pad_monitor_intercept_report (GstValidateReporter *
280     reporter, GstValidateReport * report)
281 {
282   GstValidateReporterInterface *iface_class, *old_iface_class;
283   GstValidatePadMonitor *pad_monitor = GST_VALIDATE_PAD_MONITOR (reporter);
284   GstValidateReportingDetails monitor_reporting_level;
285   GstValidateInterceptionReturn ret;
286
287   monitor_reporting_level =
288       gst_validate_reporter_get_reporting_level (reporter);
289
290   iface_class =
291       G_TYPE_INSTANCE_GET_INTERFACE (reporter, GST_TYPE_VALIDATE_REPORTER,
292       GstValidateReporterInterface);
293   old_iface_class = g_type_interface_peek_parent (iface_class);
294
295   old_iface_class->intercept_report (reporter, report);
296
297   switch (monitor_reporting_level) {
298     case GST_VALIDATE_SHOW_NONE:
299       ret = GST_VALIDATE_REPORTER_DROP;
300       break;
301     case GST_VALIDATE_SHOW_UNKNOWN:
302       ret = _concatenate_issues (pad_monitor, report);
303       break;
304     default:
305       ret = GST_VALIDATE_REPORTER_REPORT;
306       break;
307   }
308
309   gst_validate_report_set_reporting_level (report, monitor_reporting_level);
310   return ret;
311 }
312
313 static void
314 debug_pending_event (GstPad * pad, GPtrArray * array)
315 {
316   guint i, len;
317
318   len = array->len;
319   for (i = 0; i < len; i++) {
320     SerializedEventData *data = g_ptr_array_index (array, i);
321     GST_DEBUG_OBJECT (pad, "event #%d %" GST_TIME_FORMAT " %s %p",
322         i, GST_TIME_ARGS (data->timestamp),
323         GST_EVENT_TYPE_NAME (data->event), data->event);
324   }
325 }
326
327 static void
328 _serialized_event_data_free (SerializedEventData * serialized_event)
329 {
330   gst_event_unref (serialized_event->event);
331   g_slice_free (SerializedEventData, serialized_event);
332 }
333
334 static gboolean gst_validate_pad_monitor_do_setup (GstValidateMonitor *
335     monitor);
336 static GstElement *gst_validate_pad_monitor_get_element (GstValidateMonitor *
337     monitor);
338 static void
339 gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor,
340     GstCaps * caps);
341 static void gst_validate_pad_monitor_setcaps_post (GstValidatePadMonitor *
342     pad_monitor, GstCaps * caps, gboolean ret);
343
344 #define PAD_IS_IN_PUSH_MODE(p) ((p)->mode == GST_PAD_MODE_PUSH)
345
346 static gboolean
347 _structure_is_raw_video (GstStructure * structure)
348 {
349   return gst_structure_has_name (structure, "video/x-raw");
350 }
351
352 static gboolean
353 _structure_is_raw_audio (GstStructure * structure)
354 {
355   return gst_structure_has_name (structure, "audio/x-raw");
356 }
357
358 static gchar *
359 _get_event_string (GstEvent * event)
360 {
361   const GstStructure *st;
362
363   if ((st = gst_event_get_structure (event)))
364     return gst_structure_to_string (st);
365   else
366     return g_strdup_printf ("%s", GST_EVENT_TYPE_NAME (event));
367 }
368
369 static void
370 _check_field_type (GstValidatePadMonitor * monitor,
371     GstStructure * structure, gboolean mandatory, const gchar * field, ...)
372 {
373   va_list var_args;
374   GType type;
375   gchar *joined_types = NULL;
376   const gchar *rejected_types[5];
377   gint rejected_types_index = 0;
378   gchar *struct_str;
379
380   if (!gst_structure_has_field (structure, field)) {
381     if (mandatory) {
382       gchar *str = gst_structure_to_string (structure);
383
384       GST_VALIDATE_REPORT (monitor, CAPS_IS_MISSING_FIELD,
385           "Field '%s' is missing from structure: %s", field, str);
386       g_free (str);
387     } else {
388       GST_DEBUG_OBJECT (monitor, "Field %s is missing but is not mandatory",
389           field);
390     }
391     return;
392   }
393
394   memset ((gchar **) rejected_types, 0, sizeof (rejected_types));
395   va_start (var_args, field);
396   while ((type = va_arg (var_args, GType)) != 0) {
397     if (gst_structure_has_field_typed (structure, field, type)) {
398       va_end (var_args);
399       return;
400     }
401     rejected_types[rejected_types_index++] = g_type_name (type);
402   }
403   va_end (var_args);
404
405   joined_types = g_strjoinv (" / ", (gchar **) rejected_types);
406   struct_str = gst_structure_to_string (structure);
407   GST_VALIDATE_REPORT (monitor, CAPS_FIELD_HAS_BAD_TYPE,
408       "Field '%s' has wrong type %s in structure '%s'. Expected: %s", field,
409       g_type_name (gst_structure_get_field_type (structure, field)), struct_str,
410       joined_types);
411   g_free (joined_types);
412   g_free (struct_str);
413 }
414
415 static void
416 gst_validate_pad_monitor_check_raw_video_caps_complete (GstValidatePadMonitor *
417     monitor, GstStructure * structure)
418 {
419   _check_field_type (monitor, structure, TRUE, "width", G_TYPE_INT,
420       GST_TYPE_INT_RANGE, 0);
421   _check_field_type (monitor, structure, TRUE, "height", G_TYPE_INT,
422       GST_TYPE_INT_RANGE, 0);
423   _check_field_type (monitor, structure, TRUE, "framerate", GST_TYPE_FRACTION,
424       GST_TYPE_FRACTION_RANGE, 0);
425   _check_field_type (monitor, structure, FALSE, "pixel-aspect-ratio",
426       GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE, 0);
427   _check_field_type (monitor, structure, TRUE, "format", G_TYPE_STRING,
428       GST_TYPE_LIST);
429 }
430
431 static void
432 gst_validate_pad_monitor_check_raw_audio_caps_complete (GstValidatePadMonitor *
433     monitor, GstStructure * structure)
434 {
435   gint channels;
436   _check_field_type (monitor, structure, TRUE, "format", G_TYPE_STRING,
437       GST_TYPE_LIST, 0);
438   _check_field_type (monitor, structure, TRUE, "layout", G_TYPE_STRING,
439       GST_TYPE_LIST, 0);
440   _check_field_type (monitor, structure, TRUE, "rate", G_TYPE_INT,
441       GST_TYPE_LIST, GST_TYPE_INT_RANGE, 0);
442   _check_field_type (monitor, structure, TRUE, "channels", G_TYPE_INT,
443       GST_TYPE_LIST, GST_TYPE_INT_RANGE, 0);
444   if (gst_structure_get_int (structure, "channels", &channels)) {
445     if (channels > 2)
446       _check_field_type (monitor, structure, TRUE, "channel-mask",
447           GST_TYPE_BITMASK, GST_TYPE_LIST, 0);
448   }
449 }
450
451 static void
452 gst_validate_pad_monitor_check_caps_complete (GstValidatePadMonitor * monitor,
453     GstCaps * caps)
454 {
455   GstStructure *structure;
456   gint i;
457
458   GST_DEBUG_OBJECT (monitor, "Checking caps %" GST_PTR_FORMAT, caps);
459
460   for (i = 0; i < gst_caps_get_size (caps); i++) {
461     structure = gst_caps_get_structure (caps, i);
462
463     if (_structure_is_raw_video (structure)) {
464       gst_validate_pad_monitor_check_raw_video_caps_complete (monitor,
465           structure);
466
467     } else if (_structure_is_raw_audio (structure)) {
468       gst_validate_pad_monitor_check_raw_audio_caps_complete (monitor,
469           structure);
470     }
471   }
472 }
473
474 static GstCaps *
475 gst_validate_pad_monitor_get_othercaps (GstValidatePadMonitor * monitor,
476     GstCaps * filter)
477 {
478   GstCaps *caps = gst_caps_new_empty ();
479   GstIterator *iter;
480   gboolean done;
481   GstPad *otherpad;
482   GstCaps *peercaps;
483   GstPad *pad =
484       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
485           (monitor)));
486
487   iter = gst_pad_iterate_internal_links (pad);
488   done = FALSE;
489   while (!done) {
490     GValue value = { 0, };
491     switch (gst_iterator_next (iter, &value)) {
492       case GST_ITERATOR_OK:
493         otherpad = g_value_get_object (&value);
494
495         /* TODO What would be the correct caps operation to merge the caps in
496          * case one sink is internally linked to multiple srcs? */
497         peercaps = gst_pad_peer_query_caps (otherpad, filter);
498         if (peercaps)
499           caps = gst_caps_merge (caps, peercaps);
500
501         g_value_reset (&value);
502         break;
503       case GST_ITERATOR_RESYNC:
504         gst_iterator_resync (iter);
505         gst_caps_unref (caps);
506         caps = gst_caps_new_empty ();
507         break;
508       case GST_ITERATOR_ERROR:
509         GST_WARNING_OBJECT (pad, "Internal links pad iteration error");
510         done = TRUE;
511         break;
512       case GST_ITERATOR_DONE:
513         done = TRUE;
514         break;
515     }
516   }
517   GST_DEBUG_OBJECT (pad, "Otherpad caps: %" GST_PTR_FORMAT, caps);
518
519   gst_iterator_free (iter);
520   gst_object_unref (pad);
521
522   return caps;
523 }
524
525 static gboolean
526 _structure_is_video (GstStructure * structure)
527 {
528   const gchar *name = gst_structure_get_name (structure);
529
530   return g_strstr_len (name, 6, "video/")
531       && strcmp (name, "video/quicktime") != 0;
532 }
533
534 static gboolean
535 _structure_is_audio (GstStructure * structure)
536 {
537   const gchar *name = gst_structure_get_name (structure);
538
539   return g_strstr_len (name, 6, "audio/") != NULL;
540 }
541
542 static gboolean
543 gst_validate_pad_monitor_pad_should_proxy_othercaps (GstValidatePadMonitor *
544     monitor)
545 {
546   GstValidateMonitor *parent = GST_VALIDATE_MONITOR_GET_PARENT (monitor);
547
548   if (!parent)
549     return FALSE;
550
551   /* We only know how to handle othercaps checks for codecs so far */
552   return (GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DECODER (parent) ||
553       GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_ENCODER (parent)) &&
554       !GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_CONVERTER (parent);
555 }
556
557
558 /* Check if the field @f from @s2 (if present) is represented in @s1
559  * Represented here means either equal or @s1's value is in a list/range
560  * from @s2
561  */
562 static gboolean
563 _structures_field_is_contained (GstStructure * s1, GstStructure * s2,
564     gboolean mandatory, const gchar * f)
565 {
566   const GValue *v1;
567   const GValue *v2;
568
569   v2 = gst_structure_get_value (s2, f);
570   if (!v2)
571     return TRUE;                /* nothing to compare to */
572
573   v1 = gst_structure_get_value (s1, f);
574   if (!v1)
575     return !mandatory;
576
577   if (!gst_value_is_fixed (v1))
578     return TRUE;
579
580   if (gst_value_compare (v1, v2) == GST_VALUE_EQUAL)
581     return TRUE;
582
583   if (GST_VALUE_HOLDS_LIST (v2)) {
584     gint i;
585     for (i = 0; i < gst_value_list_get_size (v2); i++) {
586       const GValue *v2_subvalue = gst_value_list_get_value (v2, i);
587       if (gst_value_compare (v1, v2_subvalue) == GST_VALUE_EQUAL)
588         return TRUE;
589     }
590   }
591
592   if (GST_VALUE_HOLDS_ARRAY (v2)) {
593     gint i;
594     for (i = 0; i < gst_value_array_get_size (v2); i++) {
595       const GValue *v2_subvalue = gst_value_array_get_value (v2, i);
596       if (gst_value_compare (v1, v2_subvalue) == GST_VALUE_EQUAL)
597         return TRUE;
598     }
599   }
600
601   if (GST_VALUE_HOLDS_INT_RANGE (v2)) {
602     gint min, max;
603
604     min = gst_value_get_int_range_min (v2);
605     max = gst_value_get_int_range_max (v2);
606
607     if (G_VALUE_HOLDS_INT (v1)) {
608       gint v = g_value_get_int (v1);
609
610       return v >= min && v <= max;
611     } else {
612       /* TODO compare int ranges with int ranges
613        * or with lists if useful */
614     }
615   }
616
617   if (GST_VALUE_HOLDS_FRACTION_RANGE (v2)) {
618     const GValue *min, *max;
619
620     min = gst_value_get_fraction_range_min (v2);
621     max = gst_value_get_fraction_range_max (v2);
622
623     if (GST_VALUE_HOLDS_FRACTION (v1)) {
624       gint v_min = gst_value_compare (v1, min);
625       gint v_max = gst_value_compare (v1, max);
626
627       return (v_min == GST_VALUE_EQUAL || v_min == GST_VALUE_GREATER_THAN) &&
628           (v_max == GST_VALUE_EQUAL || v_max == GST_VALUE_LESS_THAN);
629     } else {
630       /* TODO compare fraction ranges with fraction ranges
631        * or with lists if useful */
632     }
633   }
634
635   return FALSE;
636 }
637
638 static void
639 _check_and_copy_structure_field (GstStructure * from, GstStructure * to,
640     const gchar * name)
641 {
642   if (gst_structure_has_field (from, name)) {
643     gst_structure_set_value (to, name, gst_structure_get_value (from, name));
644   }
645 }
646
647 static GstCaps *
648 gst_validate_pad_monitor_copy_caps_fields_into_caps (GstValidatePadMonitor *
649     monitor, GstCaps * from_caps, GstCaps * into_caps)
650 {
651   gint i, j, into_size, from_size;
652   GstStructure *structure;
653   GstCaps *res = gst_caps_new_empty ();
654
655   into_size = gst_caps_get_size (into_caps);
656   from_size = gst_caps_get_size (from_caps);
657
658   for (i = 0; i < into_size; i++) {
659     GstStructure *s = gst_caps_get_structure (into_caps, i);
660
661     for (j = 0; j < from_size; j++) {
662       GstStructure *new_structure = gst_structure_copy (s);
663
664       structure = gst_caps_get_structure (from_caps, j);
665       if (_structure_is_video (structure)) {
666         _check_and_copy_structure_field (structure, new_structure, "width");
667         _check_and_copy_structure_field (structure, new_structure, "height");
668         _check_and_copy_structure_field (structure, new_structure, "framerate");
669         _check_and_copy_structure_field (structure, new_structure,
670             "pixel-aspect-ratio");
671       } else if (_structure_is_audio (s)) {
672         _check_and_copy_structure_field (structure, new_structure, "rate");
673         _check_and_copy_structure_field (structure, new_structure, "channels");
674       }
675
676       gst_caps_append_structure (res, new_structure);
677     }
678   }
679   return res;
680 }
681
682 static GstCaps *
683 gst_validate_pad_monitor_transform_caps (GstValidatePadMonitor * monitor,
684     GstCaps * caps)
685 {
686   GstCaps *othercaps;
687   GstCaps *new_caps;
688   GstIterator *iter;
689   gboolean done;
690   GstPad *otherpad;
691   GstCaps *template_caps;
692   GstPad *pad;
693
694
695   GST_DEBUG_OBJECT (monitor, "Transform caps %" GST_PTR_FORMAT, caps);
696
697   if (caps == NULL)
698     return NULL;
699
700   othercaps = gst_caps_new_empty ();
701
702   pad =
703       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
704           (monitor)));
705   iter = gst_pad_iterate_internal_links (pad);
706   done = FALSE;
707   while (!done) {
708     GValue value = { 0, };
709     switch (gst_iterator_next (iter, &value)) {
710       case GST_ITERATOR_OK:
711         otherpad = g_value_get_object (&value);
712         template_caps = gst_pad_get_pad_template_caps (otherpad);
713
714         new_caps =
715             gst_validate_pad_monitor_copy_caps_fields_into_caps (monitor, caps,
716             template_caps);
717         if (!gst_caps_is_empty (new_caps))
718           gst_caps_append (othercaps, new_caps);
719         else
720           gst_caps_unref (new_caps);
721
722         gst_caps_unref (template_caps);
723         g_value_reset (&value);
724         break;
725       case GST_ITERATOR_RESYNC:
726         gst_iterator_resync (iter);
727         gst_caps_unref (othercaps);
728         othercaps = gst_caps_new_empty ();
729         break;
730       case GST_ITERATOR_ERROR:
731         GST_WARNING_OBJECT (pad, "Internal links pad iteration error");
732         done = TRUE;
733         break;
734       case GST_ITERATOR_DONE:
735         done = TRUE;
736         break;
737     }
738   }
739   gst_iterator_free (iter);
740
741   GST_DEBUG_OBJECT (pad, "Transformed caps: %" GST_PTR_FORMAT, othercaps);
742   gst_object_unref (pad);
743
744   return othercaps;
745 }
746
747 static void
748 gst_validate_pad_monitor_check_caps_fields_proxied (GstValidatePadMonitor *
749     monitor, GstCaps * caps, GstCaps * filter)
750 {
751   GstStructure *structure;
752   GstStructure *otherstructure;
753   GstCaps *othercaps;
754   GstCaps *otherfilter;
755   gint i, j;
756
757   if (!gst_validate_pad_monitor_pad_should_proxy_othercaps (monitor))
758     return;
759
760   otherfilter = gst_validate_pad_monitor_transform_caps (monitor, filter);
761   othercaps = gst_validate_pad_monitor_get_othercaps (monitor, otherfilter);
762   if (otherfilter)
763     gst_caps_unref (otherfilter);
764
765   for (i = 0; i < gst_caps_get_size (othercaps); i++) {
766     gboolean found = FALSE;
767     gboolean type_match = FALSE;
768
769     otherstructure = gst_caps_get_structure (othercaps, i);
770
771     /* look for a proxied version of 'otherstructure' */
772     if (_structure_is_video (otherstructure)) {
773       for (j = 0; j < gst_caps_get_size (caps); j++) {
774         structure = gst_caps_get_structure (caps, j);
775         if (_structure_is_video (structure)) {
776           type_match = TRUE;
777           if (_structures_field_is_contained (structure, otherstructure, TRUE,
778                   "width")
779               && _structures_field_is_contained (structure, otherstructure,
780                   TRUE, "height")
781               && _structures_field_is_contained (structure, otherstructure,
782                   TRUE, "framerate")
783               && _structures_field_is_contained (structure, otherstructure,
784                   FALSE, "pixel-aspect-ratio")) {
785             found = TRUE;
786             break;
787           }
788         }
789       }
790     } else if (_structure_is_audio (otherstructure)) {
791       for (j = 0; j < gst_caps_get_size (caps); j++) {
792         structure = gst_caps_get_structure (caps, j);
793         if (_structure_is_audio (structure)) {
794           type_match = TRUE;
795           if (_structures_field_is_contained (structure, otherstructure, TRUE,
796                   "rate")
797               && _structures_field_is_contained (structure, otherstructure,
798                   TRUE, "channels")) {
799             found = TRUE;
800             break;
801           }
802         }
803       }
804     }
805
806     if (type_match && !found) {
807       gchar *otherstruct_str = gst_structure_to_string (otherstructure),
808           *caps_str = gst_caps_to_string (caps);
809
810       GST_VALIDATE_REPORT (monitor, GET_CAPS_NOT_PROXYING_FIELDS,
811           "Peer pad structure '%s' has no similar version "
812           "on pad's caps '%s'", otherstruct_str, caps_str);
813
814       g_free (otherstruct_str);
815       g_free (caps_str);
816     }
817   }
818
819   gst_caps_unref (othercaps);
820 }
821
822 static void
823 gst_validate_pad_monitor_check_late_serialized_events (GstValidatePadMonitor *
824     monitor, GstClockTime ts)
825 {
826   gint i;
827   GstPad *pad;
828
829   if (!GST_CLOCK_TIME_IS_VALID (ts))
830     return;
831
832   pad =
833       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
834           (monitor)));
835
836   GST_DEBUG_OBJECT (pad, "Timestamp to check %" GST_TIME_FORMAT,
837       GST_TIME_ARGS (ts));
838
839   for (i = 0; i < monitor->serialized_events->len; i++) {
840     SerializedEventData *data =
841         g_ptr_array_index (monitor->serialized_events, i);
842
843     GST_DEBUG_OBJECT (pad, "Event #%d (%s) ts: %" GST_TIME_FORMAT,
844         i, GST_EVENT_TYPE_NAME (data->event), GST_TIME_ARGS (data->timestamp));
845
846     if (GST_CLOCK_TIME_IS_VALID (data->timestamp) && data->timestamp < ts) {
847       gchar *event_str = _get_event_string (data->event);
848
849       GST_VALIDATE_REPORT (monitor, SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME,
850           "Serialized event %s wasn't pushed before expected timestamp %"
851           GST_TIME_FORMAT " on pad %s:%s", event_str,
852           GST_TIME_ARGS (data->timestamp), GST_DEBUG_PAD_NAME (pad));
853
854       g_free (event_str);
855     } else {
856       /* events should be ordered by ts */
857       break;
858     }
859   }
860
861   if (i) {
862     debug_pending_event (pad, monitor->serialized_events);
863     g_ptr_array_remove_range (monitor->serialized_events, 0, i);
864   }
865
866   gst_object_unref (pad);
867 }
868
869 static void
870 gst_validate_pad_monitor_dispose (GObject * object)
871 {
872   GstValidatePadMonitor *monitor = GST_VALIDATE_PAD_MONITOR_CAST (object);
873   GstPad *pad =
874       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
875           (monitor)));
876
877   if (pad) {
878     if (monitor->pad_probe_id)
879       gst_pad_remove_probe (pad, monitor->pad_probe_id);
880     gst_object_unref (pad);
881   }
882
883   if (monitor->expected_segment)
884     gst_event_unref (monitor->expected_segment);
885
886   gst_structure_free (monitor->pending_setcaps_fields);
887   g_ptr_array_unref (monitor->serialized_events);
888   g_list_free_full (monitor->expired_events, (GDestroyNotify) gst_event_unref);
889   g_list_free_full (monitor->all_bufs, (GDestroyNotify) gst_buffer_unref);
890   gst_caps_replace (&monitor->last_caps, NULL);
891   gst_caps_replace (&monitor->last_query_res, NULL);
892   gst_caps_replace (&monitor->last_query_filter, NULL);
893
894   G_OBJECT_CLASS (parent_class)->dispose (object);
895 }
896
897 static void
898 gst_validate_pad_monitor_class_init (GstValidatePadMonitorClass * klass)
899 {
900   GObjectClass *gobject_class;
901   GstValidateMonitorClass *monitor_klass;
902
903   gobject_class = G_OBJECT_CLASS (klass);
904   monitor_klass = GST_VALIDATE_MONITOR_CLASS (klass);
905
906   gobject_class->dispose = gst_validate_pad_monitor_dispose;
907
908   monitor_klass->setup = gst_validate_pad_monitor_do_setup;
909   monitor_klass->get_element = gst_validate_pad_monitor_get_element;
910 }
911
912 static void
913 gst_validate_pad_monitor_init (GstValidatePadMonitor * pad_monitor)
914 {
915   pad_monitor->pending_setcaps_fields =
916       gst_structure_new_empty (PENDING_FIELDS);
917   pad_monitor->serialized_events =
918       g_ptr_array_new_with_free_func ((GDestroyNotify)
919       _serialized_event_data_free);
920   pad_monitor->expired_events = NULL;
921   gst_segment_init (&pad_monitor->segment, GST_FORMAT_BYTES);
922   pad_monitor->first_buffer = TRUE;
923   pad_monitor->pending_buffer_discont = TRUE;
924
925   pad_monitor->timestamp_range_start = GST_CLOCK_TIME_NONE;
926   pad_monitor->timestamp_range_end = GST_CLOCK_TIME_NONE;
927   pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE;
928 }
929
930 /**
931  * gst_validate_pad_monitor_new:
932  * @pad: (transfer none): a #GstPad to run Validate on
933  */
934 GstValidatePadMonitor *
935 gst_validate_pad_monitor_new (GstPad * pad, GstValidateRunner * runner,
936     GstValidateElementMonitor * parent)
937 {
938   GstValidatePadMonitor *monitor = g_object_new (GST_TYPE_VALIDATE_PAD_MONITOR,
939       "object", pad, "validate-runner", runner, "validate-parent",
940       parent, NULL);
941   GstObject *target =
942       gst_validate_monitor_get_target (GST_VALIDATE_MONITOR (monitor));
943
944   if (target == NULL) {
945     g_object_unref (monitor);
946     return NULL;
947   }
948
949   gst_object_unref (target);
950   return monitor;
951 }
952
953 static GstElement *
954 gst_validate_pad_monitor_get_element (GstValidateMonitor * monitor)
955 {
956   GstPad *pad =
957       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
958           (monitor)));
959   GstElement *parent = GST_ELEMENT (gst_pad_get_parent (pad));
960
961   gst_object_unref (pad);
962
963   return parent;
964 }
965
966 static void
967 gst_validate_pad_monitor_event_overrides (GstValidatePadMonitor * pad_monitor,
968     GstEvent * event)
969 {
970   GList *iter;
971
972   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
973   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
974       iter = g_list_next (iter)) {
975     GstValidateOverride *override = iter->data;
976
977     gst_validate_override_event_handler (override,
978         GST_VALIDATE_MONITOR_CAST (pad_monitor), event);
979   }
980   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
981 }
982
983 static void
984 gst_validate_pad_monitor_buffer_overrides (GstValidatePadMonitor * pad_monitor,
985     GstBuffer * buffer)
986 {
987   GList *iter;
988
989   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
990   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
991       iter = g_list_next (iter)) {
992     GstValidateOverride *override = iter->data;
993
994     gst_validate_override_buffer_handler (override,
995         GST_VALIDATE_MONITOR_CAST (pad_monitor), buffer);
996   }
997   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
998 }
999
1000 static void
1001 gst_validate_pad_monitor_buffer_probe_overrides (GstValidatePadMonitor *
1002     pad_monitor, GstBuffer * buffer)
1003 {
1004   GList *iter;
1005
1006   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
1007   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
1008       iter = g_list_next (iter)) {
1009     GstValidateOverride *override = iter->data;
1010
1011     gst_validate_override_buffer_probe_handler (override,
1012         GST_VALIDATE_MONITOR_CAST (pad_monitor), buffer);
1013   }
1014   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
1015 }
1016
1017 static void
1018 gst_validate_pad_monitor_query_overrides (GstValidatePadMonitor * pad_monitor,
1019     GstQuery * query)
1020 {
1021   GList *iter;
1022
1023   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
1024   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
1025       iter = g_list_next (iter)) {
1026     GstValidateOverride *override = iter->data;
1027
1028     gst_validate_override_query_handler (override,
1029         GST_VALIDATE_MONITOR_CAST (pad_monitor), query);
1030   }
1031   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
1032 }
1033
1034 static void
1035 gst_validate_pad_monitor_setcaps_overrides (GstValidatePadMonitor * pad_monitor,
1036     GstCaps * caps)
1037 {
1038   GList *iter;
1039
1040   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
1041   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
1042       iter = g_list_next (iter)) {
1043     GstValidateOverride *override = iter->data;
1044
1045     gst_validate_override_setcaps_handler (override,
1046         GST_VALIDATE_MONITOR_CAST (pad_monitor), caps);
1047   }
1048   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
1049 }
1050
1051 /* FIXME : This is a bit dubious, what's the point of this check ? */
1052 static gboolean
1053 gst_validate_pad_monitor_timestamp_is_in_received_range (GstValidatePadMonitor *
1054     monitor, GstClockTime ts, GstClockTime tolerance)
1055 {
1056   GstPad *pad =
1057       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1058           (monitor)));
1059
1060   GST_DEBUG_OBJECT (pad,
1061       "Checking if timestamp %" GST_TIME_FORMAT " is in range: %"
1062       GST_TIME_FORMAT " - %" GST_TIME_FORMAT " for pad "
1063       "%s:%s with tolerance: %" GST_TIME_FORMAT, GST_TIME_ARGS (ts),
1064       GST_TIME_ARGS (monitor->timestamp_range_start),
1065       GST_TIME_ARGS (monitor->timestamp_range_end), GST_DEBUG_PAD_NAME (pad),
1066       GST_TIME_ARGS (tolerance));
1067   gst_object_unref (pad);
1068
1069   return !GST_CLOCK_TIME_IS_VALID (monitor->timestamp_range_start) ||
1070       !GST_CLOCK_TIME_IS_VALID (monitor->timestamp_range_end) ||
1071       ((monitor->timestamp_range_start >= tolerance ?
1072           monitor->timestamp_range_start - tolerance : 0) <= ts
1073       && (ts >= tolerance ? ts - tolerance : 0) <=
1074       monitor->timestamp_range_end);
1075 }
1076
1077 /* Iterates over internal links (sinkpads) to check that this buffer has
1078  * a timestamp that is in the range of the lastly received buffers */
1079 static void
1080     gst_validate_pad_monitor_check_buffer_timestamp_in_received_range
1081     (GstValidatePadMonitor * monitor, GstBuffer * buffer,
1082     GstClockTime tolerance)
1083 {
1084   GstClockTime ts;
1085   GstClockTime ts_end;
1086   GstIterator *iter;
1087   gboolean has_one = FALSE;
1088   gboolean found = FALSE;
1089   gboolean done;
1090   GstPad *otherpad;
1091   GstValidatePadMonitor *othermonitor;
1092   GstPad *pad =
1093       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1094           (monitor)));
1095
1096   if (!GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))
1097       || !GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) {
1098     GST_DEBUG_OBJECT (pad,
1099         "Can't check buffer timestamps range as "
1100         "buffer has no valid timestamp/duration");
1101     goto done;
1102   }
1103
1104   ts = GST_BUFFER_TIMESTAMP (buffer);
1105   ts_end = ts + GST_BUFFER_DURATION (buffer);
1106
1107   iter = gst_pad_iterate_internal_links (pad);
1108
1109   if (iter == NULL) {
1110     GST_WARNING_OBJECT (pad, "No iterator available");
1111     goto done;
1112   }
1113
1114   done = FALSE;
1115   while (!done) {
1116     GValue value = { 0, };
1117     switch (gst_iterator_next (iter, &value)) {
1118       case GST_ITERATOR_OK:
1119         otherpad = g_value_get_object (&value);
1120         GST_DEBUG_OBJECT (pad, "Checking pad %s:%s input timestamps",
1121             GST_DEBUG_PAD_NAME (otherpad));
1122         othermonitor =
1123             g_object_get_data ((GObject *) otherpad, "validate-monitor");
1124         GST_VALIDATE_MONITOR_LOCK (othermonitor);
1125         if (gst_validate_pad_monitor_timestamp_is_in_received_range
1126             (othermonitor, ts, tolerance)
1127             &&
1128             gst_validate_pad_monitor_timestamp_is_in_received_range
1129             (othermonitor, ts_end, tolerance)) {
1130           done = TRUE;
1131           found = TRUE;
1132         }
1133         GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1134         g_value_reset (&value);
1135         has_one = TRUE;
1136         break;
1137       case GST_ITERATOR_RESYNC:
1138         gst_iterator_resync (iter);
1139         has_one = FALSE;
1140         found = FALSE;
1141         break;
1142       case GST_ITERATOR_ERROR:
1143         GST_WARNING_OBJECT (pad, "Internal links pad iteration error");
1144         done = TRUE;
1145         break;
1146       case GST_ITERATOR_DONE:
1147         done = TRUE;
1148         break;
1149     }
1150   }
1151   gst_iterator_free (iter);
1152
1153   if (!has_one) {
1154     GST_DEBUG_OBJECT (pad, "Skipping timestamp in range check as no "
1155         "internal linked pad was found");
1156     goto done;
1157   }
1158   if (!found) {
1159     GST_VALIDATE_REPORT (monitor, BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE,
1160         "Timestamp %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT
1161         " is out of range of received input", GST_TIME_ARGS (ts),
1162         GST_TIME_ARGS (ts_end));
1163   }
1164 done:
1165   if (pad)
1166     gst_object_unref (pad);
1167 }
1168
1169 static void
1170 gst_validate_pad_monitor_check_discont (GstValidatePadMonitor * pad_monitor,
1171     GstBuffer * buffer)
1172 {
1173   if (pad_monitor->pending_buffer_discont) {
1174     if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT))
1175       GST_VALIDATE_REPORT (pad_monitor, BUFFER_MISSING_DISCONT,
1176           "Buffer is missing a DISCONT flag");
1177     pad_monitor->pending_buffer_discont = FALSE;
1178   }
1179 }
1180
1181 static void
1182 gst_validate_pad_monitor_check_first_buffer (GstValidatePadMonitor *
1183     pad_monitor, GstBuffer * buffer)
1184 {
1185   GstPad *pad =
1186       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1187           (pad_monitor)));
1188
1189   if (G_UNLIKELY (pad_monitor->first_buffer)) {
1190     pad_monitor->first_buffer = FALSE;
1191
1192     if (!pad_monitor->has_segment && PAD_IS_IN_PUSH_MODE (pad)) {
1193       GST_VALIDATE_REPORT (pad_monitor, BUFFER_BEFORE_SEGMENT,
1194           "Received buffer before Segment event");
1195     }
1196
1197     GST_DEBUG_OBJECT (pad,
1198         "Checking first buffer (pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
1199         ")", GST_TIME_ARGS (GST_BUFFER_PTS (buffer)),
1200         GST_TIME_ARGS (GST_BUFFER_DTS (buffer)));
1201
1202   }
1203
1204   gst_object_unref (pad);
1205 }
1206
1207 static void
1208 gst_validate_pad_monitor_check_eos (GstValidatePadMonitor *
1209     pad_monitor, GstBuffer * buffer)
1210 {
1211   if (G_UNLIKELY (pad_monitor->is_eos)) {
1212     GST_VALIDATE_REPORT (pad_monitor, BUFFER_AFTER_EOS,
1213         "Received buffer %" GST_PTR_FORMAT " after EOS", buffer);
1214   }
1215 }
1216
1217 static void
1218 gst_validate_pad_monitor_update_buffer_data (GstValidatePadMonitor *
1219     pad_monitor, GstBuffer * buffer)
1220 {
1221   GstPad *pad =
1222       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1223           (pad_monitor)));
1224   pad_monitor->current_timestamp = GST_BUFFER_TIMESTAMP (buffer);
1225   pad_monitor->current_duration = GST_BUFFER_DURATION (buffer);
1226   if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) {
1227     if (GST_CLOCK_TIME_IS_VALID (pad_monitor->timestamp_range_start)) {
1228       pad_monitor->timestamp_range_start =
1229           MIN (pad_monitor->timestamp_range_start,
1230           GST_BUFFER_TIMESTAMP (buffer));
1231     } else {
1232       pad_monitor->timestamp_range_start = GST_BUFFER_TIMESTAMP (buffer);
1233     }
1234
1235     if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) {
1236       GstClockTime endts =
1237           GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer);
1238       if (GST_CLOCK_TIME_IS_VALID (pad_monitor->timestamp_range_end)) {
1239         pad_monitor->timestamp_range_end =
1240             MAX (pad_monitor->timestamp_range_end, endts);
1241       } else {
1242         pad_monitor->timestamp_range_end = endts;
1243       }
1244     }
1245   }
1246   GST_DEBUG_OBJECT (pad, "Current stored range: %" GST_TIME_FORMAT
1247       " - %" GST_TIME_FORMAT,
1248       GST_TIME_ARGS (pad_monitor->timestamp_range_start),
1249       GST_TIME_ARGS (pad_monitor->timestamp_range_end));
1250
1251   gst_object_unref (pad);
1252 }
1253
1254 static GstFlowReturn
1255 _combine_flows (GstFlowReturn ret1, GstFlowReturn ret2)
1256 {
1257   if (ret1 == ret2)
1258     return ret1;
1259   if (ret1 <= GST_FLOW_NOT_NEGOTIATED)
1260     return ret1;
1261   if (ret2 <= GST_FLOW_NOT_NEGOTIATED)
1262     return ret2;
1263   if (ret1 == GST_FLOW_FLUSHING || ret2 == GST_FLOW_FLUSHING)
1264     return GST_FLOW_FLUSHING;
1265   if (ret1 == GST_FLOW_OK || ret2 == GST_FLOW_OK)
1266     return GST_FLOW_OK;
1267   return ret2;
1268 }
1269
1270 static void
1271 gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor *
1272     monitor, GstObject * parent, GstFlowReturn ret)
1273 {
1274   GstIterator *iter;
1275   gboolean done;
1276   GstPad *otherpad;
1277   GstPad *peerpad;
1278   GstValidatePadMonitor *othermonitor;
1279   GstFlowReturn aggregated = GST_FLOW_NOT_LINKED;
1280   gboolean found_a_pad = FALSE;
1281   GstPad *pad =
1282       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1283           (monitor)));
1284
1285   iter = gst_pad_iterate_internal_links (pad);
1286   done = FALSE;
1287   while (!done) {
1288     GValue value = { 0, };
1289     switch (gst_iterator_next (iter, &value)) {
1290       case GST_ITERATOR_OK:
1291         otherpad = g_value_get_object (&value);
1292         peerpad = gst_pad_get_peer (otherpad);
1293         if (peerpad) {
1294           othermonitor =
1295               g_object_get_data ((GObject *) peerpad, "validate-monitor");
1296           if (othermonitor) {
1297             found_a_pad = TRUE;
1298             GST_VALIDATE_MONITOR_LOCK (othermonitor);
1299             aggregated =
1300                 _combine_flows (aggregated, othermonitor->last_flow_return);
1301             GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1302           }
1303
1304           gst_object_unref (peerpad);
1305         }
1306         g_value_reset (&value);
1307         break;
1308       case GST_ITERATOR_RESYNC:
1309         gst_iterator_resync (iter);
1310         break;
1311       case GST_ITERATOR_ERROR:
1312         GST_WARNING_OBJECT (pad, "Internal links pad iteration error");
1313         done = TRUE;
1314         break;
1315       case GST_ITERATOR_DONE:
1316         done = TRUE;
1317         break;
1318     }
1319   }
1320   gst_iterator_free (iter);
1321   if (!found_a_pad) {
1322     /* no peer pad found, nothing to do */
1323     goto done;
1324   }
1325   if (aggregated == GST_FLOW_OK || aggregated == GST_FLOW_EOS) {
1326     GstState state, pending;
1327
1328     /* those are acceptable situations */
1329     if (GST_PAD_IS_FLUSHING (pad) && ret == GST_FLOW_FLUSHING) {
1330       /* pad is flushing, always acceptable to return flushing */
1331       goto done;
1332     }
1333
1334     gst_element_get_state (GST_ELEMENT (parent), &state, &pending, 0);
1335     if (ret == GST_FLOW_FLUSHING && (state < GST_STATE_PAUSED
1336             || pending < GST_STATE_PAUSED)) {
1337       /* Element is being teared down, accept FLOW_FLUSHING */
1338
1339       goto done;
1340     }
1341
1342     if (monitor->is_eos && ret == GST_FLOW_EOS) {
1343       /* this element received eos and returned eos */
1344       goto done;
1345     }
1346
1347     if (PAD_PARENT_IS_DEMUXER (monitor) && ret == GST_FLOW_EOS) {
1348       /* a demuxer can return EOS when the samples end */
1349       goto done;
1350     }
1351   }
1352
1353   if (aggregated != ret) {
1354     GST_VALIDATE_REPORT (monitor, WRONG_FLOW_RETURN,
1355         "Wrong combined flow return %s(%d). Expected: %s(%d)",
1356         gst_flow_get_name (ret), ret, gst_flow_get_name (aggregated),
1357         aggregated);
1358   }
1359
1360 done:
1361   gst_object_unref (pad);
1362 }
1363
1364 static void
1365     gst_validate_pad_monitor_otherpad_add_pending_serialized_event
1366     (GstValidatePadMonitor * monitor, GstEvent * event, GstClockTime last_ts)
1367 {
1368   GstIterator *iter;
1369   gboolean done;
1370   GstPad *otherpad;
1371   GstValidatePadMonitor *othermonitor;
1372   GstPad *pad;
1373
1374
1375   if (!GST_EVENT_IS_SERIALIZED (event))
1376     return;
1377
1378   pad =
1379       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1380           (monitor)));
1381   iter = gst_pad_iterate_internal_links (pad);
1382   if (iter == NULL) {
1383     /* inputselector will return NULL if the sinkpad is not the active one .... */
1384     GST_FIXME_OBJECT (pad, "No iterator");
1385     gst_object_unref (pad);
1386     return;
1387   }
1388
1389   done = FALSE;
1390   while (!done) {
1391     GValue value = { 0, };
1392     switch (gst_iterator_next (iter, &value)) {
1393       case GST_ITERATOR_OK:
1394         otherpad = g_value_get_object (&value);
1395         othermonitor =
1396             g_object_get_data ((GObject *) otherpad, "validate-monitor");
1397         if (othermonitor) {
1398           SerializedEventData *data = g_slice_new0 (SerializedEventData);
1399           data->timestamp = last_ts;
1400           data->event = gst_event_ref (event);
1401           GST_VALIDATE_MONITOR_LOCK (othermonitor);
1402           GST_DEBUG_OBJECT (pad, "Storing for pad %s:%s event %p %s",
1403               GST_DEBUG_PAD_NAME (otherpad), event,
1404               GST_EVENT_TYPE_NAME (event));
1405           g_ptr_array_add (othermonitor->serialized_events, data);
1406           debug_pending_event (otherpad, othermonitor->serialized_events);
1407           GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1408         }
1409         g_value_reset (&value);
1410         break;
1411       case GST_ITERATOR_RESYNC:
1412         gst_iterator_resync (iter);
1413         break;
1414       case GST_ITERATOR_ERROR:
1415         GST_WARNING_OBJECT (pad, "Internal links pad iteration error");
1416         done = TRUE;
1417         break;
1418       case GST_ITERATOR_DONE:
1419         done = TRUE;
1420         break;
1421     }
1422   }
1423   gst_iterator_free (iter);
1424   gst_object_unref (pad);
1425 }
1426
1427 static void
1428 gst_validate_pad_monitor_otherpad_add_pending_field (GstValidatePadMonitor *
1429     monitor, GstStructure * structure, const gchar * field)
1430 {
1431   GstIterator *iter;
1432   gboolean done;
1433   GstPad *otherpad;
1434   GstValidatePadMonitor *othermonitor;
1435   const GValue *v;
1436   GstPad *pad;
1437
1438   v = gst_structure_get_value (structure, field);
1439   pad =
1440       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1441           (monitor)));
1442
1443   if (v == NULL) {
1444     GST_DEBUG_OBJECT (pad, "Not adding pending field %s as it isn't "
1445         "present on structure %" GST_PTR_FORMAT, field, structure);
1446     gst_object_unref (pad);
1447     return;
1448   }
1449
1450   iter = gst_pad_iterate_internal_links (pad);
1451   done = FALSE;
1452   while (!done) {
1453     GValue value = { 0, };
1454     switch (gst_iterator_next (iter, &value)) {
1455       case GST_ITERATOR_OK:
1456         otherpad = g_value_get_object (&value);
1457         othermonitor =
1458             g_object_get_data ((GObject *) otherpad, "validate-monitor");
1459         if (othermonitor) {
1460           GST_VALIDATE_MONITOR_LOCK (othermonitor);
1461           g_assert (othermonitor->pending_setcaps_fields != NULL);
1462           gst_structure_set_value (othermonitor->pending_setcaps_fields,
1463               field, v);
1464           GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1465         }
1466         g_value_reset (&value);
1467         break;
1468       case GST_ITERATOR_RESYNC:
1469         gst_iterator_resync (iter);
1470         break;
1471       case GST_ITERATOR_ERROR:
1472         GST_WARNING_OBJECT (pad, "Internal links pad iteration error");
1473         done = TRUE;
1474         break;
1475       case GST_ITERATOR_DONE:
1476         done = TRUE;
1477         break;
1478     }
1479   }
1480   gst_iterator_free (iter);
1481   gst_object_unref (pad);
1482 }
1483
1484 static void
1485 gst_validate_pad_monitor_otherpad_clear_pending_fields (GstValidatePadMonitor *
1486     monitor)
1487 {
1488   GstIterator *iter;
1489   gboolean done;
1490   GstPad *otherpad;
1491   GstValidatePadMonitor *othermonitor;
1492
1493   GstPad *pad =
1494       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1495           (monitor)));
1496
1497   iter = gst_pad_iterate_internal_links (pad);
1498   if (iter == NULL) {
1499     gst_object_unref (pad);
1500     GST_DEBUG_OBJECT (monitor, "No internally linked pad");
1501
1502     return;
1503   }
1504
1505   done = FALSE;
1506   while (!done) {
1507     GValue value = { 0, };
1508     switch (gst_iterator_next (iter, &value)) {
1509       case GST_ITERATOR_OK:
1510         otherpad = g_value_get_object (&value);
1511         othermonitor =
1512             g_object_get_data ((GObject *) otherpad, "validate-monitor");
1513         if (othermonitor) {
1514           GST_VALIDATE_MONITOR_LOCK (othermonitor);
1515           g_assert (othermonitor->pending_setcaps_fields != NULL);
1516           gst_structure_free (othermonitor->pending_setcaps_fields);
1517           othermonitor->pending_setcaps_fields =
1518               gst_structure_new_empty (PENDING_FIELDS);
1519           GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1520         }
1521         g_value_reset (&value);
1522         break;
1523       case GST_ITERATOR_RESYNC:
1524         gst_iterator_resync (iter);
1525         break;
1526       case GST_ITERATOR_ERROR:
1527         GST_WARNING_OBJECT (pad, "Internal links pad iteration error");
1528         done = TRUE;
1529         break;
1530       case GST_ITERATOR_DONE:
1531         done = TRUE;
1532         break;
1533     }
1534   }
1535   gst_object_unref (pad);
1536   gst_iterator_free (iter);
1537 }
1538
1539 static void
1540 gst_validate_pad_monitor_add_expected_newsegment (GstValidatePadMonitor *
1541     monitor, GstEvent * event)
1542 {
1543   GstIterator *iter;
1544   gboolean done;
1545   GstPad *otherpad;
1546   GstValidatePadMonitor *othermonitor;
1547   GstPad *pad =
1548       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1549           (monitor)));
1550
1551   iter = gst_pad_iterate_internal_links (pad);
1552   if (iter == NULL) {
1553     GST_DEBUG_OBJECT (monitor, "No internally linked pad");
1554     gst_object_unref (pad);
1555     return;
1556   }
1557
1558   done = FALSE;
1559   while (!done) {
1560     GValue value = { 0, };
1561     switch (gst_iterator_next (iter, &value)) {
1562       case GST_ITERATOR_OK:
1563         otherpad = g_value_get_object (&value);
1564         if (!otherpad)
1565           continue;
1566         othermonitor =
1567             g_object_get_data ((GObject *) otherpad, "validate-monitor");
1568         GST_VALIDATE_MONITOR_LOCK (othermonitor);
1569         gst_event_replace (&othermonitor->expected_segment, event);
1570         GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1571         g_value_reset (&value);
1572         break;
1573       case GST_ITERATOR_RESYNC:
1574         gst_iterator_resync (iter);
1575         break;
1576       case GST_ITERATOR_ERROR:
1577         GST_WARNING_OBJECT (pad, "Internal links pad iteration error");
1578         done = TRUE;
1579         break;
1580       case GST_ITERATOR_DONE:
1581         done = TRUE;
1582         break;
1583     }
1584   }
1585   gst_iterator_free (iter);
1586   gst_object_unref (pad);
1587 }
1588
1589 static void
1590 gst_validate_pad_monitor_flush (GstValidatePadMonitor * pad_monitor)
1591 {
1592   pad_monitor->current_timestamp = GST_CLOCK_TIME_NONE;
1593   pad_monitor->current_duration = GST_CLOCK_TIME_NONE;
1594   pad_monitor->timestamp_range_start = GST_CLOCK_TIME_NONE;
1595   pad_monitor->timestamp_range_end = GST_CLOCK_TIME_NONE;
1596   pad_monitor->has_segment = FALSE;
1597   pad_monitor->is_eos = FALSE;
1598   pad_monitor->last_flow_return = GST_FLOW_OK;
1599   gst_caps_replace (&pad_monitor->last_caps, NULL);
1600   pad_monitor->caps_is_audio = pad_monitor->caps_is_video =
1601       pad_monitor->caps_is_raw = FALSE;
1602
1603   g_list_free_full (pad_monitor->expired_events,
1604       (GDestroyNotify) gst_event_unref);
1605   pad_monitor->expired_events = NULL;
1606
1607   if (pad_monitor->serialized_events->len)
1608     g_ptr_array_remove_range (pad_monitor->serialized_events, 0,
1609         pad_monitor->serialized_events->len);
1610 }
1611
1612 /* common checks for both sink and src event functions */
1613 static void
1614 gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor *
1615     pad_monitor, GstEvent * event)
1616 {
1617   guint32 seqnum = gst_event_get_seqnum (event);
1618
1619   if (seqnum == GST_SEQNUM_INVALID)
1620     GST_VALIDATE_REPORT (pad_monitor, EVENT_INVALID_SEQNUM,
1621         "Event %p (%s) has an invalid SEQNUM", event,
1622         GST_EVENT_TYPE_NAME (event));
1623
1624   switch (GST_EVENT_TYPE (event)) {
1625     case GST_EVENT_FLUSH_START:
1626     {
1627       if (pad_monitor->pending_flush_start_seqnum != GST_SEQNUM_INVALID) {
1628         if (seqnum == pad_monitor->pending_flush_start_seqnum) {
1629           pad_monitor->pending_flush_start_seqnum = GST_SEQNUM_INVALID;
1630         } else {
1631           GST_VALIDATE_REPORT (pad_monitor, FLUSH_START_HAS_WRONG_SEQNUM,
1632               "Got: %u Expected: %u", seqnum,
1633               pad_monitor->pending_flush_start_seqnum);
1634         }
1635       }
1636
1637       if (pad_monitor->pending_flush_stop) {
1638         GST_VALIDATE_REPORT (pad_monitor, EVENT_FLUSH_START_UNEXPECTED,
1639             "Received flush-start from when flush-stop was expected");
1640       }
1641       pad_monitor->pending_flush_stop = TRUE;
1642     }
1643       break;
1644     case GST_EVENT_FLUSH_STOP:
1645     {
1646       if (pad_monitor->pending_flush_stop_seqnum != GST_SEQNUM_INVALID) {
1647         if (seqnum == pad_monitor->pending_flush_stop_seqnum) {
1648           pad_monitor->pending_flush_stop_seqnum = GST_SEQNUM_INVALID;
1649         } else {
1650           GST_VALIDATE_REPORT (pad_monitor, FLUSH_STOP_HAS_WRONG_SEQNUM,
1651               "Got: %u Expected: %u", seqnum,
1652               pad_monitor->pending_flush_stop_seqnum);
1653         }
1654       }
1655
1656       pad_monitor->pending_newsegment_seqnum = seqnum;
1657       pad_monitor->pending_eos_seqnum = seqnum;
1658
1659       if (!pad_monitor->pending_flush_stop) {
1660         gchar *event_str = _get_event_string (event);
1661
1662         GST_VALIDATE_REPORT (pad_monitor, EVENT_FLUSH_STOP_UNEXPECTED,
1663             "Unexpected flush-stop %s", event_str);
1664         g_free (event_str);
1665       }
1666       pad_monitor->pending_flush_stop = FALSE;
1667
1668       /* Buffers following a FLUSH should have the DISCONT flag set */
1669       pad_monitor->pending_buffer_discont = TRUE;
1670
1671       /* cleanup our data */
1672       gst_validate_pad_monitor_flush (pad_monitor);
1673     }
1674       break;
1675     default:
1676       break;
1677   }
1678 }
1679
1680 static void
1681 mark_pads_eos (GstValidatePadMonitor * pad_monitor)
1682 {
1683   GstValidatePadMonitor *peer_monitor;
1684   GstPad *real_peer;
1685   GstPad *pad =
1686       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1687           (pad_monitor)));
1688   GstPad *peer = gst_pad_get_peer (pad);
1689
1690   gst_object_unref (pad);
1691   pad_monitor->is_eos = TRUE;
1692   if (peer) {
1693     real_peer = _get_actual_pad (peer);
1694     peer_monitor =
1695         g_object_get_data ((GObject *) real_peer, "validate-monitor");
1696     if (peer_monitor)
1697       peer_monitor->is_eos = TRUE;
1698     gst_object_unref (peer);
1699     gst_object_unref (real_peer);
1700   }
1701 }
1702
1703 static inline gboolean
1704 _should_check_buffers (GstValidatePadMonitor * pad_monitor,
1705     gboolean force_checks)
1706 {
1707   GstPad *pad =
1708       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1709           (pad_monitor)));
1710   GstValidateMonitor *monitor = GST_VALIDATE_MONITOR (pad_monitor);
1711
1712   if (pad_monitor->first_buffer || force_checks) {
1713     if (pad_monitor->segment.rate != 1.0) {
1714       GST_INFO_OBJECT (pad_monitor, "We do not support buffer checking"
1715           " for trick modes");
1716
1717       pad_monitor->check_buffers = FALSE;
1718     } else if (!PAD_PARENT_IS_DECODER (pad_monitor)) {
1719       GST_DEBUG_OBJECT (pad, "Not on a decoder => no buffer checking");
1720
1721       pad_monitor->check_buffers = FALSE;
1722     } else if (GST_PAD_DIRECTION (pad) != GST_PAD_SINK) {
1723       GST_DEBUG_OBJECT (pad, "Not a sinkpad => no buffer checking");
1724
1725       pad_monitor->check_buffers = FALSE;
1726     } else if (!pad_monitor->caps_is_video) {
1727       GST_DEBUG_OBJECT (pad, "Not working with video => no buffer checking");
1728
1729       pad_monitor->check_buffers = FALSE;
1730     } else if (monitor->media_descriptor == NULL) {
1731       GST_DEBUG_OBJECT (pad, "No media_descriptor set => no buffer checking");
1732
1733       pad_monitor->check_buffers = FALSE;
1734     } else
1735         if (!gst_validate_media_descriptor_detects_frames
1736         (monitor->media_descriptor)) {
1737       GST_DEBUG_OBJECT (pad,
1738           "No frame detection media descriptor => not buffer checking");
1739       pad_monitor->check_buffers = FALSE;
1740     } else if (pad_monitor->all_bufs == NULL &&
1741         !gst_validate_media_descriptor_get_buffers (monitor->media_descriptor,
1742             pad, NULL, &pad_monitor->all_bufs)) {
1743
1744       GST_INFO_OBJECT (monitor,
1745           "The MediaInfo is marked as detecting frame, but getting frames"
1746           " from pad %" GST_PTR_FORMAT " did not work (some format conversion"
1747           " might be happening)", pad);
1748
1749       pad_monitor->check_buffers = FALSE;
1750     } else {
1751       if (!pad_monitor->current_buf)
1752         pad_monitor->current_buf = pad_monitor->all_bufs;
1753       pad_monitor->check_buffers = TRUE;
1754     }
1755   }
1756   gst_object_unref (pad);
1757
1758   return pad_monitor->check_buffers;
1759 }
1760
1761 static void
1762 gst_validate_monitor_find_next_buffer (GstValidatePadMonitor * pad_monitor)
1763 {
1764   GList *tmp;
1765   gboolean passed_start = FALSE;
1766
1767   if (!_should_check_buffers (pad_monitor, TRUE))
1768     return;
1769
1770   for (tmp = g_list_last (pad_monitor->all_bufs); tmp; tmp = tmp->prev) {
1771     GstBuffer *cbuf = (GstBuffer *) tmp->data;
1772     GstClockTime ts =
1773         GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DTS (cbuf)) ? GST_BUFFER_DTS (cbuf)
1774         : GST_BUFFER_PTS (cbuf);
1775
1776     if (!GST_CLOCK_TIME_IS_VALID (ts))
1777       continue;
1778
1779     if (ts <= pad_monitor->segment.start)
1780       passed_start = TRUE;
1781
1782     if (!passed_start)
1783       continue;
1784
1785     if (!GST_BUFFER_FLAG_IS_SET (cbuf, GST_BUFFER_FLAG_DELTA_UNIT)) {
1786       break;
1787     }
1788   }
1789
1790   if (tmp == NULL)
1791     pad_monitor->current_buf = pad_monitor->all_bufs;
1792   else
1793     pad_monitor->current_buf = tmp;
1794 }
1795
1796 /* Checks whether a segment is just an update of another,
1797  * That is to say that only the base and offset field differ and all
1798  * other fields are identical */
1799 static gboolean
1800 is_segment_update (GstSegment * a, const GstSegment * b)
1801 {
1802   /* Note : We never care about the position field, it is only
1803    * used for internal usage by elements */
1804   if (a->rate == b->rate &&
1805       a->applied_rate == b->applied_rate &&
1806       a->format == b->format && a->time == b->time) {
1807     /* Changes in base/offset are considered updates */
1808     /* Updating the end position of a segment is an update */
1809     /* Updating the duration of a segment is an update */
1810     if (a->rate > 0.0) {
1811       if (a->start == b->start)
1812         return TRUE;
1813     } else {
1814       if (a->stop == b->stop)
1815         return TRUE;
1816     }
1817   }
1818   return FALSE;
1819 }
1820
1821 static GstFlowReturn
1822 gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor *
1823     pad_monitor, GstObject * parent, GstEvent * event,
1824     GstPadEventFunction handler)
1825 {
1826   GstFlowReturn ret = GST_FLOW_OK;
1827   const GstSegment *segment;
1828   guint32 seqnum = gst_event_get_seqnum (event);
1829   GstPad *pad =
1830       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1831           (pad_monitor)));
1832
1833   gst_validate_pad_monitor_common_event_check (pad_monitor, event);
1834
1835   /* pre checks */
1836   switch (GST_EVENT_TYPE (event)) {
1837     case GST_EVENT_STREAM_START:
1838       /* Buffers following a STREAM_START should have the DISCONT flag set */
1839       pad_monitor->pending_buffer_discont = TRUE;
1840       break;
1841     case GST_EVENT_SEGMENT:
1842       /* parse segment data to be used if event is handled */
1843       gst_event_parse_segment (event, &segment);
1844
1845       GST_DEBUG_OBJECT (pad, "Got segment %" GST_SEGMENT_FORMAT, segment);
1846
1847       /* Reset expected flush start/stop values, we have a segment */
1848       pad_monitor->pending_flush_start_seqnum = GST_SEQNUM_INVALID;
1849       pad_monitor->pending_flush_stop_seqnum = GST_SEQNUM_INVALID;
1850
1851       if (pad_monitor->pending_newsegment_seqnum != GST_SEQNUM_INVALID) {
1852         if (pad_monitor->pending_newsegment_seqnum == seqnum) {
1853           pad_monitor->pending_newsegment_seqnum = GST_SEQNUM_INVALID;
1854           if (GST_CLOCK_TIME_IS_VALID (pad_monitor->pending_seek_accurate_time)) {
1855             if (segment->time == pad_monitor->pending_seek_accurate_time) {
1856               pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE;
1857             } else {
1858               GST_VALIDATE_REPORT (pad_monitor, SEGMENT_HAS_WRONG_START,
1859                   "After an accurate seek, got: %" GST_TIME_FORMAT
1860                   " Expected: %" GST_TIME_FORMAT, GST_TIME_ARGS (segment->time),
1861                   GST_TIME_ARGS (pad_monitor->pending_seek_accurate_time));
1862             }
1863           }
1864         } else {
1865           GST_VALIDATE_REPORT (pad_monitor, SEGMENT_HAS_WRONG_SEQNUM,
1866               "Got: %u Expected: %u", seqnum, pad_monitor->pending_eos_seqnum);
1867         }
1868       }
1869
1870       pad_monitor->pending_eos_seqnum = seqnum;
1871
1872       if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
1873         gst_validate_pad_monitor_add_expected_newsegment (pad_monitor, event);
1874       } else {
1875         /* check if this segment is the expected one */
1876         if (pad_monitor->expected_segment) {
1877           const GstSegment *exp_segment;
1878
1879           if (pad_monitor->expected_segment != event) {
1880             gst_event_parse_segment (pad_monitor->expected_segment,
1881                 &exp_segment);
1882             if (segment->format == exp_segment->format) {
1883               if ((exp_segment->rate * exp_segment->applied_rate !=
1884                       segment->rate * segment->applied_rate))
1885                 GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH,
1886                     "Rate * applied_rate %f != expected %f",
1887                     segment->rate * segment->applied_rate,
1888                     exp_segment->rate * exp_segment->applied_rate);
1889               if (exp_segment->start != segment->start)
1890                 GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH,
1891                     "Start %" GST_TIME_FORMAT " != expected %" GST_TIME_FORMAT,
1892                     GST_TIME_ARGS (segment->start),
1893                     GST_TIME_ARGS (exp_segment->start));
1894               if (exp_segment->stop != segment->stop)
1895                 GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH,
1896                     "Stop %" GST_TIME_FORMAT " != expected %" GST_TIME_FORMAT,
1897                     GST_TIME_ARGS (segment->stop),
1898                     GST_TIME_ARGS (exp_segment->stop));
1899               if (exp_segment->position != segment->position)
1900                 GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH,
1901                     "Position %" GST_TIME_FORMAT " != expected %"
1902                     GST_TIME_FORMAT, GST_TIME_ARGS (segment->position),
1903                     GST_TIME_ARGS (exp_segment->position));
1904             }
1905           }
1906           gst_event_replace (&pad_monitor->expected_segment, NULL);
1907         }
1908       }
1909       break;
1910     case GST_EVENT_CAPS:{
1911       GstCaps *caps;
1912
1913       gst_event_parse_caps (event, &caps);
1914       gst_validate_pad_monitor_setcaps_pre (pad_monitor, caps);
1915       break;
1916     }
1917     case GST_EVENT_EOS:
1918       pad_monitor->is_eos = TRUE;
1919       /* FIXME : This feels and looks wrong ... */
1920       if (pad_monitor->pending_eos_seqnum == GST_SEQNUM_INVALID) {
1921         GST_VALIDATE_REPORT (pad_monitor, EVENT_EOS_WITHOUT_SEGMENT,
1922             "EOS %" GST_PTR_FORMAT " received before a segment was received",
1923             event);
1924       } else if (pad_monitor->pending_eos_seqnum != seqnum) {
1925         GST_VALIDATE_REPORT (pad_monitor, EOS_HAS_WRONG_SEQNUM,
1926             "Got: %u. Expected: %u", seqnum, pad_monitor->pending_eos_seqnum);
1927       }
1928
1929       /*
1930        * TODO add end of stream checks for
1931        *  - events not pushed
1932        *  - buffer data not pushed
1933        *  - pending events not received
1934        */
1935       break;
1936
1937       /* both flushes are handled by the common event function */
1938     case GST_EVENT_FLUSH_START:
1939     case GST_EVENT_FLUSH_STOP:
1940     case GST_EVENT_TAG:
1941     case GST_EVENT_SINK_MESSAGE:
1942     default:
1943       break;
1944   }
1945
1946   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1947   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
1948   gst_validate_pad_monitor_event_overrides (pad_monitor, event);
1949   if (handler) {
1950     gst_event_ref (event);
1951     if (pad_monitor->event_full_func)
1952       ret = pad_monitor->event_full_func (pad, parent, event);
1953     else if (pad_monitor->event_func (pad, parent, event))
1954       ret = GST_FLOW_OK;
1955     else
1956       ret = GST_FLOW_ERROR;
1957   }
1958   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
1959   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1960
1961   /* post checks */
1962   switch (GST_EVENT_TYPE (event)) {
1963     case GST_EVENT_SEGMENT:
1964       if (ret == GST_FLOW_OK) {
1965         /* If the new segment is not an update of the previous one, then
1966          * the following buffer should have the DISCONT flag set */
1967         if (!is_segment_update (&pad_monitor->segment, segment))
1968           pad_monitor->pending_buffer_discont = TRUE;
1969         if (!pad_monitor->has_segment
1970             && pad_monitor->segment.format != segment->format) {
1971           gst_segment_init (&pad_monitor->segment, segment->format);
1972         }
1973         gst_segment_copy_into (segment, &pad_monitor->segment);
1974         pad_monitor->has_segment = TRUE;
1975         gst_validate_monitor_find_next_buffer (pad_monitor);
1976       }
1977       break;
1978     case GST_EVENT_CAPS:{
1979       GstCaps *caps;
1980
1981       gst_event_parse_caps (event, &caps);
1982       gst_validate_pad_monitor_setcaps_post (pad_monitor, caps,
1983           ret == GST_FLOW_OK);
1984       break;
1985     }
1986     case GST_EVENT_FLUSH_START:
1987     case GST_EVENT_FLUSH_STOP:
1988     case GST_EVENT_EOS:
1989     case GST_EVENT_TAG:
1990     case GST_EVENT_SINK_MESSAGE:
1991     default:
1992       break;
1993   }
1994
1995   if (handler)
1996     gst_event_unref (event);
1997   gst_object_unref (pad);
1998   return ret;
1999 }
2000
2001 static gboolean
2002 gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor,
2003     GstObject * parent, GstEvent * event, GstPadEventFunction handler)
2004 {
2005   gboolean ret = TRUE;
2006   gdouble rate;
2007   GstFormat format;
2008   gint64 start, stop;
2009   GstSeekFlags seek_flags;
2010   GstSeekType start_type, stop_type;
2011   guint32 seqnum = gst_event_get_seqnum (event);
2012   GstPad *pad =
2013       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
2014           (pad_monitor)));
2015
2016   gst_validate_pad_monitor_common_event_check (pad_monitor, event);
2017
2018   /* pre checks */
2019   switch (GST_EVENT_TYPE (event)) {
2020     case GST_EVENT_SEEK:
2021     {
2022       gst_event_parse_seek (event, &rate, &format, &seek_flags, &start_type,
2023           &start, &stop_type, &stop);
2024       /* upstream seek - store the seek event seqnum to check
2025        * flushes and newsegments share the same */
2026     }
2027       break;
2028       /* both flushes are handled by the common event handling function */
2029     case GST_EVENT_FLUSH_START:
2030     case GST_EVENT_FLUSH_STOP:
2031     case GST_EVENT_NAVIGATION:
2032     case GST_EVENT_LATENCY:
2033     case GST_EVENT_STEP:
2034     case GST_EVENT_QOS:
2035     default:
2036       break;
2037   }
2038
2039   if (handler) {
2040     GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
2041     /* Safely store pending accurate seek values */
2042     if (GST_EVENT_TYPE (event) == GST_EVENT_SEEK) {
2043       if (seek_flags & GST_SEEK_FLAG_ACCURATE) {
2044         GST_DEBUG_OBJECT (pad,
2045             "Storing expected accurate seek time %" GST_TIME_FORMAT,
2046             GST_TIME_ARGS (start));
2047         pad_monitor->pending_seek_accurate_time = start;
2048       }
2049       /* TODO we might need to use a list as multiple seeks can be sent
2050        * before the flushes arrive here */
2051       if (seek_flags & GST_SEEK_FLAG_FLUSH) {
2052         pad_monitor->pending_flush_start_seqnum = seqnum;
2053         pad_monitor->pending_flush_stop_seqnum = seqnum;
2054       }
2055     }
2056
2057     gst_event_ref (event);
2058     ret = pad_monitor->event_func (pad, parent, event);
2059
2060     if (GST_EVENT_TYPE (event) == GST_EVENT_SEEK) {
2061       /* If the seek was already handled (same current seqnum), reset the
2062        * expected accurate seek value */
2063       if (ret && pad_monitor->has_segment
2064           && seqnum == pad_monitor->pending_eos_seqnum) {
2065         GST_DEBUG_OBJECT (pad,
2066             "Resetting expected accurate seek value, was already handled");
2067         pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE;
2068       } else if (!ret) {
2069         /* do not expect any of these events anymore */
2070         pad_monitor->pending_flush_start_seqnum = GST_SEQNUM_INVALID;
2071         pad_monitor->pending_flush_stop_seqnum = GST_SEQNUM_INVALID;
2072         pad_monitor->pending_newsegment_seqnum = GST_SEQNUM_INVALID;
2073         pad_monitor->pending_eos_seqnum = GST_SEQNUM_INVALID;
2074         pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE;
2075       }
2076     }
2077     GST_VALIDATE_MONITOR_LOCK (pad_monitor);
2078   }
2079
2080   /* post checks */
2081   switch (GST_EVENT_TYPE (event)) {
2082     case GST_EVENT_FLUSH_START:
2083     case GST_EVENT_FLUSH_STOP:
2084     case GST_EVENT_QOS:
2085     case GST_EVENT_SEEK:
2086     case GST_EVENT_NAVIGATION:
2087     case GST_EVENT_LATENCY:
2088     case GST_EVENT_STEP:
2089     default:
2090       break;
2091   }
2092
2093   if (handler)
2094     gst_event_unref (event);
2095   gst_object_unref (pad);
2096   return ret;
2097 }
2098
2099 static gboolean
2100 gst_validate_pad_monitor_check_right_buffer (GstValidatePadMonitor *
2101     pad_monitor, GstBuffer * buffer)
2102 {
2103   gchar *checksum;
2104   GstBuffer *wanted_buf;
2105   GstMapInfo map, wanted_map;
2106
2107   gboolean ret = TRUE;
2108   GstPad *pad;
2109
2110
2111   if (_should_check_buffers (pad_monitor, FALSE) == FALSE)
2112     return FALSE;
2113
2114   pad =
2115       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
2116           (pad_monitor)));
2117   if (pad_monitor->current_buf == NULL) {
2118     GST_INFO_OBJECT (pad, "No current buffer one pad, Why?");
2119     gst_object_unref (pad);
2120     return FALSE;
2121   }
2122
2123   wanted_buf = pad_monitor->current_buf->data;
2124
2125   if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (wanted_buf)) &&
2126       GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (buffer)) &&
2127       GST_BUFFER_PTS (wanted_buf) != GST_BUFFER_PTS (buffer)) {
2128
2129     GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER,
2130         "buffer %" GST_PTR_FORMAT " PTS %" GST_TIME_FORMAT
2131         " different than expected: %" GST_TIME_FORMAT, buffer,
2132         GST_TIME_ARGS (GST_BUFFER_PTS (buffer)),
2133         GST_TIME_ARGS (GST_BUFFER_PTS (wanted_buf)));
2134
2135     ret = FALSE;
2136   }
2137
2138   if (GST_BUFFER_DTS (wanted_buf) != GST_BUFFER_DTS (buffer)) {
2139     GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER,
2140         "buffer %" GST_PTR_FORMAT " DTS %" GST_TIME_FORMAT
2141         " different than expected: %" GST_TIME_FORMAT, buffer,
2142         GST_TIME_ARGS (GST_BUFFER_DTS (buffer)),
2143         GST_TIME_ARGS (GST_BUFFER_DTS (wanted_buf)));
2144     ret = FALSE;
2145   }
2146
2147   if (GST_BUFFER_DURATION (wanted_buf) != GST_BUFFER_DURATION (buffer)) {
2148     GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER,
2149         "buffer %" GST_PTR_FORMAT " DURATION %" GST_TIME_FORMAT
2150         " different than expected: %" GST_TIME_FORMAT, buffer,
2151         GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)),
2152         GST_TIME_ARGS (GST_BUFFER_DURATION (wanted_buf)));
2153     ret = FALSE;
2154   }
2155
2156   if (GST_BUFFER_FLAG_IS_SET (wanted_buf, GST_BUFFER_FLAG_DELTA_UNIT) !=
2157       GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)) {
2158     GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER,
2159         "buffer %" GST_PTR_FORMAT "  Delta unit is set to %s but expected %s",
2160         buffer, GST_BUFFER_FLAG_IS_SET (buffer,
2161             GST_BUFFER_FLAG_DELTA_UNIT) ? "True" : "False",
2162         GST_BUFFER_FLAG_IS_SET (wanted_buf,
2163             GST_BUFFER_FLAG_DELTA_UNIT) ? "True" : "False");
2164     ret = FALSE;
2165   }
2166
2167   g_assert (gst_buffer_map (wanted_buf, &wanted_map, GST_MAP_READ));
2168   g_assert (gst_buffer_map (buffer, &map, GST_MAP_READ));
2169
2170   checksum = g_compute_checksum_for_data (G_CHECKSUM_MD5,
2171       (const guchar *) map.data, map.size);
2172
2173   if (g_strcmp0 ((gchar *) wanted_map.data, checksum)) {
2174     GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER,
2175         "buffer %" GST_PTR_FORMAT " checksum %s different from expected: %s",
2176         buffer, checksum, wanted_map.data);
2177     ret = FALSE;
2178   }
2179
2180   gst_buffer_unmap (wanted_buf, &wanted_map);
2181   gst_buffer_unmap (buffer, &map);
2182   g_free (checksum);
2183   gst_object_unref (pad);
2184
2185   pad_monitor->current_buf = pad_monitor->current_buf->next;
2186
2187   return ret;
2188 }
2189
2190 static void
2191 gst_validate_pad_monitor_check_return (GstValidatePadMonitor * pad_monitor,
2192     GstFlowReturn ret)
2193 {
2194   GstValidateMonitor *parent = GST_VALIDATE_MONITOR (pad_monitor);
2195
2196   if (ret != GST_FLOW_ERROR)
2197     return;
2198
2199   while (GST_VALIDATE_MONITOR_GET_PARENT (parent))
2200     parent = GST_VALIDATE_MONITOR_GET_PARENT (parent);
2201
2202   if (GST_IS_VALIDATE_PIPELINE_MONITOR (parent)) {
2203     GstValidatePipelineMonitor *m = GST_VALIDATE_PIPELINE_MONITOR (parent);
2204
2205     GST_VALIDATE_MONITOR_LOCK (m);
2206     if (m->got_error == FALSE) {
2207       GST_VALIDATE_REPORT (pad_monitor, FLOW_ERROR_WITHOUT_ERROR_MESSAGE,
2208           "Pad return GST_FLOW_ERROR but no GST_MESSAGE_ERROR was received on"
2209           " the bus");
2210
2211       /* Only report it the first time */
2212       m->got_error = TRUE;
2213     }
2214     GST_VALIDATE_MONITOR_UNLOCK (m);
2215   }
2216 }
2217
2218 static GstFlowReturn
2219 gst_validate_pad_monitor_chain_func (GstPad * pad, GstObject * parent,
2220     GstBuffer * buffer)
2221 {
2222   GstValidatePadMonitor *pad_monitor =
2223       g_object_get_data ((GObject *) pad, "validate-monitor");
2224   GstFlowReturn ret;
2225
2226   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
2227   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
2228
2229   gst_validate_pad_monitor_check_discont (pad_monitor, buffer);
2230   gst_validate_pad_monitor_check_right_buffer (pad_monitor, buffer);
2231   gst_validate_pad_monitor_check_first_buffer (pad_monitor, buffer);
2232   gst_validate_pad_monitor_update_buffer_data (pad_monitor, buffer);
2233   gst_validate_pad_monitor_check_eos (pad_monitor, buffer);
2234
2235   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
2236   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
2237
2238   gst_validate_pad_monitor_buffer_overrides (pad_monitor, buffer);
2239
2240   ret = pad_monitor->chain_func (pad, parent, buffer);
2241
2242   gst_validate_pad_monitor_check_return (pad_monitor, ret);
2243
2244   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
2245   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
2246
2247   pad_monitor->last_flow_return = ret;
2248   if (ret == GST_FLOW_EOS) {
2249     mark_pads_eos (pad_monitor);
2250   }
2251   if (PAD_PARENT_IS_DEMUXER (pad_monitor))
2252     gst_validate_pad_monitor_check_aggregated_return (pad_monitor, parent, ret);
2253
2254   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
2255   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
2256
2257   return ret;
2258 }
2259
2260 static gboolean
2261 gst_validate_pad_monitor_event_is_tracked (GstValidatePadMonitor * monitor,
2262     GstEvent * event)
2263 {
2264   if (!GST_EVENT_IS_SERIALIZED (event)) {
2265     return FALSE;
2266   }
2267
2268   /* we don't track Tag events because they mutate too much and it is hard
2269    * to match a tag event pushed on a source pad with the one that was received
2270    * on a sink pad.
2271    * One idea would be to use seqnum, but it seems that it is undefined whether
2272    * seqnums should be maintained in tag events that are created from others
2273    * up to today. (2013-08-29)
2274    */
2275   if (GST_EVENT_TYPE (event) == GST_EVENT_TAG)
2276     return FALSE;
2277
2278   return TRUE;
2279 }
2280
2281 static GstFlowReturn
2282 gst_validate_pad_monitor_sink_event_full_func (GstPad * pad, GstObject * parent,
2283     GstEvent * event)
2284 {
2285   GstValidatePadMonitor *pad_monitor =
2286       g_object_get_data ((GObject *) pad, "validate-monitor");
2287   GstFlowReturn ret;
2288
2289   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
2290   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
2291
2292   if (gst_validate_pad_monitor_event_is_tracked (pad_monitor, event)) {
2293     GstClockTime last_ts = GST_CLOCK_TIME_NONE;
2294     if (GST_CLOCK_TIME_IS_VALID (pad_monitor->current_timestamp)) {
2295       last_ts = pad_monitor->current_timestamp;
2296       if (GST_CLOCK_TIME_IS_VALID (pad_monitor->current_duration)) {
2297         last_ts += pad_monitor->current_duration;
2298       }
2299     }
2300     gst_validate_pad_monitor_otherpad_add_pending_serialized_event (pad_monitor,
2301         event, last_ts);
2302   }
2303
2304   ret =
2305       gst_validate_pad_monitor_downstream_event_check (pad_monitor, parent,
2306       event, pad_monitor->event_func);
2307
2308   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
2309   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
2310   return ret;
2311 }
2312
2313 static gboolean
2314 gst_validate_pad_monitor_sink_event_func (GstPad * pad, GstObject * parent,
2315     GstEvent * event)
2316 {
2317   if (gst_validate_pad_monitor_sink_event_full_func (pad, parent,
2318           event) == GST_FLOW_OK)
2319     return TRUE;
2320   return FALSE;
2321 }
2322
2323 static gboolean
2324 gst_validate_pad_monitor_src_event_func (GstPad * pad, GstObject * parent,
2325     GstEvent * event)
2326 {
2327   GstValidatePadMonitor *pad_monitor =
2328       g_object_get_data ((GObject *) pad, "validate-monitor");
2329   gboolean ret;
2330
2331   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
2332   ret = gst_validate_pad_monitor_src_event_check (pad_monitor, parent, event,
2333       pad_monitor->event_func);
2334   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
2335   return ret;
2336 }
2337
2338 static gboolean
2339 gst_validate_pad_monitor_query_func (GstPad * pad, GstObject * parent,
2340     GstQuery * query)
2341 {
2342   GstValidatePadMonitor *pad_monitor =
2343       g_object_get_data ((GObject *) pad, "validate-monitor");
2344   gboolean ret;
2345
2346   gst_validate_pad_monitor_query_overrides (pad_monitor, query);
2347   ret = pad_monitor->query_func (pad, parent, query);
2348
2349   if (ret) {
2350     switch (GST_QUERY_TYPE (query)) {
2351       case GST_QUERY_ACCEPT_CAPS:
2352       {
2353         gboolean result;
2354
2355         gst_caps_replace (&pad_monitor->last_refused_caps, NULL);
2356         gst_query_parse_accept_caps_result (query, &result);
2357         if (!result) {
2358           GstCaps *refused_caps;
2359
2360           gst_query_parse_accept_caps (query, &refused_caps);
2361           pad_monitor->last_refused_caps = gst_caps_copy (refused_caps);
2362
2363         }
2364
2365         break;
2366       }
2367       case GST_QUERY_CAPS:{
2368         GstCaps *res;
2369         GstCaps *filter;
2370
2371         /* We shouldn't need to lock the parent as this doesn't modify
2372          * other monitors, just does some peer_pad_caps */
2373         GST_VALIDATE_MONITOR_LOCK (pad_monitor);
2374
2375         gst_query_parse_caps (query, &filter);
2376         gst_query_parse_caps_result (query, &res);
2377
2378         gst_caps_replace (&pad_monitor->last_query_res, NULL);
2379         gst_caps_replace (&pad_monitor->last_query_filter, NULL);
2380         pad_monitor->last_query_res =
2381             res ? gst_caps_copy (res) : gst_caps_ref (GST_CAPS_NONE);
2382         pad_monitor->last_query_filter =
2383             filter ? gst_caps_copy (filter) : gst_caps_ref (GST_CAPS_NONE);
2384
2385         if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
2386           gst_validate_pad_monitor_check_caps_fields_proxied (pad_monitor, res,
2387               filter);
2388         }
2389         GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
2390         break;
2391       }
2392       default:
2393         break;
2394     }
2395   }
2396
2397   return ret;
2398 }
2399
2400 static gboolean
2401 gst_validate_pad_monitor_activatemode_func (GstPad * pad, GstObject * parent,
2402     GstPadMode mode, gboolean active)
2403 {
2404   GstValidatePadMonitor *pad_monitor =
2405       g_object_get_data ((GObject *) pad, "validate-monitor");
2406   gboolean ret = TRUE;
2407
2408   /* TODO add overrides for activate func */
2409
2410   if (pad_monitor->activatemode_func)
2411     ret = pad_monitor->activatemode_func (pad, parent, mode, active);
2412   if (ret && active == FALSE) {
2413     GST_VALIDATE_MONITOR_LOCK (pad_monitor);
2414     gst_validate_pad_monitor_flush (pad_monitor);
2415     GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
2416   }
2417
2418   return ret;
2419 }
2420
2421 static GstFlowReturn
2422 gst_validate_pad_get_range_func (GstPad * pad, GstObject * parent,
2423     guint64 offset, guint size, GstBuffer ** buffer)
2424 {
2425   GstValidatePadMonitor *pad_monitor =
2426       g_object_get_data ((GObject *) pad, "validate-monitor");
2427   GstFlowReturn ret;
2428   ret = pad_monitor->getrange_func (pad, parent, offset, size, buffer);
2429   return ret;
2430 }
2431
2432 static gboolean
2433 gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer,
2434     gpointer udata, gboolean pull_mode)
2435 {
2436   GstValidatePadMonitor *monitor = udata;
2437
2438   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor);
2439   GST_VALIDATE_MONITOR_LOCK (monitor);
2440
2441   if (!pull_mode)
2442     gst_validate_pad_monitor_check_discont (monitor, buffer);
2443   gst_validate_pad_monitor_check_first_buffer (monitor, buffer);
2444   gst_validate_pad_monitor_update_buffer_data (monitor, buffer);
2445   gst_validate_pad_monitor_check_eos (monitor, buffer);
2446
2447   if (PAD_PARENT_IS_DECODER (monitor) || PAD_PARENT_IS_ENCODER (monitor)) {
2448     GstClockTime tolerance = 0;
2449
2450     if (monitor->caps_is_audio)
2451       tolerance = AUDIO_TIMESTAMP_TOLERANCE;
2452
2453     gst_validate_pad_monitor_check_buffer_timestamp_in_received_range (monitor,
2454         buffer, tolerance);
2455   }
2456
2457   gst_validate_pad_monitor_check_late_serialized_events (monitor,
2458       GST_BUFFER_TIMESTAMP (buffer));
2459
2460   /* a GstValidatePadMonitor parent must be a GstValidateElementMonitor */
2461   if (PAD_PARENT_IS_DECODER (monitor)) {
2462
2463     /* should not push out of segment data */
2464     if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer)) &&
2465         GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer)) &&
2466         ((!gst_segment_clip (&monitor->segment, monitor->segment.format,
2467                     GST_BUFFER_TIMESTAMP (buffer),
2468                     GST_BUFFER_TIMESTAMP (buffer) +
2469                     GST_BUFFER_DURATION (buffer), NULL, NULL)) ||
2470             /* In the case of raw data, buffers should be strictly contained inside the
2471              * segment */
2472             (monitor->caps_is_raw &&
2473                 GST_BUFFER_PTS (buffer) + GST_BUFFER_DURATION (buffer) <
2474                 monitor->segment.start))
2475         ) {
2476       /* TODO is this a timestamp issue? */
2477       GST_VALIDATE_REPORT (monitor, BUFFER_IS_OUT_OF_SEGMENT,
2478           "buffer is out of segment and shouldn't be pushed. Timestamp: %"
2479           GST_TIME_FORMAT " - Duration: %" GST_TIME_FORMAT ". Range: %"
2480           GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2481           GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
2482           GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)),
2483           GST_TIME_ARGS (monitor->segment.start),
2484           GST_TIME_ARGS (monitor->segment.stop));
2485     }
2486   }
2487
2488   GST_VALIDATE_MONITOR_UNLOCK (monitor);
2489   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (monitor);
2490   gst_validate_pad_monitor_buffer_probe_overrides (monitor, buffer);
2491   return TRUE;
2492 }
2493
2494 static void
2495 gst_validate_pad_monitor_event_probe (GstPad * pad, GstEvent * event,
2496     gpointer udata)
2497 {
2498   GstValidatePadMonitor *monitor = GST_VALIDATE_PAD_MONITOR_CAST (udata);
2499
2500   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor);
2501   GST_VALIDATE_MONITOR_LOCK (monitor);
2502
2503   GST_DEBUG_OBJECT (pad, "event %p %s", event, GST_EVENT_TYPE_NAME (event));
2504
2505   if (GST_EVENT_IS_SERIALIZED (event)) {
2506     gint i;
2507
2508     /* Detect if events the element received are being forwarded in the same order
2509      *
2510      * Several scenarios:
2511      * 1) The element pushes the event as-is
2512      * 2) The element consumes the event and does not forward it
2513      * 3) The element consumes the event and creates another one instead
2514      * 4) The element pushes other serialized event before pushing out the
2515      *    one it received
2516      *
2517      * For each pad we have two lists to track serialized events:
2518      *  1) We received on input and expect to see (serialized_events)
2519      *  2) We received on input but don't expect to see (expired_events)
2520      *
2521      * To detect events that are pushed in a different order from the one they were
2522      * received in we check that:
2523      *
2524      * For each event being outputted:
2525      *   If it is in the expired_events list:
2526      *     RAISE WARNING
2527      *   If it is in the serialized_events list:
2528      *     If there are other events that were received before:
2529      *        Put those events on the expired_events list
2530      *     Remove that event and any previous ones from the serialized_events list
2531      *
2532      * Clear expired events list when flushing or on pad deactivation
2533      *
2534      */
2535
2536     if (g_list_find (monitor->expired_events, event)) {
2537       gchar *event_str = _get_event_string (event);
2538       /* If it's the expired events, we've failed */
2539       GST_WARNING_OBJECT (pad, "Did not expect event %p %s", event,
2540           GST_EVENT_TYPE_NAME (event));
2541       GST_VALIDATE_REPORT (monitor, EVENT_SERIALIZED_OUT_OF_ORDER,
2542           "Serialized event was pushed out of order: %s", event_str);
2543
2544       g_free (event_str);
2545       monitor->expired_events = g_list_remove (monitor->expired_events, event);
2546       gst_event_unref (event);  /* remove the ref that was on the list */
2547     } else if (monitor->serialized_events->len) {
2548       for (i = 0; i < monitor->serialized_events->len; i++) {
2549         SerializedEventData *next_event =
2550             g_ptr_array_index (monitor->serialized_events, i);
2551         GST_DEBUG_OBJECT (pad, "Checking against stored event #%d: %p %s", i,
2552             next_event->event, GST_EVENT_TYPE_NAME (next_event->event));
2553
2554         if (event == next_event->event
2555             || GST_EVENT_TYPE (event) == GST_EVENT_TYPE (next_event->event)) {
2556           /* We have found our event */
2557           GST_DEBUG_OBJECT (pad, "Found matching event");
2558
2559           while (monitor->serialized_events->len > i
2560               && GST_EVENT_TYPE (event) == GST_EVENT_TYPE (next_event->event)) {
2561             /* Swallow all expected events of the same type */
2562             g_ptr_array_remove_index (monitor->serialized_events, i);
2563             next_event = g_ptr_array_index (monitor->serialized_events, i);
2564           }
2565
2566           /* Move all previous events to expired events */
2567           if (G_UNLIKELY (i > 0)) {
2568             GST_DEBUG_OBJECT (pad,
2569                 "Moving previous expected events to expired list");
2570             while (i--) {
2571               next_event = g_ptr_array_index (monitor->serialized_events, 0);
2572               monitor->expired_events =
2573                   g_list_append (monitor->expired_events,
2574                   gst_event_ref (next_event->event));
2575               g_ptr_array_remove_index (monitor->serialized_events, 0);
2576             }
2577           }
2578           debug_pending_event (pad, monitor->serialized_events);
2579           break;
2580         }
2581       }
2582     }
2583   }
2584
2585   /* This so far is just like an event that is flowing downstream,
2586    * so we do the same checks as a sinkpad event handler */
2587   gst_validate_pad_monitor_downstream_event_check (monitor, NULL, event, NULL);
2588   GST_VALIDATE_MONITOR_UNLOCK (monitor);
2589   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (monitor);
2590 }
2591
2592 static GstPadProbeReturn
2593 gst_validate_pad_monitor_pad_probe (GstPad * pad, GstPadProbeInfo * info,
2594     gpointer udata)
2595 {
2596   if (info->type & GST_PAD_PROBE_TYPE_BUFFER)
2597     gst_validate_pad_monitor_buffer_probe (pad, info->data, udata,
2598         GST_PAD_PROBE_INFO_TYPE (info) & GST_PAD_PROBE_TYPE_PULL);
2599   else if (info->type & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM)
2600     gst_validate_pad_monitor_event_probe (pad, info->data, udata);
2601
2602   return GST_PAD_PROBE_OK;
2603 }
2604
2605 static void
2606 gst_validate_pad_monitor_update_caps_info (GstValidatePadMonitor * pad_monitor,
2607     GstCaps * caps)
2608 {
2609   GstStructure *structure;
2610
2611   g_return_if_fail (gst_caps_is_fixed (caps));
2612
2613   pad_monitor->caps_is_audio = FALSE;
2614   pad_monitor->caps_is_video = FALSE;
2615
2616   structure = gst_caps_get_structure (caps, 0);
2617   if (g_str_has_prefix (gst_structure_get_name (structure), "audio/")) {
2618     pad_monitor->caps_is_audio = TRUE;
2619   } else if (g_str_has_prefix (gst_structure_get_name (structure), "video/")) {
2620     pad_monitor->caps_is_video = TRUE;
2621   }
2622
2623   if (g_str_has_prefix (gst_structure_get_name (structure), "audio/x-raw") ||
2624       g_str_has_prefix (gst_structure_get_name (structure), "video/x-raw")) {
2625     pad_monitor->caps_is_raw = TRUE;
2626   } else {
2627     pad_monitor->caps_is_raw = FALSE;
2628   }
2629 }
2630
2631 static void
2632 gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor,
2633     GstCaps * caps)
2634 {
2635   GstStructure *structure;
2636   GstPad *pad =
2637       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
2638           (pad_monitor)));
2639
2640   /* Check if caps are identical to last caps and complain if so
2641    * Only checked for sink pads as src pads might push the same caps
2642    * multiple times during unlinked/autoplugging scenarios */
2643   if (GST_PAD_IS_SINK (pad) && pad_monitor->last_caps
2644       && gst_caps_is_equal (caps, pad_monitor->last_caps)) {
2645     gchar *caps_str = gst_caps_to_string (caps);
2646
2647     GST_VALIDATE_REPORT (pad_monitor, EVENT_CAPS_DUPLICATE, "%s", caps_str);
2648     g_free (caps_str);
2649
2650   }
2651
2652   gst_validate_pad_monitor_check_caps_complete (pad_monitor, caps);
2653
2654   if (caps) {
2655     structure = gst_caps_get_structure (caps, 0);
2656     if (gst_structure_n_fields (pad_monitor->pending_setcaps_fields)) {
2657       gint i;
2658       for (i = 0;
2659           i < gst_structure_n_fields (pad_monitor->pending_setcaps_fields);
2660           i++) {
2661         const gchar *name =
2662             gst_structure_nth_field_name (pad_monitor->pending_setcaps_fields,
2663             i);
2664         const GValue *v = gst_structure_get_value (structure, name);
2665         const GValue *otherv =
2666             gst_structure_get_value (pad_monitor->pending_setcaps_fields, name);
2667
2668         if (v == NULL) {
2669           gchar *caps_str = gst_caps_to_string (caps);
2670
2671           GST_VALIDATE_REPORT (pad_monitor, CAPS_EXPECTED_FIELD_NOT_FOUND,
2672               "Field %s is missing from setcaps caps '%s'", name, caps_str);
2673           g_free (caps_str);
2674         } else if (gst_value_compare (v, otherv) != GST_VALUE_EQUAL) {
2675           gchar *caps_str = gst_caps_to_string (caps),
2676               *pending_setcaps_fields_str =
2677               gst_structure_to_string (pad_monitor->pending_setcaps_fields);
2678
2679
2680           GST_VALIDATE_REPORT (pad_monitor, CAPS_FIELD_UNEXPECTED_VALUE,
2681               "Field %s from setcaps caps '%s' is different "
2682               "from expected value in caps '%s'", name, caps_str,
2683               pending_setcaps_fields_str);
2684
2685           g_free (pending_setcaps_fields_str);
2686           g_free (caps_str);
2687         }
2688       }
2689     }
2690
2691     if (GST_PAD_IS_SINK (pad) &&
2692         gst_validate_pad_monitor_pad_should_proxy_othercaps (pad_monitor)) {
2693       if (_structure_is_video (structure)) {
2694         GST_DEBUG_OBJECT (pad,
2695             "Adding video common pending fields to other pad: %" GST_PTR_FORMAT,
2696             structure);
2697         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2698             structure, "width");
2699         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2700             structure, "height");
2701         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2702             structure, "framerate");
2703         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2704             structure, "pixel-aspect-ratio");
2705       } else if (_structure_is_audio (structure)) {
2706         GST_DEBUG_OBJECT (pad,
2707             "Adding audio common pending fields to other pad: %" GST_PTR_FORMAT,
2708             structure);
2709         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2710             structure, "rate");
2711         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2712             structure, "channels");
2713       }
2714     }
2715   }
2716
2717   gst_structure_free (pad_monitor->pending_setcaps_fields);
2718   pad_monitor->pending_setcaps_fields =
2719       gst_structure_new_empty (PENDING_FIELDS);
2720   gst_object_unref (pad);
2721
2722   gst_validate_pad_monitor_setcaps_overrides (pad_monitor, caps);
2723 }
2724
2725 static void
2726 gst_validate_pad_monitor_setcaps_post (GstValidatePadMonitor * pad_monitor,
2727     GstCaps * caps, gboolean ret)
2728 {
2729   if (!ret)
2730     gst_validate_pad_monitor_otherpad_clear_pending_fields (pad_monitor);
2731   else {
2732     if (pad_monitor->last_caps) {
2733       gst_caps_unref (pad_monitor->last_caps);
2734     }
2735     pad_monitor->last_caps = gst_caps_ref (caps);
2736     gst_validate_pad_monitor_update_caps_info (pad_monitor, caps);
2737   }
2738 }
2739
2740 static gboolean
2741 gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor)
2742 {
2743   GstValidatePadMonitor *pad_monitor = GST_VALIDATE_PAD_MONITOR_CAST (monitor);
2744   GstPad *pad = (gpointer) gst_validate_monitor_get_target (monitor);
2745
2746   if (!GST_IS_PAD (pad)) {
2747     GST_WARNING_OBJECT (monitor, "Trying to create pad monitor with other "
2748         "type of object");
2749     gst_object_unref (pad);
2750     return FALSE;
2751   }
2752
2753   if (g_object_get_data ((GObject *) pad, "validate-monitor")) {
2754     GST_WARNING_OBJECT (pad_monitor,
2755         "Pad already has a validate-monitor associated");
2756     gst_object_unref (pad);
2757     return FALSE;
2758   }
2759
2760   g_object_set_data ((GObject *) pad, "validate-monitor", pad_monitor);
2761
2762   pad_monitor->event_func = GST_PAD_EVENTFUNC (pad);
2763   pad_monitor->event_full_func = GST_PAD_EVENTFULLFUNC (pad);
2764   pad_monitor->query_func = GST_PAD_QUERYFUNC (pad);
2765   pad_monitor->activatemode_func = GST_PAD_ACTIVATEMODEFUNC (pad);
2766   if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
2767
2768     pad_monitor->chain_func = GST_PAD_CHAINFUNC (pad);
2769     if (pad_monitor->chain_func)
2770       gst_pad_set_chain_function (pad, gst_validate_pad_monitor_chain_func);
2771
2772     if (pad_monitor->event_full_func)
2773       gst_pad_set_event_full_function (pad,
2774           gst_validate_pad_monitor_sink_event_full_func);
2775     else
2776       gst_pad_set_event_function (pad,
2777           gst_validate_pad_monitor_sink_event_func);
2778   } else {
2779     pad_monitor->getrange_func = GST_PAD_GETRANGEFUNC (pad);
2780     if (pad_monitor->getrange_func)
2781       gst_pad_set_getrange_function (pad, gst_validate_pad_get_range_func);
2782
2783     gst_pad_set_event_function (pad, gst_validate_pad_monitor_src_event_func);
2784
2785     /* add buffer/event probes */
2786     pad_monitor->pad_probe_id =
2787         gst_pad_add_probe (pad,
2788         GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM |
2789         GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2790         (GstPadProbeCallback) gst_validate_pad_monitor_pad_probe, pad_monitor,
2791         NULL);
2792   }
2793   gst_pad_set_query_function (pad, gst_validate_pad_monitor_query_func);
2794   gst_pad_set_activatemode_function (pad,
2795       gst_validate_pad_monitor_activatemode_func);
2796
2797   gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (monitor),
2798       g_strdup_printf ("%s:%s", GST_DEBUG_PAD_NAME (pad)));
2799
2800   if (G_UNLIKELY (GST_PAD_PARENT (pad) == NULL))
2801     GST_FIXME ("Saw a pad not belonging to any object");
2802
2803   gst_object_unref (pad);
2804   return TRUE;
2805 }