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