pad-monitor: Reset stream-related variables when deactivating
[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 /* Called when a pad is being flushed */
913 static void
914 gst_validate_pad_monitor_flush (GstValidatePadMonitor * pad_monitor)
915 {
916   /* Note: Keep in the same order as in the GstValidatePadMonitor structure */
917
918   gst_caps_replace (&pad_monitor->last_caps, NULL);
919   pad_monitor->caps_is_audio = pad_monitor->caps_is_video =
920       pad_monitor->caps_is_raw = FALSE;
921
922   pad_monitor->first_buffer = TRUE;
923
924   pad_monitor->has_segment = FALSE;
925   pad_monitor->is_eos = FALSE;
926
927   pad_monitor->pending_buffer_discont = TRUE;
928
929   gst_event_replace (&pad_monitor->expected_segment, NULL);
930   if (pad_monitor->serialized_events->len)
931     g_ptr_array_remove_range (pad_monitor->serialized_events, 0,
932         pad_monitor->serialized_events->len);
933   g_list_free_full (pad_monitor->expired_events,
934       (GDestroyNotify) gst_event_unref);
935   pad_monitor->expired_events = NULL;
936
937   gst_segment_init (&pad_monitor->segment, GST_FORMAT_BYTES);
938   pad_monitor->current_timestamp = GST_CLOCK_TIME_NONE;
939   pad_monitor->current_duration = GST_CLOCK_TIME_NONE;
940
941   pad_monitor->last_flow_return = GST_FLOW_OK;
942
943   pad_monitor->timestamp_range_start = GST_CLOCK_TIME_NONE;
944   pad_monitor->timestamp_range_end = GST_CLOCK_TIME_NONE;
945 }
946
947 /* Called when the pad monitor is initialized or when
948  * the pad is deactivated */
949 static void
950 gst_validate_pad_monitor_reset (GstValidatePadMonitor * pad_monitor)
951 {
952   gst_validate_pad_monitor_flush (pad_monitor);
953
954   /* Note : For the entries that haven't been resetted in _flush(), do
955    * it here and keep in the same order as the GstValidatePadMonitor
956    * structure */
957
958   pad_monitor->pending_flush_stop = FALSE;
959   pad_monitor->pending_newsegment_seqnum = GST_SEQNUM_INVALID;
960   pad_monitor->pending_eos_seqnum = GST_SEQNUM_INVALID;
961
962   pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE;
963
964   if (pad_monitor->pending_setcaps_fields)
965     gst_structure_free (pad_monitor->pending_setcaps_fields);
966   pad_monitor->pending_setcaps_fields =
967       gst_structure_new_empty (PENDING_FIELDS);
968
969   /* FIXME : Why BYTES and not UNDEFINED ? */
970   gst_segment_init (&pad_monitor->segment, GST_FORMAT_BYTES);
971 }
972
973 static void
974 gst_validate_pad_monitor_init (GstValidatePadMonitor * pad_monitor)
975 {
976   pad_monitor->serialized_events =
977       g_ptr_array_new_with_free_func ((GDestroyNotify)
978       _serialized_event_data_free);
979
980   gst_validate_pad_monitor_reset (pad_monitor);
981 }
982
983 /**
984  * gst_validate_pad_monitor_new:
985  * @pad: (transfer none): a #GstPad to run Validate on
986  */
987 GstValidatePadMonitor *
988 gst_validate_pad_monitor_new (GstPad * pad, GstValidateRunner * runner,
989     GstValidateElementMonitor * parent)
990 {
991   GstValidatePadMonitor *monitor = g_object_new (GST_TYPE_VALIDATE_PAD_MONITOR,
992       "object", pad, "validate-runner", runner, "validate-parent",
993       parent, NULL);
994   GstObject *target =
995       gst_validate_monitor_get_target (GST_VALIDATE_MONITOR (monitor));
996
997   if (target == NULL) {
998     g_object_unref (monitor);
999     return NULL;
1000   }
1001
1002   gst_object_unref (target);
1003   return monitor;
1004 }
1005
1006 static GstElement *
1007 gst_validate_pad_monitor_get_element (GstValidateMonitor * monitor)
1008 {
1009   GstPad *pad =
1010       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1011           (monitor)));
1012   GstElement *parent = GST_ELEMENT (gst_pad_get_parent (pad));
1013
1014   gst_object_unref (pad);
1015
1016   return parent;
1017 }
1018
1019 static void
1020 gst_validate_pad_monitor_event_overrides (GstValidatePadMonitor * pad_monitor,
1021     GstEvent * event)
1022 {
1023   GList *iter;
1024
1025   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
1026   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
1027       iter = g_list_next (iter)) {
1028     GstValidateOverride *override = iter->data;
1029
1030     gst_validate_override_event_handler (override,
1031         GST_VALIDATE_MONITOR_CAST (pad_monitor), event);
1032   }
1033   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
1034 }
1035
1036 static void
1037 gst_validate_pad_monitor_buffer_overrides (GstValidatePadMonitor * pad_monitor,
1038     GstBuffer * buffer)
1039 {
1040   GList *iter;
1041
1042   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
1043   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
1044       iter = g_list_next (iter)) {
1045     GstValidateOverride *override = iter->data;
1046
1047     gst_validate_override_buffer_handler (override,
1048         GST_VALIDATE_MONITOR_CAST (pad_monitor), buffer);
1049   }
1050   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
1051 }
1052
1053 static void
1054 gst_validate_pad_monitor_buffer_probe_overrides (GstValidatePadMonitor *
1055     pad_monitor, GstBuffer * buffer)
1056 {
1057   GList *iter;
1058
1059   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
1060   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
1061       iter = g_list_next (iter)) {
1062     GstValidateOverride *override = iter->data;
1063
1064     gst_validate_override_buffer_probe_handler (override,
1065         GST_VALIDATE_MONITOR_CAST (pad_monitor), buffer);
1066   }
1067   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
1068 }
1069
1070 static void
1071 gst_validate_pad_monitor_query_overrides (GstValidatePadMonitor * pad_monitor,
1072     GstQuery * query)
1073 {
1074   GList *iter;
1075
1076   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
1077   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
1078       iter = g_list_next (iter)) {
1079     GstValidateOverride *override = iter->data;
1080
1081     gst_validate_override_query_handler (override,
1082         GST_VALIDATE_MONITOR_CAST (pad_monitor), query);
1083   }
1084   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
1085 }
1086
1087 static void
1088 gst_validate_pad_monitor_setcaps_overrides (GstValidatePadMonitor * pad_monitor,
1089     GstCaps * caps)
1090 {
1091   GList *iter;
1092
1093   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
1094   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
1095       iter = g_list_next (iter)) {
1096     GstValidateOverride *override = iter->data;
1097
1098     gst_validate_override_setcaps_handler (override,
1099         GST_VALIDATE_MONITOR_CAST (pad_monitor), caps);
1100   }
1101   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
1102 }
1103
1104 /* FIXME : This is a bit dubious, what's the point of this check ? */
1105 static gboolean
1106 gst_validate_pad_monitor_timestamp_is_in_received_range (GstValidatePadMonitor *
1107     monitor, GstClockTime ts, GstClockTime tolerance)
1108 {
1109   GstPad *pad =
1110       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1111           (monitor)));
1112
1113   GST_DEBUG_OBJECT (pad,
1114       "Checking if timestamp %" GST_TIME_FORMAT " is in range: %"
1115       GST_TIME_FORMAT " - %" GST_TIME_FORMAT " for pad "
1116       "%s:%s with tolerance: %" GST_TIME_FORMAT, GST_TIME_ARGS (ts),
1117       GST_TIME_ARGS (monitor->timestamp_range_start),
1118       GST_TIME_ARGS (monitor->timestamp_range_end), GST_DEBUG_PAD_NAME (pad),
1119       GST_TIME_ARGS (tolerance));
1120   gst_object_unref (pad);
1121
1122   return !GST_CLOCK_TIME_IS_VALID (monitor->timestamp_range_start) ||
1123       !GST_CLOCK_TIME_IS_VALID (monitor->timestamp_range_end) ||
1124       ((monitor->timestamp_range_start >= tolerance ?
1125           monitor->timestamp_range_start - tolerance : 0) <= ts
1126       && (ts >= tolerance ? ts - tolerance : 0) <=
1127       monitor->timestamp_range_end);
1128 }
1129
1130 /* Iterates over internal links (sinkpads) to check that this buffer has
1131  * a timestamp that is in the range of the lastly received buffers */
1132 static void
1133     gst_validate_pad_monitor_check_buffer_timestamp_in_received_range
1134     (GstValidatePadMonitor * monitor, GstBuffer * buffer,
1135     GstClockTime tolerance)
1136 {
1137   GstClockTime ts;
1138   GstClockTime ts_end;
1139   GstIterator *iter;
1140   gboolean has_one = FALSE;
1141   gboolean found = FALSE;
1142   gboolean done;
1143   GstPad *otherpad;
1144   GstValidatePadMonitor *othermonitor;
1145   GstPad *pad =
1146       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1147           (monitor)));
1148
1149   if (!GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))
1150       || !GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) {
1151     GST_DEBUG_OBJECT (pad,
1152         "Can't check buffer timestamps range as "
1153         "buffer has no valid timestamp/duration");
1154     goto done;
1155   }
1156
1157   ts = GST_BUFFER_TIMESTAMP (buffer);
1158   ts_end = ts + GST_BUFFER_DURATION (buffer);
1159
1160   iter = gst_pad_iterate_internal_links (pad);
1161
1162   if (iter == NULL) {
1163     GST_WARNING_OBJECT (pad, "No iterator available");
1164     goto done;
1165   }
1166
1167   done = FALSE;
1168   while (!done) {
1169     GValue value = { 0, };
1170     switch (gst_iterator_next (iter, &value)) {
1171       case GST_ITERATOR_OK:
1172         otherpad = g_value_get_object (&value);
1173         GST_DEBUG_OBJECT (pad, "Checking pad %s:%s input timestamps",
1174             GST_DEBUG_PAD_NAME (otherpad));
1175         othermonitor =
1176             g_object_get_data ((GObject *) otherpad, "validate-monitor");
1177         GST_VALIDATE_MONITOR_LOCK (othermonitor);
1178         if (gst_validate_pad_monitor_timestamp_is_in_received_range
1179             (othermonitor, ts, tolerance)
1180             &&
1181             gst_validate_pad_monitor_timestamp_is_in_received_range
1182             (othermonitor, ts_end, tolerance)) {
1183           done = TRUE;
1184           found = TRUE;
1185         }
1186         GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1187         g_value_reset (&value);
1188         has_one = TRUE;
1189         break;
1190       case GST_ITERATOR_RESYNC:
1191         gst_iterator_resync (iter);
1192         has_one = FALSE;
1193         found = FALSE;
1194         break;
1195       case GST_ITERATOR_ERROR:
1196         GST_WARNING_OBJECT (pad, "Internal links pad iteration error");
1197         done = TRUE;
1198         break;
1199       case GST_ITERATOR_DONE:
1200         done = TRUE;
1201         break;
1202     }
1203   }
1204   gst_iterator_free (iter);
1205
1206   if (!has_one) {
1207     GST_DEBUG_OBJECT (pad, "Skipping timestamp in range check as no "
1208         "internal linked pad was found");
1209     goto done;
1210   }
1211   if (!found) {
1212     GST_VALIDATE_REPORT (monitor, BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE,
1213         "Timestamp %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT
1214         " is out of range of received input", GST_TIME_ARGS (ts),
1215         GST_TIME_ARGS (ts_end));
1216   }
1217 done:
1218   if (pad)
1219     gst_object_unref (pad);
1220 }
1221
1222 static void
1223 gst_validate_pad_monitor_check_discont (GstValidatePadMonitor * pad_monitor,
1224     GstBuffer * buffer)
1225 {
1226   if (pad_monitor->pending_buffer_discont) {
1227     if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT))
1228       GST_VALIDATE_REPORT (pad_monitor, BUFFER_MISSING_DISCONT,
1229           "Buffer is missing a DISCONT flag");
1230     pad_monitor->pending_buffer_discont = FALSE;
1231   }
1232 }
1233
1234 static void
1235 gst_validate_pad_monitor_check_first_buffer (GstValidatePadMonitor *
1236     pad_monitor, GstBuffer * buffer)
1237 {
1238   GstPad *pad =
1239       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1240           (pad_monitor)));
1241
1242   if (G_UNLIKELY (pad_monitor->first_buffer)) {
1243     pad_monitor->first_buffer = FALSE;
1244
1245     if (!pad_monitor->has_segment && PAD_IS_IN_PUSH_MODE (pad)) {
1246       GST_VALIDATE_REPORT (pad_monitor, BUFFER_BEFORE_SEGMENT,
1247           "Received buffer before Segment event");
1248     }
1249
1250     GST_DEBUG_OBJECT (pad,
1251         "Checking first buffer (pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
1252         ")", GST_TIME_ARGS (GST_BUFFER_PTS (buffer)),
1253         GST_TIME_ARGS (GST_BUFFER_DTS (buffer)));
1254
1255   }
1256
1257   gst_object_unref (pad);
1258 }
1259
1260 static void
1261 gst_validate_pad_monitor_check_eos (GstValidatePadMonitor *
1262     pad_monitor, GstBuffer * buffer)
1263 {
1264   if (G_UNLIKELY (pad_monitor->is_eos)) {
1265     GST_VALIDATE_REPORT (pad_monitor, BUFFER_AFTER_EOS,
1266         "Received buffer %" GST_PTR_FORMAT " after EOS", buffer);
1267   }
1268 }
1269
1270 static void
1271 gst_validate_pad_monitor_update_buffer_data (GstValidatePadMonitor *
1272     pad_monitor, GstBuffer * buffer)
1273 {
1274   GstPad *pad =
1275       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1276           (pad_monitor)));
1277   pad_monitor->current_timestamp = GST_BUFFER_TIMESTAMP (buffer);
1278   pad_monitor->current_duration = GST_BUFFER_DURATION (buffer);
1279   if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) {
1280     if (GST_CLOCK_TIME_IS_VALID (pad_monitor->timestamp_range_start)) {
1281       pad_monitor->timestamp_range_start =
1282           MIN (pad_monitor->timestamp_range_start,
1283           GST_BUFFER_TIMESTAMP (buffer));
1284     } else {
1285       pad_monitor->timestamp_range_start = GST_BUFFER_TIMESTAMP (buffer);
1286     }
1287
1288     if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) {
1289       GstClockTime endts =
1290           GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer);
1291       if (GST_CLOCK_TIME_IS_VALID (pad_monitor->timestamp_range_end)) {
1292         pad_monitor->timestamp_range_end =
1293             MAX (pad_monitor->timestamp_range_end, endts);
1294       } else {
1295         pad_monitor->timestamp_range_end = endts;
1296       }
1297     }
1298   }
1299   GST_DEBUG_OBJECT (pad, "Current stored range: %" GST_TIME_FORMAT
1300       " - %" GST_TIME_FORMAT,
1301       GST_TIME_ARGS (pad_monitor->timestamp_range_start),
1302       GST_TIME_ARGS (pad_monitor->timestamp_range_end));
1303
1304   gst_object_unref (pad);
1305 }
1306
1307 static GstFlowReturn
1308 _combine_flows (GstFlowReturn ret1, GstFlowReturn ret2)
1309 {
1310   if (ret1 == ret2)
1311     return ret1;
1312   if (ret1 <= GST_FLOW_NOT_NEGOTIATED)
1313     return ret1;
1314   if (ret2 <= GST_FLOW_NOT_NEGOTIATED)
1315     return ret2;
1316   if (ret1 == GST_FLOW_FLUSHING || ret2 == GST_FLOW_FLUSHING)
1317     return GST_FLOW_FLUSHING;
1318   if (ret1 == GST_FLOW_OK || ret2 == GST_FLOW_OK)
1319     return GST_FLOW_OK;
1320   return ret2;
1321 }
1322
1323 static void
1324 gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor *
1325     monitor, GstObject * parent, GstFlowReturn ret)
1326 {
1327   GstIterator *iter;
1328   gboolean done;
1329   GstPad *otherpad;
1330   GstPad *peerpad;
1331   GstValidatePadMonitor *othermonitor;
1332   GstFlowReturn aggregated = GST_FLOW_NOT_LINKED;
1333   gboolean found_a_pad = FALSE;
1334   GstPad *pad =
1335       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1336           (monitor)));
1337
1338   iter = gst_pad_iterate_internal_links (pad);
1339   done = FALSE;
1340   while (!done) {
1341     GValue value = { 0, };
1342     switch (gst_iterator_next (iter, &value)) {
1343       case GST_ITERATOR_OK:
1344         otherpad = g_value_get_object (&value);
1345         peerpad = gst_pad_get_peer (otherpad);
1346         if (peerpad) {
1347           othermonitor =
1348               g_object_get_data ((GObject *) peerpad, "validate-monitor");
1349           if (othermonitor) {
1350             found_a_pad = TRUE;
1351             GST_VALIDATE_MONITOR_LOCK (othermonitor);
1352             aggregated =
1353                 _combine_flows (aggregated, othermonitor->last_flow_return);
1354             GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1355           }
1356
1357           gst_object_unref (peerpad);
1358         }
1359         g_value_reset (&value);
1360         break;
1361       case GST_ITERATOR_RESYNC:
1362         gst_iterator_resync (iter);
1363         break;
1364       case GST_ITERATOR_ERROR:
1365         GST_WARNING_OBJECT (pad, "Internal links pad iteration error");
1366         done = TRUE;
1367         break;
1368       case GST_ITERATOR_DONE:
1369         done = TRUE;
1370         break;
1371     }
1372   }
1373   gst_iterator_free (iter);
1374   if (!found_a_pad) {
1375     /* no peer pad found, nothing to do */
1376     goto done;
1377   }
1378   if (aggregated == GST_FLOW_OK || aggregated == GST_FLOW_EOS) {
1379     GstState state, pending;
1380
1381     /* those are acceptable situations */
1382     if (GST_PAD_IS_FLUSHING (pad) && ret == GST_FLOW_FLUSHING) {
1383       /* pad is flushing, always acceptable to return flushing */
1384       goto done;
1385     }
1386
1387     gst_element_get_state (GST_ELEMENT (parent), &state, &pending, 0);
1388     if (ret == GST_FLOW_FLUSHING && (state < GST_STATE_PAUSED
1389             || pending < GST_STATE_PAUSED)) {
1390       /* Element is being teared down, accept FLOW_FLUSHING */
1391
1392       goto done;
1393     }
1394
1395     if (monitor->is_eos && ret == GST_FLOW_EOS) {
1396       /* this element received eos and returned eos */
1397       goto done;
1398     }
1399
1400     if (PAD_PARENT_IS_DEMUXER (monitor) && ret == GST_FLOW_EOS) {
1401       /* a demuxer can return EOS when the samples end */
1402       goto done;
1403     }
1404   }
1405
1406   if (aggregated != ret) {
1407     GST_VALIDATE_REPORT (monitor, WRONG_FLOW_RETURN,
1408         "Wrong combined flow return %s(%d). Expected: %s(%d)",
1409         gst_flow_get_name (ret), ret, gst_flow_get_name (aggregated),
1410         aggregated);
1411   }
1412
1413 done:
1414   gst_object_unref (pad);
1415 }
1416
1417 static void
1418     gst_validate_pad_monitor_otherpad_add_pending_serialized_event
1419     (GstValidatePadMonitor * monitor, GstEvent * event, GstClockTime last_ts)
1420 {
1421   GstIterator *iter;
1422   gboolean done;
1423   GstPad *otherpad;
1424   GstValidatePadMonitor *othermonitor;
1425   GstPad *pad;
1426
1427
1428   if (!GST_EVENT_IS_SERIALIZED (event))
1429     return;
1430
1431   pad =
1432       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1433           (monitor)));
1434   iter = gst_pad_iterate_internal_links (pad);
1435   if (iter == NULL) {
1436     /* inputselector will return NULL if the sinkpad is not the active one .... */
1437     GST_FIXME_OBJECT (pad, "No iterator");
1438     gst_object_unref (pad);
1439     return;
1440   }
1441
1442   done = FALSE;
1443   while (!done) {
1444     GValue value = { 0, };
1445     switch (gst_iterator_next (iter, &value)) {
1446       case GST_ITERATOR_OK:
1447         otherpad = g_value_get_object (&value);
1448         othermonitor =
1449             g_object_get_data ((GObject *) otherpad, "validate-monitor");
1450         if (othermonitor) {
1451           SerializedEventData *data = g_slice_new0 (SerializedEventData);
1452           data->timestamp = last_ts;
1453           data->event = gst_event_ref (event);
1454           GST_VALIDATE_MONITOR_LOCK (othermonitor);
1455           GST_DEBUG_OBJECT (pad, "Storing for pad %s:%s event %p %s",
1456               GST_DEBUG_PAD_NAME (otherpad), event,
1457               GST_EVENT_TYPE_NAME (event));
1458           g_ptr_array_add (othermonitor->serialized_events, data);
1459           debug_pending_event (otherpad, othermonitor->serialized_events);
1460           GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1461         }
1462         g_value_reset (&value);
1463         break;
1464       case GST_ITERATOR_RESYNC:
1465         gst_iterator_resync (iter);
1466         break;
1467       case GST_ITERATOR_ERROR:
1468         GST_WARNING_OBJECT (pad, "Internal links pad iteration error");
1469         done = TRUE;
1470         break;
1471       case GST_ITERATOR_DONE:
1472         done = TRUE;
1473         break;
1474     }
1475   }
1476   gst_iterator_free (iter);
1477   gst_object_unref (pad);
1478 }
1479
1480 static void
1481 gst_validate_pad_monitor_otherpad_add_pending_field (GstValidatePadMonitor *
1482     monitor, GstStructure * structure, const gchar * field)
1483 {
1484   GstIterator *iter;
1485   gboolean done;
1486   GstPad *otherpad;
1487   GstValidatePadMonitor *othermonitor;
1488   const GValue *v;
1489   GstPad *pad;
1490
1491   v = gst_structure_get_value (structure, field);
1492   pad =
1493       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1494           (monitor)));
1495
1496   if (v == NULL) {
1497     GST_DEBUG_OBJECT (pad, "Not adding pending field %s as it isn't "
1498         "present on structure %" GST_PTR_FORMAT, field, structure);
1499     gst_object_unref (pad);
1500     return;
1501   }
1502
1503   iter = gst_pad_iterate_internal_links (pad);
1504   done = FALSE;
1505   while (!done) {
1506     GValue value = { 0, };
1507     switch (gst_iterator_next (iter, &value)) {
1508       case GST_ITERATOR_OK:
1509         otherpad = g_value_get_object (&value);
1510         othermonitor =
1511             g_object_get_data ((GObject *) otherpad, "validate-monitor");
1512         if (othermonitor) {
1513           GST_VALIDATE_MONITOR_LOCK (othermonitor);
1514           g_assert (othermonitor->pending_setcaps_fields != NULL);
1515           gst_structure_set_value (othermonitor->pending_setcaps_fields,
1516               field, v);
1517           GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1518         }
1519         g_value_reset (&value);
1520         break;
1521       case GST_ITERATOR_RESYNC:
1522         gst_iterator_resync (iter);
1523         break;
1524       case GST_ITERATOR_ERROR:
1525         GST_WARNING_OBJECT (pad, "Internal links pad iteration error");
1526         done = TRUE;
1527         break;
1528       case GST_ITERATOR_DONE:
1529         done = TRUE;
1530         break;
1531     }
1532   }
1533   gst_iterator_free (iter);
1534   gst_object_unref (pad);
1535 }
1536
1537 static void
1538 gst_validate_pad_monitor_otherpad_clear_pending_fields (GstValidatePadMonitor *
1539     monitor)
1540 {
1541   GstIterator *iter;
1542   gboolean done;
1543   GstPad *otherpad;
1544   GstValidatePadMonitor *othermonitor;
1545
1546   GstPad *pad =
1547       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1548           (monitor)));
1549
1550   iter = gst_pad_iterate_internal_links (pad);
1551   if (iter == NULL) {
1552     gst_object_unref (pad);
1553     GST_DEBUG_OBJECT (monitor, "No internally linked pad");
1554
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         othermonitor =
1565             g_object_get_data ((GObject *) otherpad, "validate-monitor");
1566         if (othermonitor) {
1567           GST_VALIDATE_MONITOR_LOCK (othermonitor);
1568           g_assert (othermonitor->pending_setcaps_fields != NULL);
1569           gst_structure_free (othermonitor->pending_setcaps_fields);
1570           othermonitor->pending_setcaps_fields =
1571               gst_structure_new_empty (PENDING_FIELDS);
1572           GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1573         }
1574         g_value_reset (&value);
1575         break;
1576       case GST_ITERATOR_RESYNC:
1577         gst_iterator_resync (iter);
1578         break;
1579       case GST_ITERATOR_ERROR:
1580         GST_WARNING_OBJECT (pad, "Internal links pad iteration error");
1581         done = TRUE;
1582         break;
1583       case GST_ITERATOR_DONE:
1584         done = TRUE;
1585         break;
1586     }
1587   }
1588   gst_object_unref (pad);
1589   gst_iterator_free (iter);
1590 }
1591
1592 static void
1593 gst_validate_pad_monitor_add_expected_newsegment (GstValidatePadMonitor *
1594     monitor, GstEvent * event)
1595 {
1596   GstIterator *iter;
1597   gboolean done;
1598   GstPad *otherpad;
1599   GstValidatePadMonitor *othermonitor;
1600   GstPad *pad =
1601       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1602           (monitor)));
1603
1604   iter = gst_pad_iterate_internal_links (pad);
1605   if (iter == NULL) {
1606     GST_DEBUG_OBJECT (monitor, "No internally linked pad");
1607     gst_object_unref (pad);
1608     return;
1609   }
1610
1611   done = FALSE;
1612   while (!done) {
1613     GValue value = { 0, };
1614     switch (gst_iterator_next (iter, &value)) {
1615       case GST_ITERATOR_OK:
1616         otherpad = g_value_get_object (&value);
1617         if (!otherpad)
1618           continue;
1619         othermonitor =
1620             g_object_get_data ((GObject *) otherpad, "validate-monitor");
1621         GST_VALIDATE_MONITOR_LOCK (othermonitor);
1622         gst_event_replace (&othermonitor->expected_segment, event);
1623         GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1624         g_value_reset (&value);
1625         break;
1626       case GST_ITERATOR_RESYNC:
1627         gst_iterator_resync (iter);
1628         break;
1629       case GST_ITERATOR_ERROR:
1630         GST_WARNING_OBJECT (pad, "Internal links pad iteration error");
1631         done = TRUE;
1632         break;
1633       case GST_ITERATOR_DONE:
1634         done = TRUE;
1635         break;
1636     }
1637   }
1638   gst_iterator_free (iter);
1639   gst_object_unref (pad);
1640 }
1641
1642 /* common checks for both sink and src event functions */
1643 static void
1644 gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor *
1645     pad_monitor, GstEvent * event)
1646 {
1647   guint32 seqnum = gst_event_get_seqnum (event);
1648
1649   if (seqnum == GST_SEQNUM_INVALID)
1650     GST_VALIDATE_REPORT (pad_monitor, EVENT_INVALID_SEQNUM,
1651         "Event %p (%s) has an invalid SEQNUM", event,
1652         GST_EVENT_TYPE_NAME (event));
1653
1654   switch (GST_EVENT_TYPE (event)) {
1655     case GST_EVENT_FLUSH_START:
1656     {
1657       if (pad_monitor->pending_flush_start_seqnum != GST_SEQNUM_INVALID) {
1658         if (seqnum == pad_monitor->pending_flush_start_seqnum) {
1659           pad_monitor->pending_flush_start_seqnum = GST_SEQNUM_INVALID;
1660         } else {
1661           GST_VALIDATE_REPORT (pad_monitor, FLUSH_START_HAS_WRONG_SEQNUM,
1662               "Got: %u Expected: %u", seqnum,
1663               pad_monitor->pending_flush_start_seqnum);
1664         }
1665       }
1666
1667       if (pad_monitor->pending_flush_stop) {
1668         GST_VALIDATE_REPORT (pad_monitor, EVENT_FLUSH_START_UNEXPECTED,
1669             "Received flush-start from when flush-stop was expected");
1670       }
1671       pad_monitor->pending_flush_stop = TRUE;
1672     }
1673       break;
1674     case GST_EVENT_FLUSH_STOP:
1675     {
1676       if (pad_monitor->pending_flush_stop_seqnum != GST_SEQNUM_INVALID) {
1677         if (seqnum == pad_monitor->pending_flush_stop_seqnum) {
1678           pad_monitor->pending_flush_stop_seqnum = GST_SEQNUM_INVALID;
1679         } else {
1680           GST_VALIDATE_REPORT (pad_monitor, FLUSH_STOP_HAS_WRONG_SEQNUM,
1681               "Got: %u Expected: %u", seqnum,
1682               pad_monitor->pending_flush_stop_seqnum);
1683         }
1684       }
1685
1686       pad_monitor->pending_newsegment_seqnum = seqnum;
1687       pad_monitor->pending_eos_seqnum = seqnum;
1688
1689       if (!pad_monitor->pending_flush_stop) {
1690         gchar *event_str = _get_event_string (event);
1691
1692         GST_VALIDATE_REPORT (pad_monitor, EVENT_FLUSH_STOP_UNEXPECTED,
1693             "Unexpected flush-stop %s", event_str);
1694         g_free (event_str);
1695       }
1696       pad_monitor->pending_flush_stop = FALSE;
1697
1698       /* Buffers following a FLUSH should have the DISCONT flag set */
1699       pad_monitor->pending_buffer_discont = TRUE;
1700
1701       /* cleanup our data */
1702       gst_validate_pad_monitor_flush (pad_monitor);
1703     }
1704       break;
1705     default:
1706       break;
1707   }
1708 }
1709
1710 static void
1711 mark_pads_eos (GstValidatePadMonitor * pad_monitor)
1712 {
1713   GstValidatePadMonitor *peer_monitor;
1714   GstPad *real_peer;
1715   GstPad *pad =
1716       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1717           (pad_monitor)));
1718   GstPad *peer = gst_pad_get_peer (pad);
1719
1720   gst_object_unref (pad);
1721   pad_monitor->is_eos = TRUE;
1722   if (peer) {
1723     real_peer = _get_actual_pad (peer);
1724     peer_monitor =
1725         g_object_get_data ((GObject *) real_peer, "validate-monitor");
1726     if (peer_monitor)
1727       peer_monitor->is_eos = TRUE;
1728     gst_object_unref (peer);
1729     gst_object_unref (real_peer);
1730   }
1731 }
1732
1733 static inline gboolean
1734 _should_check_buffers (GstValidatePadMonitor * pad_monitor,
1735     gboolean force_checks)
1736 {
1737   GstPad *pad =
1738       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1739           (pad_monitor)));
1740   GstValidateMonitor *monitor = GST_VALIDATE_MONITOR (pad_monitor);
1741
1742   if (pad_monitor->first_buffer || force_checks) {
1743     if (pad_monitor->segment.rate != 1.0) {
1744       GST_INFO_OBJECT (pad_monitor, "We do not support buffer checking"
1745           " for trick modes");
1746
1747       pad_monitor->check_buffers = FALSE;
1748     } else if (!PAD_PARENT_IS_DECODER (pad_monitor)) {
1749       GST_DEBUG_OBJECT (pad, "Not on a decoder => no buffer checking");
1750
1751       pad_monitor->check_buffers = FALSE;
1752     } else if (GST_PAD_DIRECTION (pad) != GST_PAD_SINK) {
1753       GST_DEBUG_OBJECT (pad, "Not a sinkpad => no buffer checking");
1754
1755       pad_monitor->check_buffers = FALSE;
1756     } else if (!pad_monitor->caps_is_video) {
1757       GST_DEBUG_OBJECT (pad, "Not working with video => no buffer checking");
1758
1759       pad_monitor->check_buffers = FALSE;
1760     } else if (monitor->media_descriptor == NULL) {
1761       GST_DEBUG_OBJECT (pad, "No media_descriptor set => no buffer checking");
1762
1763       pad_monitor->check_buffers = FALSE;
1764     } else
1765         if (!gst_validate_media_descriptor_detects_frames
1766         (monitor->media_descriptor)) {
1767       GST_DEBUG_OBJECT (pad,
1768           "No frame detection media descriptor => not buffer checking");
1769       pad_monitor->check_buffers = FALSE;
1770     } else if (pad_monitor->all_bufs == NULL &&
1771         !gst_validate_media_descriptor_get_buffers (monitor->media_descriptor,
1772             pad, NULL, &pad_monitor->all_bufs)) {
1773
1774       GST_INFO_OBJECT (monitor,
1775           "The MediaInfo is marked as detecting frame, but getting frames"
1776           " from pad %" GST_PTR_FORMAT " did not work (some format conversion"
1777           " might be happening)", pad);
1778
1779       pad_monitor->check_buffers = FALSE;
1780     } else {
1781       if (!pad_monitor->current_buf)
1782         pad_monitor->current_buf = pad_monitor->all_bufs;
1783       pad_monitor->check_buffers = TRUE;
1784     }
1785   }
1786   gst_object_unref (pad);
1787
1788   return pad_monitor->check_buffers;
1789 }
1790
1791 static void
1792 gst_validate_monitor_find_next_buffer (GstValidatePadMonitor * pad_monitor)
1793 {
1794   GList *tmp;
1795   gboolean passed_start = FALSE;
1796
1797   if (!_should_check_buffers (pad_monitor, TRUE))
1798     return;
1799
1800   for (tmp = g_list_last (pad_monitor->all_bufs); tmp; tmp = tmp->prev) {
1801     GstBuffer *cbuf = (GstBuffer *) tmp->data;
1802     GstClockTime ts =
1803         GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DTS (cbuf)) ? GST_BUFFER_DTS (cbuf)
1804         : GST_BUFFER_PTS (cbuf);
1805
1806     if (!GST_CLOCK_TIME_IS_VALID (ts))
1807       continue;
1808
1809     if (ts <= pad_monitor->segment.start)
1810       passed_start = TRUE;
1811
1812     if (!passed_start)
1813       continue;
1814
1815     if (!GST_BUFFER_FLAG_IS_SET (cbuf, GST_BUFFER_FLAG_DELTA_UNIT)) {
1816       break;
1817     }
1818   }
1819
1820   if (tmp == NULL)
1821     pad_monitor->current_buf = pad_monitor->all_bufs;
1822   else
1823     pad_monitor->current_buf = tmp;
1824 }
1825
1826 /* Checks whether a segment is just an update of another,
1827  * That is to say that only the base and offset field differ and all
1828  * other fields are identical */
1829 static gboolean
1830 is_segment_update (GstSegment * a, const GstSegment * b)
1831 {
1832   /* Note : We never care about the position field, it is only
1833    * used for internal usage by elements */
1834   if (a->rate == b->rate &&
1835       a->applied_rate == b->applied_rate &&
1836       a->format == b->format && a->time == b->time) {
1837     /* Changes in base/offset are considered updates */
1838     /* Updating the end position of a segment is an update */
1839     /* Updating the duration of a segment is an update */
1840     if (a->rate > 0.0) {
1841       if (a->start == b->start)
1842         return TRUE;
1843     } else {
1844       if (a->stop == b->stop)
1845         return TRUE;
1846     }
1847   }
1848   return FALSE;
1849 }
1850
1851 static GstFlowReturn
1852 gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor *
1853     pad_monitor, GstObject * parent, GstEvent * event,
1854     GstPadEventFunction handler)
1855 {
1856   GstFlowReturn ret = GST_FLOW_OK;
1857   const GstSegment *segment;
1858   guint32 seqnum = gst_event_get_seqnum (event);
1859   GstPad *pad =
1860       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
1861           (pad_monitor)));
1862
1863   gst_validate_pad_monitor_common_event_check (pad_monitor, event);
1864
1865   /* pre checks */
1866   switch (GST_EVENT_TYPE (event)) {
1867     case GST_EVENT_STREAM_START:
1868       /* Buffers following a STREAM_START should have the DISCONT flag set */
1869       pad_monitor->pending_buffer_discont = TRUE;
1870       break;
1871     case GST_EVENT_SEGMENT:
1872       /* parse segment data to be used if event is handled */
1873       gst_event_parse_segment (event, &segment);
1874
1875       GST_DEBUG_OBJECT (pad, "Got segment %" GST_SEGMENT_FORMAT, segment);
1876
1877       /* Reset expected flush start/stop values, we have a segment */
1878       pad_monitor->pending_flush_start_seqnum = GST_SEQNUM_INVALID;
1879       pad_monitor->pending_flush_stop_seqnum = GST_SEQNUM_INVALID;
1880
1881       if (pad_monitor->pending_newsegment_seqnum != GST_SEQNUM_INVALID) {
1882         if (pad_monitor->pending_newsegment_seqnum == seqnum) {
1883           pad_monitor->pending_newsegment_seqnum = GST_SEQNUM_INVALID;
1884           if (GST_CLOCK_TIME_IS_VALID (pad_monitor->pending_seek_accurate_time)) {
1885             if (segment->time == pad_monitor->pending_seek_accurate_time) {
1886               pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE;
1887             } else {
1888               GST_VALIDATE_REPORT (pad_monitor, SEGMENT_HAS_WRONG_START,
1889                   "After an accurate seek, got: %" GST_TIME_FORMAT
1890                   " Expected: %" GST_TIME_FORMAT, GST_TIME_ARGS (segment->time),
1891                   GST_TIME_ARGS (pad_monitor->pending_seek_accurate_time));
1892             }
1893           }
1894         } else {
1895           GST_VALIDATE_REPORT (pad_monitor, SEGMENT_HAS_WRONG_SEQNUM,
1896               "Got: %u Expected: %u", seqnum, pad_monitor->pending_eos_seqnum);
1897         }
1898       }
1899
1900       pad_monitor->pending_eos_seqnum = seqnum;
1901
1902       if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
1903         gst_validate_pad_monitor_add_expected_newsegment (pad_monitor, event);
1904       } else {
1905         /* check if this segment is the expected one */
1906         if (pad_monitor->expected_segment) {
1907           const GstSegment *exp_segment;
1908
1909           if (pad_monitor->expected_segment != event) {
1910             gst_event_parse_segment (pad_monitor->expected_segment,
1911                 &exp_segment);
1912             if (segment->format == exp_segment->format) {
1913               if ((exp_segment->rate * exp_segment->applied_rate !=
1914                       segment->rate * segment->applied_rate))
1915                 GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH,
1916                     "Rate * applied_rate %f != expected %f",
1917                     segment->rate * segment->applied_rate,
1918                     exp_segment->rate * exp_segment->applied_rate);
1919               if (exp_segment->start != segment->start)
1920                 GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH,
1921                     "Start %" GST_TIME_FORMAT " != expected %" GST_TIME_FORMAT,
1922                     GST_TIME_ARGS (segment->start),
1923                     GST_TIME_ARGS (exp_segment->start));
1924               if (exp_segment->stop != segment->stop)
1925                 GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH,
1926                     "Stop %" GST_TIME_FORMAT " != expected %" GST_TIME_FORMAT,
1927                     GST_TIME_ARGS (segment->stop),
1928                     GST_TIME_ARGS (exp_segment->stop));
1929               if (exp_segment->position != segment->position)
1930                 GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH,
1931                     "Position %" GST_TIME_FORMAT " != expected %"
1932                     GST_TIME_FORMAT, GST_TIME_ARGS (segment->position),
1933                     GST_TIME_ARGS (exp_segment->position));
1934             }
1935           }
1936           gst_event_replace (&pad_monitor->expected_segment, NULL);
1937         }
1938       }
1939       break;
1940     case GST_EVENT_CAPS:{
1941       GstCaps *caps;
1942
1943       gst_event_parse_caps (event, &caps);
1944       gst_validate_pad_monitor_setcaps_pre (pad_monitor, caps);
1945       break;
1946     }
1947     case GST_EVENT_EOS:
1948       pad_monitor->is_eos = TRUE;
1949       /* FIXME : This feels and looks wrong ... */
1950       if (pad_monitor->pending_eos_seqnum == GST_SEQNUM_INVALID) {
1951         GST_VALIDATE_REPORT (pad_monitor, EVENT_EOS_WITHOUT_SEGMENT,
1952             "EOS %" GST_PTR_FORMAT " received before a segment was received",
1953             event);
1954       } else if (pad_monitor->pending_eos_seqnum != seqnum) {
1955         GST_VALIDATE_REPORT (pad_monitor, EOS_HAS_WRONG_SEQNUM,
1956             "Got: %u. Expected: %u", seqnum, pad_monitor->pending_eos_seqnum);
1957       }
1958
1959       /*
1960        * TODO add end of stream checks for
1961        *  - events not pushed
1962        *  - buffer data not pushed
1963        *  - pending events not received
1964        */
1965       break;
1966
1967       /* both flushes are handled by the common event function */
1968     case GST_EVENT_FLUSH_START:
1969     case GST_EVENT_FLUSH_STOP:
1970     case GST_EVENT_TAG:
1971     case GST_EVENT_SINK_MESSAGE:
1972     default:
1973       break;
1974   }
1975
1976   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1977   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
1978   gst_validate_pad_monitor_event_overrides (pad_monitor, event);
1979   if (handler) {
1980     gst_event_ref (event);
1981     if (pad_monitor->event_full_func)
1982       ret = pad_monitor->event_full_func (pad, parent, event);
1983     else if (pad_monitor->event_func (pad, parent, event))
1984       ret = GST_FLOW_OK;
1985     else
1986       ret = GST_FLOW_ERROR;
1987   }
1988   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
1989   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1990
1991   /* post checks */
1992   switch (GST_EVENT_TYPE (event)) {
1993     case GST_EVENT_SEGMENT:
1994       if (ret == GST_FLOW_OK) {
1995         /* If the new segment is not an update of the previous one, then
1996          * the following buffer should have the DISCONT flag set */
1997         if (!is_segment_update (&pad_monitor->segment, segment))
1998           pad_monitor->pending_buffer_discont = TRUE;
1999         if (!pad_monitor->has_segment
2000             && pad_monitor->segment.format != segment->format) {
2001           gst_segment_init (&pad_monitor->segment, segment->format);
2002         }
2003         gst_segment_copy_into (segment, &pad_monitor->segment);
2004         pad_monitor->has_segment = TRUE;
2005         gst_validate_monitor_find_next_buffer (pad_monitor);
2006       }
2007       break;
2008     case GST_EVENT_CAPS:{
2009       GstCaps *caps;
2010
2011       gst_event_parse_caps (event, &caps);
2012       gst_validate_pad_monitor_setcaps_post (pad_monitor, caps,
2013           ret == GST_FLOW_OK);
2014       break;
2015     }
2016     case GST_EVENT_FLUSH_START:
2017     case GST_EVENT_FLUSH_STOP:
2018     case GST_EVENT_EOS:
2019     case GST_EVENT_TAG:
2020     case GST_EVENT_SINK_MESSAGE:
2021     default:
2022       break;
2023   }
2024
2025   if (handler)
2026     gst_event_unref (event);
2027   gst_object_unref (pad);
2028   return ret;
2029 }
2030
2031 static gboolean
2032 gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor,
2033     GstObject * parent, GstEvent * event, GstPadEventFunction handler)
2034 {
2035   gboolean ret = TRUE;
2036   gdouble rate;
2037   GstFormat format;
2038   gint64 start, stop;
2039   GstSeekFlags seek_flags;
2040   GstSeekType start_type, stop_type;
2041   guint32 seqnum = gst_event_get_seqnum (event);
2042   GstPad *pad =
2043       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
2044           (pad_monitor)));
2045
2046   gst_validate_pad_monitor_common_event_check (pad_monitor, event);
2047
2048   /* pre checks */
2049   switch (GST_EVENT_TYPE (event)) {
2050     case GST_EVENT_SEEK:
2051     {
2052       gst_event_parse_seek (event, &rate, &format, &seek_flags, &start_type,
2053           &start, &stop_type, &stop);
2054       /* upstream seek - store the seek event seqnum to check
2055        * flushes and newsegments share the same */
2056     }
2057       break;
2058       /* both flushes are handled by the common event handling function */
2059     case GST_EVENT_FLUSH_START:
2060     case GST_EVENT_FLUSH_STOP:
2061     case GST_EVENT_NAVIGATION:
2062     case GST_EVENT_LATENCY:
2063     case GST_EVENT_STEP:
2064     case GST_EVENT_QOS:
2065     default:
2066       break;
2067   }
2068
2069   if (handler) {
2070     GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
2071     /* Safely store pending accurate seek values */
2072     if (GST_EVENT_TYPE (event) == GST_EVENT_SEEK) {
2073       if (seek_flags & GST_SEEK_FLAG_ACCURATE) {
2074         GST_DEBUG_OBJECT (pad,
2075             "Storing expected accurate seek time %" GST_TIME_FORMAT,
2076             GST_TIME_ARGS (start));
2077         pad_monitor->pending_seek_accurate_time = start;
2078       }
2079       /* TODO we might need to use a list as multiple seeks can be sent
2080        * before the flushes arrive here */
2081       if (seek_flags & GST_SEEK_FLAG_FLUSH) {
2082         pad_monitor->pending_flush_start_seqnum = seqnum;
2083         pad_monitor->pending_flush_stop_seqnum = seqnum;
2084       }
2085     }
2086
2087     gst_event_ref (event);
2088     ret = pad_monitor->event_func (pad, parent, event);
2089
2090     if (GST_EVENT_TYPE (event) == GST_EVENT_SEEK) {
2091       /* If the seek was already handled (same current seqnum), reset the
2092        * expected accurate seek value */
2093       if (ret && pad_monitor->has_segment
2094           && seqnum == pad_monitor->pending_eos_seqnum) {
2095         GST_DEBUG_OBJECT (pad,
2096             "Resetting expected accurate seek value, was already handled");
2097         pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE;
2098       } else if (!ret) {
2099         /* do not expect any of these events anymore */
2100         pad_monitor->pending_flush_start_seqnum = GST_SEQNUM_INVALID;
2101         pad_monitor->pending_flush_stop_seqnum = GST_SEQNUM_INVALID;
2102         pad_monitor->pending_newsegment_seqnum = GST_SEQNUM_INVALID;
2103         pad_monitor->pending_eos_seqnum = GST_SEQNUM_INVALID;
2104         pad_monitor->pending_seek_accurate_time = GST_CLOCK_TIME_NONE;
2105       }
2106     }
2107     GST_VALIDATE_MONITOR_LOCK (pad_monitor);
2108   }
2109
2110   /* post checks */
2111   switch (GST_EVENT_TYPE (event)) {
2112     case GST_EVENT_FLUSH_START:
2113     case GST_EVENT_FLUSH_STOP:
2114     case GST_EVENT_QOS:
2115     case GST_EVENT_SEEK:
2116     case GST_EVENT_NAVIGATION:
2117     case GST_EVENT_LATENCY:
2118     case GST_EVENT_STEP:
2119     default:
2120       break;
2121   }
2122
2123   if (handler)
2124     gst_event_unref (event);
2125   gst_object_unref (pad);
2126   return ret;
2127 }
2128
2129 static gboolean
2130 gst_validate_pad_monitor_check_right_buffer (GstValidatePadMonitor *
2131     pad_monitor, GstBuffer * buffer)
2132 {
2133   gchar *checksum;
2134   GstBuffer *wanted_buf;
2135   GstMapInfo map, wanted_map;
2136
2137   gboolean ret = TRUE;
2138   GstPad *pad;
2139
2140
2141   if (_should_check_buffers (pad_monitor, FALSE) == FALSE)
2142     return FALSE;
2143
2144   pad =
2145       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
2146           (pad_monitor)));
2147   if (pad_monitor->current_buf == NULL) {
2148     GST_INFO_OBJECT (pad, "No current buffer one pad, Why?");
2149     gst_object_unref (pad);
2150     return FALSE;
2151   }
2152
2153   wanted_buf = pad_monitor->current_buf->data;
2154
2155   if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (wanted_buf)) &&
2156       GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (buffer)) &&
2157       GST_BUFFER_PTS (wanted_buf) != GST_BUFFER_PTS (buffer)) {
2158
2159     GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER,
2160         "buffer %" GST_PTR_FORMAT " PTS %" GST_TIME_FORMAT
2161         " different than expected: %" GST_TIME_FORMAT, buffer,
2162         GST_TIME_ARGS (GST_BUFFER_PTS (buffer)),
2163         GST_TIME_ARGS (GST_BUFFER_PTS (wanted_buf)));
2164
2165     ret = FALSE;
2166   }
2167
2168   if (GST_BUFFER_DTS (wanted_buf) != GST_BUFFER_DTS (buffer)) {
2169     GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER,
2170         "buffer %" GST_PTR_FORMAT " DTS %" GST_TIME_FORMAT
2171         " different than expected: %" GST_TIME_FORMAT, buffer,
2172         GST_TIME_ARGS (GST_BUFFER_DTS (buffer)),
2173         GST_TIME_ARGS (GST_BUFFER_DTS (wanted_buf)));
2174     ret = FALSE;
2175   }
2176
2177   if (GST_BUFFER_DURATION (wanted_buf) != GST_BUFFER_DURATION (buffer)) {
2178     GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER,
2179         "buffer %" GST_PTR_FORMAT " DURATION %" GST_TIME_FORMAT
2180         " different than expected: %" GST_TIME_FORMAT, buffer,
2181         GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)),
2182         GST_TIME_ARGS (GST_BUFFER_DURATION (wanted_buf)));
2183     ret = FALSE;
2184   }
2185
2186   if (GST_BUFFER_FLAG_IS_SET (wanted_buf, GST_BUFFER_FLAG_DELTA_UNIT) !=
2187       GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)) {
2188     GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER,
2189         "buffer %" GST_PTR_FORMAT "  Delta unit is set to %s but expected %s",
2190         buffer, GST_BUFFER_FLAG_IS_SET (buffer,
2191             GST_BUFFER_FLAG_DELTA_UNIT) ? "True" : "False",
2192         GST_BUFFER_FLAG_IS_SET (wanted_buf,
2193             GST_BUFFER_FLAG_DELTA_UNIT) ? "True" : "False");
2194     ret = FALSE;
2195   }
2196
2197   g_assert (gst_buffer_map (wanted_buf, &wanted_map, GST_MAP_READ));
2198   g_assert (gst_buffer_map (buffer, &map, GST_MAP_READ));
2199
2200   checksum = g_compute_checksum_for_data (G_CHECKSUM_MD5,
2201       (const guchar *) map.data, map.size);
2202
2203   if (g_strcmp0 ((gchar *) wanted_map.data, checksum)) {
2204     GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER,
2205         "buffer %" GST_PTR_FORMAT " checksum %s different from expected: %s",
2206         buffer, checksum, wanted_map.data);
2207     ret = FALSE;
2208   }
2209
2210   gst_buffer_unmap (wanted_buf, &wanted_map);
2211   gst_buffer_unmap (buffer, &map);
2212   g_free (checksum);
2213   gst_object_unref (pad);
2214
2215   pad_monitor->current_buf = pad_monitor->current_buf->next;
2216
2217   return ret;
2218 }
2219
2220 static void
2221 gst_validate_pad_monitor_check_return (GstValidatePadMonitor * pad_monitor,
2222     GstFlowReturn ret)
2223 {
2224   GstValidateMonitor *parent = GST_VALIDATE_MONITOR (pad_monitor);
2225
2226   if (ret != GST_FLOW_ERROR)
2227     return;
2228
2229   while (GST_VALIDATE_MONITOR_GET_PARENT (parent))
2230     parent = GST_VALIDATE_MONITOR_GET_PARENT (parent);
2231
2232   if (GST_IS_VALIDATE_PIPELINE_MONITOR (parent)) {
2233     GstValidatePipelineMonitor *m = GST_VALIDATE_PIPELINE_MONITOR (parent);
2234
2235     GST_VALIDATE_MONITOR_LOCK (m);
2236     if (m->got_error == FALSE) {
2237       GST_VALIDATE_REPORT (pad_monitor, FLOW_ERROR_WITHOUT_ERROR_MESSAGE,
2238           "Pad return GST_FLOW_ERROR but no GST_MESSAGE_ERROR was received on"
2239           " the bus");
2240
2241       /* Only report it the first time */
2242       m->got_error = TRUE;
2243     }
2244     GST_VALIDATE_MONITOR_UNLOCK (m);
2245   }
2246 }
2247
2248 static GstFlowReturn
2249 gst_validate_pad_monitor_chain_func (GstPad * pad, GstObject * parent,
2250     GstBuffer * buffer)
2251 {
2252   GstValidatePadMonitor *pad_monitor =
2253       g_object_get_data ((GObject *) pad, "validate-monitor");
2254   GstFlowReturn ret;
2255
2256   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
2257   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
2258
2259   gst_validate_pad_monitor_check_discont (pad_monitor, buffer);
2260   gst_validate_pad_monitor_check_right_buffer (pad_monitor, buffer);
2261   gst_validate_pad_monitor_check_first_buffer (pad_monitor, buffer);
2262   gst_validate_pad_monitor_update_buffer_data (pad_monitor, buffer);
2263   gst_validate_pad_monitor_check_eos (pad_monitor, buffer);
2264
2265   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
2266   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
2267
2268   gst_validate_pad_monitor_buffer_overrides (pad_monitor, buffer);
2269
2270   ret = pad_monitor->chain_func (pad, parent, buffer);
2271
2272   gst_validate_pad_monitor_check_return (pad_monitor, ret);
2273
2274   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
2275   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
2276
2277   pad_monitor->last_flow_return = ret;
2278   if (ret == GST_FLOW_EOS) {
2279     mark_pads_eos (pad_monitor);
2280   }
2281   if (PAD_PARENT_IS_DEMUXER (pad_monitor))
2282     gst_validate_pad_monitor_check_aggregated_return (pad_monitor, parent, ret);
2283
2284   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
2285   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
2286
2287   return ret;
2288 }
2289
2290 static gboolean
2291 gst_validate_pad_monitor_event_is_tracked (GstValidatePadMonitor * monitor,
2292     GstEvent * event)
2293 {
2294   if (!GST_EVENT_IS_SERIALIZED (event)) {
2295     return FALSE;
2296   }
2297
2298   /* we don't track Tag events because they mutate too much and it is hard
2299    * to match a tag event pushed on a source pad with the one that was received
2300    * on a sink pad.
2301    * One idea would be to use seqnum, but it seems that it is undefined whether
2302    * seqnums should be maintained in tag events that are created from others
2303    * up to today. (2013-08-29)
2304    */
2305   if (GST_EVENT_TYPE (event) == GST_EVENT_TAG)
2306     return FALSE;
2307
2308   return TRUE;
2309 }
2310
2311 static GstFlowReturn
2312 gst_validate_pad_monitor_sink_event_full_func (GstPad * pad, GstObject * parent,
2313     GstEvent * event)
2314 {
2315   GstValidatePadMonitor *pad_monitor =
2316       g_object_get_data ((GObject *) pad, "validate-monitor");
2317   GstFlowReturn ret;
2318
2319   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
2320   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
2321
2322   if (gst_validate_pad_monitor_event_is_tracked (pad_monitor, event)) {
2323     GstClockTime last_ts = GST_CLOCK_TIME_NONE;
2324     if (GST_CLOCK_TIME_IS_VALID (pad_monitor->current_timestamp)) {
2325       last_ts = pad_monitor->current_timestamp;
2326       if (GST_CLOCK_TIME_IS_VALID (pad_monitor->current_duration)) {
2327         last_ts += pad_monitor->current_duration;
2328       }
2329     }
2330     gst_validate_pad_monitor_otherpad_add_pending_serialized_event (pad_monitor,
2331         event, last_ts);
2332   }
2333
2334   ret =
2335       gst_validate_pad_monitor_downstream_event_check (pad_monitor, parent,
2336       event, pad_monitor->event_func);
2337
2338   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
2339   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
2340   return ret;
2341 }
2342
2343 static gboolean
2344 gst_validate_pad_monitor_sink_event_func (GstPad * pad, GstObject * parent,
2345     GstEvent * event)
2346 {
2347   if (gst_validate_pad_monitor_sink_event_full_func (pad, parent,
2348           event) == GST_FLOW_OK)
2349     return TRUE;
2350   return FALSE;
2351 }
2352
2353 static gboolean
2354 gst_validate_pad_monitor_src_event_func (GstPad * pad, GstObject * parent,
2355     GstEvent * event)
2356 {
2357   GstValidatePadMonitor *pad_monitor =
2358       g_object_get_data ((GObject *) pad, "validate-monitor");
2359   gboolean ret;
2360
2361   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
2362   ret = gst_validate_pad_monitor_src_event_check (pad_monitor, parent, event,
2363       pad_monitor->event_func);
2364   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
2365   return ret;
2366 }
2367
2368 static gboolean
2369 gst_validate_pad_monitor_query_func (GstPad * pad, GstObject * parent,
2370     GstQuery * query)
2371 {
2372   GstValidatePadMonitor *pad_monitor =
2373       g_object_get_data ((GObject *) pad, "validate-monitor");
2374   gboolean ret;
2375
2376   gst_validate_pad_monitor_query_overrides (pad_monitor, query);
2377   ret = pad_monitor->query_func (pad, parent, query);
2378
2379   if (ret) {
2380     switch (GST_QUERY_TYPE (query)) {
2381       case GST_QUERY_ACCEPT_CAPS:
2382       {
2383         gboolean result;
2384
2385         gst_caps_replace (&pad_monitor->last_refused_caps, NULL);
2386         gst_query_parse_accept_caps_result (query, &result);
2387         if (!result) {
2388           GstCaps *refused_caps;
2389
2390           gst_query_parse_accept_caps (query, &refused_caps);
2391           pad_monitor->last_refused_caps = gst_caps_copy (refused_caps);
2392
2393         }
2394
2395         break;
2396       }
2397       case GST_QUERY_CAPS:{
2398         GstCaps *res;
2399         GstCaps *filter;
2400
2401         /* We shouldn't need to lock the parent as this doesn't modify
2402          * other monitors, just does some peer_pad_caps */
2403         GST_VALIDATE_MONITOR_LOCK (pad_monitor);
2404
2405         gst_query_parse_caps (query, &filter);
2406         gst_query_parse_caps_result (query, &res);
2407
2408         gst_caps_replace (&pad_monitor->last_query_res, NULL);
2409         gst_caps_replace (&pad_monitor->last_query_filter, NULL);
2410         pad_monitor->last_query_res =
2411             res ? gst_caps_copy (res) : gst_caps_ref (GST_CAPS_NONE);
2412         pad_monitor->last_query_filter =
2413             filter ? gst_caps_copy (filter) : gst_caps_ref (GST_CAPS_NONE);
2414
2415         if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
2416           gst_validate_pad_monitor_check_caps_fields_proxied (pad_monitor, res,
2417               filter);
2418         }
2419         GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
2420         break;
2421       }
2422       default:
2423         break;
2424     }
2425   }
2426
2427   return ret;
2428 }
2429
2430 static gboolean
2431 gst_validate_pad_monitor_activatemode_func (GstPad * pad, GstObject * parent,
2432     GstPadMode mode, gboolean active)
2433 {
2434   GstValidatePadMonitor *pad_monitor =
2435       g_object_get_data ((GObject *) pad, "validate-monitor");
2436   gboolean ret = TRUE;
2437
2438   /* TODO add overrides for activate func */
2439   GST_DEBUG_OBJECT (pad, "active:%d", active);
2440
2441   if (pad_monitor->activatemode_func)
2442     ret = pad_monitor->activatemode_func (pad, parent, mode, active);
2443   if (ret && active == FALSE) {
2444     GST_VALIDATE_MONITOR_LOCK (pad_monitor);
2445     gst_validate_pad_monitor_reset (pad_monitor);
2446     GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
2447   }
2448
2449   return ret;
2450 }
2451
2452 static GstFlowReturn
2453 gst_validate_pad_get_range_func (GstPad * pad, GstObject * parent,
2454     guint64 offset, guint size, GstBuffer ** buffer)
2455 {
2456   GstValidatePadMonitor *pad_monitor =
2457       g_object_get_data ((GObject *) pad, "validate-monitor");
2458   GstFlowReturn ret;
2459   ret = pad_monitor->getrange_func (pad, parent, offset, size, buffer);
2460   return ret;
2461 }
2462
2463 static gboolean
2464 gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer,
2465     gpointer udata, gboolean pull_mode)
2466 {
2467   GstValidatePadMonitor *monitor = udata;
2468
2469   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor);
2470   GST_VALIDATE_MONITOR_LOCK (monitor);
2471
2472   if (!pull_mode)
2473     gst_validate_pad_monitor_check_discont (monitor, buffer);
2474   gst_validate_pad_monitor_check_first_buffer (monitor, buffer);
2475   gst_validate_pad_monitor_update_buffer_data (monitor, buffer);
2476   gst_validate_pad_monitor_check_eos (monitor, buffer);
2477
2478   if (PAD_PARENT_IS_DECODER (monitor) || PAD_PARENT_IS_ENCODER (monitor)) {
2479     GstClockTime tolerance = 0;
2480
2481     if (monitor->caps_is_audio)
2482       tolerance = AUDIO_TIMESTAMP_TOLERANCE;
2483
2484     gst_validate_pad_monitor_check_buffer_timestamp_in_received_range (monitor,
2485         buffer, tolerance);
2486   }
2487
2488   gst_validate_pad_monitor_check_late_serialized_events (monitor,
2489       GST_BUFFER_TIMESTAMP (buffer));
2490
2491   /* a GstValidatePadMonitor parent must be a GstValidateElementMonitor */
2492   if (PAD_PARENT_IS_DECODER (monitor)) {
2493
2494     /* should not push out of segment data */
2495     if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer)) &&
2496         GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer)) &&
2497         ((!gst_segment_clip (&monitor->segment, monitor->segment.format,
2498                     GST_BUFFER_TIMESTAMP (buffer),
2499                     GST_BUFFER_TIMESTAMP (buffer) +
2500                     GST_BUFFER_DURATION (buffer), NULL, NULL)) ||
2501             /* In the case of raw data, buffers should be strictly contained inside the
2502              * segment */
2503             (monitor->caps_is_raw &&
2504                 GST_BUFFER_PTS (buffer) + GST_BUFFER_DURATION (buffer) <
2505                 monitor->segment.start))
2506         ) {
2507       /* TODO is this a timestamp issue? */
2508       GST_VALIDATE_REPORT (monitor, BUFFER_IS_OUT_OF_SEGMENT,
2509           "buffer is out of segment and shouldn't be pushed. Timestamp: %"
2510           GST_TIME_FORMAT " - Duration: %" GST_TIME_FORMAT ". Range: %"
2511           GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2512           GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
2513           GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)),
2514           GST_TIME_ARGS (monitor->segment.start),
2515           GST_TIME_ARGS (monitor->segment.stop));
2516     }
2517   }
2518
2519   GST_VALIDATE_MONITOR_UNLOCK (monitor);
2520   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (monitor);
2521   gst_validate_pad_monitor_buffer_probe_overrides (monitor, buffer);
2522   return TRUE;
2523 }
2524
2525 static void
2526 gst_validate_pad_monitor_event_probe (GstPad * pad, GstEvent * event,
2527     gpointer udata)
2528 {
2529   GstValidatePadMonitor *monitor = GST_VALIDATE_PAD_MONITOR_CAST (udata);
2530
2531   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor);
2532   GST_VALIDATE_MONITOR_LOCK (monitor);
2533
2534   GST_DEBUG_OBJECT (pad, "event %p %s", event, GST_EVENT_TYPE_NAME (event));
2535
2536   if (GST_EVENT_IS_SERIALIZED (event)) {
2537     gint i;
2538
2539     /* Detect if events the element received are being forwarded in the same order
2540      *
2541      * Several scenarios:
2542      * 1) The element pushes the event as-is
2543      * 2) The element consumes the event and does not forward it
2544      * 3) The element consumes the event and creates another one instead
2545      * 4) The element pushes other serialized event before pushing out the
2546      *    one it received
2547      *
2548      * For each pad we have two lists to track serialized events:
2549      *  1) We received on input and expect to see (serialized_events)
2550      *  2) We received on input but don't expect to see (expired_events)
2551      *
2552      * To detect events that are pushed in a different order from the one they were
2553      * received in we check that:
2554      *
2555      * For each event being outputted:
2556      *   If it is in the expired_events list:
2557      *     RAISE WARNING
2558      *   If it is in the serialized_events list:
2559      *     If there are other events that were received before:
2560      *        Put those events on the expired_events list
2561      *     Remove that event and any previous ones from the serialized_events list
2562      *
2563      * Clear expired events list when flushing or on pad deactivation
2564      *
2565      */
2566
2567     if (g_list_find (monitor->expired_events, event)) {
2568       gchar *event_str = _get_event_string (event);
2569       /* If it's the expired events, we've failed */
2570       GST_WARNING_OBJECT (pad, "Did not expect event %p %s", event,
2571           GST_EVENT_TYPE_NAME (event));
2572       GST_VALIDATE_REPORT (monitor, EVENT_SERIALIZED_OUT_OF_ORDER,
2573           "Serialized event was pushed out of order: %s", event_str);
2574
2575       g_free (event_str);
2576       monitor->expired_events = g_list_remove (monitor->expired_events, event);
2577       gst_event_unref (event);  /* remove the ref that was on the list */
2578     } else if (monitor->serialized_events->len) {
2579       for (i = 0; i < monitor->serialized_events->len; i++) {
2580         SerializedEventData *next_event =
2581             g_ptr_array_index (monitor->serialized_events, i);
2582         GST_DEBUG_OBJECT (pad, "Checking against stored event #%d: %p %s", i,
2583             next_event->event, GST_EVENT_TYPE_NAME (next_event->event));
2584
2585         if (event == next_event->event
2586             || GST_EVENT_TYPE (event) == GST_EVENT_TYPE (next_event->event)) {
2587           /* We have found our event */
2588           GST_DEBUG_OBJECT (pad, "Found matching event");
2589
2590           while (monitor->serialized_events->len > i
2591               && GST_EVENT_TYPE (event) == GST_EVENT_TYPE (next_event->event)) {
2592             /* Swallow all expected events of the same type */
2593             g_ptr_array_remove_index (monitor->serialized_events, i);
2594             next_event = g_ptr_array_index (monitor->serialized_events, i);
2595           }
2596
2597           /* Move all previous events to expired events */
2598           if (G_UNLIKELY (i > 0)) {
2599             GST_DEBUG_OBJECT (pad,
2600                 "Moving previous expected events to expired list");
2601             while (i--) {
2602               next_event = g_ptr_array_index (monitor->serialized_events, 0);
2603               monitor->expired_events =
2604                   g_list_append (monitor->expired_events,
2605                   gst_event_ref (next_event->event));
2606               g_ptr_array_remove_index (monitor->serialized_events, 0);
2607             }
2608           }
2609           debug_pending_event (pad, monitor->serialized_events);
2610           break;
2611         }
2612       }
2613     }
2614   }
2615
2616   /* This so far is just like an event that is flowing downstream,
2617    * so we do the same checks as a sinkpad event handler */
2618   gst_validate_pad_monitor_downstream_event_check (monitor, NULL, event, NULL);
2619   GST_VALIDATE_MONITOR_UNLOCK (monitor);
2620   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (monitor);
2621 }
2622
2623 static GstPadProbeReturn
2624 gst_validate_pad_monitor_pad_probe (GstPad * pad, GstPadProbeInfo * info,
2625     gpointer udata)
2626 {
2627   if (info->type & GST_PAD_PROBE_TYPE_BUFFER)
2628     gst_validate_pad_monitor_buffer_probe (pad, info->data, udata,
2629         GST_PAD_PROBE_INFO_TYPE (info) & GST_PAD_PROBE_TYPE_PULL);
2630   else if (info->type & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM)
2631     gst_validate_pad_monitor_event_probe (pad, info->data, udata);
2632
2633   return GST_PAD_PROBE_OK;
2634 }
2635
2636 static void
2637 gst_validate_pad_monitor_update_caps_info (GstValidatePadMonitor * pad_monitor,
2638     GstCaps * caps)
2639 {
2640   GstStructure *structure;
2641
2642   g_return_if_fail (gst_caps_is_fixed (caps));
2643
2644   pad_monitor->caps_is_audio = FALSE;
2645   pad_monitor->caps_is_video = FALSE;
2646
2647   structure = gst_caps_get_structure (caps, 0);
2648   if (g_str_has_prefix (gst_structure_get_name (structure), "audio/")) {
2649     pad_monitor->caps_is_audio = TRUE;
2650   } else if (g_str_has_prefix (gst_structure_get_name (structure), "video/")) {
2651     pad_monitor->caps_is_video = TRUE;
2652   }
2653
2654   if (g_str_has_prefix (gst_structure_get_name (structure), "audio/x-raw") ||
2655       g_str_has_prefix (gst_structure_get_name (structure), "video/x-raw")) {
2656     pad_monitor->caps_is_raw = TRUE;
2657   } else {
2658     pad_monitor->caps_is_raw = FALSE;
2659   }
2660 }
2661
2662 static void
2663 gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor,
2664     GstCaps * caps)
2665 {
2666   GstStructure *structure;
2667   GstPad *pad =
2668       GST_PAD (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR
2669           (pad_monitor)));
2670
2671   /* Check if caps are identical to last caps and complain if so
2672    * Only checked for sink pads as src pads might push the same caps
2673    * multiple times during unlinked/autoplugging scenarios */
2674   if (GST_PAD_IS_SINK (pad) && pad_monitor->last_caps
2675       && gst_caps_is_equal (caps, pad_monitor->last_caps)) {
2676     gchar *caps_str = gst_caps_to_string (caps);
2677
2678     GST_VALIDATE_REPORT (pad_monitor, EVENT_CAPS_DUPLICATE, "%s", caps_str);
2679     g_free (caps_str);
2680
2681   }
2682
2683   gst_validate_pad_monitor_check_caps_complete (pad_monitor, caps);
2684
2685   if (caps) {
2686     structure = gst_caps_get_structure (caps, 0);
2687     if (gst_structure_n_fields (pad_monitor->pending_setcaps_fields)) {
2688       gint i;
2689       for (i = 0;
2690           i < gst_structure_n_fields (pad_monitor->pending_setcaps_fields);
2691           i++) {
2692         const gchar *name =
2693             gst_structure_nth_field_name (pad_monitor->pending_setcaps_fields,
2694             i);
2695         const GValue *v = gst_structure_get_value (structure, name);
2696         const GValue *otherv =
2697             gst_structure_get_value (pad_monitor->pending_setcaps_fields, name);
2698
2699         if (v == NULL) {
2700           gchar *caps_str = gst_caps_to_string (caps);
2701
2702           GST_VALIDATE_REPORT (pad_monitor, CAPS_EXPECTED_FIELD_NOT_FOUND,
2703               "Field %s is missing from setcaps caps '%s'", name, caps_str);
2704           g_free (caps_str);
2705         } else if (gst_value_compare (v, otherv) != GST_VALUE_EQUAL) {
2706           gchar *caps_str = gst_caps_to_string (caps),
2707               *pending_setcaps_fields_str =
2708               gst_structure_to_string (pad_monitor->pending_setcaps_fields);
2709
2710
2711           GST_VALIDATE_REPORT (pad_monitor, CAPS_FIELD_UNEXPECTED_VALUE,
2712               "Field %s from setcaps caps '%s' is different "
2713               "from expected value in caps '%s'", name, caps_str,
2714               pending_setcaps_fields_str);
2715
2716           g_free (pending_setcaps_fields_str);
2717           g_free (caps_str);
2718         }
2719       }
2720     }
2721
2722     if (GST_PAD_IS_SINK (pad) &&
2723         gst_validate_pad_monitor_pad_should_proxy_othercaps (pad_monitor)) {
2724       if (_structure_is_video (structure)) {
2725         GST_DEBUG_OBJECT (pad,
2726             "Adding video common pending fields to other pad: %" GST_PTR_FORMAT,
2727             structure);
2728         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2729             structure, "width");
2730         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2731             structure, "height");
2732         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2733             structure, "framerate");
2734         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2735             structure, "pixel-aspect-ratio");
2736       } else if (_structure_is_audio (structure)) {
2737         GST_DEBUG_OBJECT (pad,
2738             "Adding audio common pending fields to other pad: %" GST_PTR_FORMAT,
2739             structure);
2740         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2741             structure, "rate");
2742         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2743             structure, "channels");
2744       }
2745     }
2746   }
2747
2748   gst_structure_free (pad_monitor->pending_setcaps_fields);
2749   pad_monitor->pending_setcaps_fields =
2750       gst_structure_new_empty (PENDING_FIELDS);
2751   gst_object_unref (pad);
2752
2753   gst_validate_pad_monitor_setcaps_overrides (pad_monitor, caps);
2754 }
2755
2756 static void
2757 gst_validate_pad_monitor_setcaps_post (GstValidatePadMonitor * pad_monitor,
2758     GstCaps * caps, gboolean ret)
2759 {
2760   if (!ret)
2761     gst_validate_pad_monitor_otherpad_clear_pending_fields (pad_monitor);
2762   else {
2763     if (pad_monitor->last_caps) {
2764       gst_caps_unref (pad_monitor->last_caps);
2765     }
2766     pad_monitor->last_caps = gst_caps_ref (caps);
2767     gst_validate_pad_monitor_update_caps_info (pad_monitor, caps);
2768   }
2769 }
2770
2771 static gboolean
2772 gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor)
2773 {
2774   GstValidatePadMonitor *pad_monitor = GST_VALIDATE_PAD_MONITOR_CAST (monitor);
2775   GstPad *pad = (gpointer) gst_validate_monitor_get_target (monitor);
2776
2777   if (!GST_IS_PAD (pad)) {
2778     GST_WARNING_OBJECT (monitor, "Trying to create pad monitor with other "
2779         "type of object");
2780     gst_object_unref (pad);
2781     return FALSE;
2782   }
2783
2784   if (g_object_get_data ((GObject *) pad, "validate-monitor")) {
2785     GST_WARNING_OBJECT (pad_monitor,
2786         "Pad already has a validate-monitor associated");
2787     gst_object_unref (pad);
2788     return FALSE;
2789   }
2790
2791   g_object_set_data ((GObject *) pad, "validate-monitor", pad_monitor);
2792
2793   pad_monitor->event_func = GST_PAD_EVENTFUNC (pad);
2794   pad_monitor->event_full_func = GST_PAD_EVENTFULLFUNC (pad);
2795   pad_monitor->query_func = GST_PAD_QUERYFUNC (pad);
2796   pad_monitor->activatemode_func = GST_PAD_ACTIVATEMODEFUNC (pad);
2797   if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
2798
2799     pad_monitor->chain_func = GST_PAD_CHAINFUNC (pad);
2800     if (pad_monitor->chain_func)
2801       gst_pad_set_chain_function (pad, gst_validate_pad_monitor_chain_func);
2802
2803     if (pad_monitor->event_full_func)
2804       gst_pad_set_event_full_function (pad,
2805           gst_validate_pad_monitor_sink_event_full_func);
2806     else
2807       gst_pad_set_event_function (pad,
2808           gst_validate_pad_monitor_sink_event_func);
2809   } else {
2810     pad_monitor->getrange_func = GST_PAD_GETRANGEFUNC (pad);
2811     if (pad_monitor->getrange_func)
2812       gst_pad_set_getrange_function (pad, gst_validate_pad_get_range_func);
2813
2814     gst_pad_set_event_function (pad, gst_validate_pad_monitor_src_event_func);
2815
2816     /* add buffer/event probes */
2817     pad_monitor->pad_probe_id =
2818         gst_pad_add_probe (pad,
2819         GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM |
2820         GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2821         (GstPadProbeCallback) gst_validate_pad_monitor_pad_probe, pad_monitor,
2822         NULL);
2823   }
2824   gst_pad_set_query_function (pad, gst_validate_pad_monitor_query_func);
2825   gst_pad_set_activatemode_function (pad,
2826       gst_validate_pad_monitor_activatemode_func);
2827
2828   gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (monitor),
2829       g_strdup_printf ("%s:%s", GST_DEBUG_PAD_NAME (pad)));
2830
2831   if (G_UNLIKELY (GST_PAD_PARENT (pad) == NULL))
2832     GST_FIXME ("Saw a pad not belonging to any object");
2833
2834   gst_object_unref (pad);
2835   return TRUE;
2836 }