pad-monitor: fix typo when acessing parents data
[platform/upstream/gstreamer.git] / validate / gst / validate / gst-validate-pad-monitor.c
1 /* GStreamer
2  * Copyright (C) 2013 Thiago Santos <thiago.sousa.santos@collabora.com>
3  *
4  * gst-validate-pad-monitor.c - Validate PadMonitor class
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #  include "config.h"
24 #endif
25
26 #include "gst-validate-internal.h"
27 #include "gst-validate-pad-monitor.h"
28 #include "gst-validate-element-monitor.h"
29 #include "gst-validate-reporter.h"
30 #include <string.h>
31 #include <stdarg.h>
32
33 /**
34  * SECTION:gst-validate-pad-monitor
35  * @short_description: Class that wraps a #GstPad for Validate checks
36  *
37  * TODO
38  */
39
40 #define gst_validate_pad_monitor_parent_class parent_class
41 G_DEFINE_TYPE (GstValidatePadMonitor, gst_validate_pad_monitor,
42     GST_TYPE_VALIDATE_MONITOR);
43
44 #define PENDING_FIELDS "pending-fields"
45
46 /*
47  * Locking the parent should always be done before locking the
48  * pad-monitor to prevent deadlocks in case another monitor from
49  * another pad on the same element starts an operation that also
50  * requires locking itself and some other monitors from internally
51  * linked pads.
52  *
53  * An example:
54  * An element has a sink and a src pad. Some test starts running at sinkpad
55  * and it locks the parent, and then it locks itself. In case it needs to get
56  * some information from the srcpad, it is able to lock the srcpad and get it
57  * because the srcpad should never lock itself before locking the parent (which
58  * it won't be able as sinkpad already locked it).
59  *
60  * As a side one, it is possible that srcpad locks itself without locking the
61  * parent in case it wants to do a check that won't need to use other internally
62  * linked pads (sinkpad). But in this case it might lock and unlock freely without
63  * causing deadlocks.
64  */
65 #define GST_VALIDATE_PAD_MONITOR_PARENT_LOCK(m)                  \
66 G_STMT_START {                                             \
67   if (G_LIKELY (GST_VALIDATE_MONITOR_GET_PARENT (m))) {          \
68     GST_VALIDATE_MONITOR_LOCK (GST_VALIDATE_MONITOR_GET_PARENT (m));   \
69   } else {                                                 \
70     GST_WARNING_OBJECT (m, "No parent found, can't lock"); \
71   }                                                        \
72 } G_STMT_END
73
74 #define GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK(m)                  \
75 G_STMT_START {                                               \
76   if (G_LIKELY (GST_VALIDATE_MONITOR_GET_PARENT (m))) {            \
77     GST_VALIDATE_MONITOR_UNLOCK (GST_VALIDATE_MONITOR_GET_PARENT (m));   \
78   } else {                                                   \
79     GST_WARNING_OBJECT (m, "No parent found, can't unlock"); \
80   }                                                          \
81 } G_STMT_END
82
83 typedef struct
84 {
85   GstClockTime timestamp;
86   GstEvent *event;
87 } SerializedEventData;
88
89 static void
90 _serialized_event_data_free (SerializedEventData * serialized_event)
91 {
92   gst_event_unref (serialized_event->event);
93   g_slice_free (SerializedEventData, serialized_event);
94 }
95
96 static gboolean gst_validate_pad_monitor_do_setup (GstValidateMonitor *
97     monitor);
98 static GstElement *gst_validate_pad_monitor_get_element (GstValidateMonitor *
99     monitor);
100 static void
101 gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor,
102     GstCaps * caps);
103 static void gst_validate_pad_monitor_setcaps_post (GstValidatePadMonitor *
104     pad_monitor, GstCaps * caps, gboolean ret);
105
106 #define PAD_IS_IN_PUSH_MODE(p) ((p)->mode == GST_PAD_MODE_PUSH)
107
108 static gboolean
109 _structure_is_raw_video (GstStructure * structure)
110 {
111   return gst_structure_has_name (structure, "video/x-raw");
112 }
113
114 static gboolean
115 _structure_is_raw_audio (GstStructure * structure)
116 {
117   return gst_structure_has_name (structure, "audio/x-raw");
118 }
119
120 static void
121 _check_field_type (GstValidatePadMonitor * monitor, GstStructure * structure,
122     const gchar * field, ...)
123 {
124   va_list var_args;
125   GType type;
126   gchar *joined_types = NULL;
127   const gchar *rejected_types[5];
128   gint rejected_types_index = 0;
129
130   if (!gst_structure_has_field (structure, field)) {
131     GST_VALIDATE_REPORT (monitor, CAPS_IS_MISSING_FIELD,
132         "Field '%s' is missing from structure: %" GST_PTR_FORMAT, field,
133         structure);
134     return;
135   }
136
137   memset (rejected_types, 0, sizeof (rejected_types));
138   va_start (var_args, field);
139   while ((type = va_arg (var_args, GType)) != 0) {
140     if (gst_structure_has_field_typed (structure, field, type)) {
141       va_end (var_args);
142       return;
143     }
144     rejected_types[rejected_types_index++] = g_type_name (type);
145   }
146   va_end (var_args);
147
148   joined_types = g_strjoinv (" / ", (gchar **) rejected_types);
149   GST_VALIDATE_REPORT (monitor, CAPS_FIELD_HAS_BAD_TYPE,
150       "Field '%s' has wrong type %s in structure '%" GST_PTR_FORMAT
151       "'. Expected: %s", field,
152       g_type_name (gst_structure_get_field_type (structure, field)), structure,
153       joined_types);
154   g_free (joined_types);
155 }
156
157 static void
158 gst_validate_pad_monitor_check_raw_video_caps_complete (GstValidatePadMonitor *
159     monitor, GstStructure * structure)
160 {
161   _check_field_type (monitor, structure, "width", G_TYPE_INT,
162       GST_TYPE_INT_RANGE, 0);
163   _check_field_type (monitor, structure, "height", G_TYPE_INT,
164       GST_TYPE_INT_RANGE, 0);
165   _check_field_type (monitor, structure, "framerate", GST_TYPE_FRACTION,
166       GST_TYPE_FRACTION_RANGE, 0);
167   _check_field_type (monitor, structure, "pixel-aspect-ratio",
168       GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE, 0);
169   _check_field_type (monitor, structure, "format", G_TYPE_STRING,
170       GST_TYPE_LIST);
171 }
172
173 static void
174 gst_validate_pad_monitor_check_raw_audio_caps_complete (GstValidatePadMonitor *
175     monitor, GstStructure * structure)
176 {
177   _check_field_type (monitor, structure, "format", G_TYPE_STRING, GST_TYPE_LIST,
178       0);
179   _check_field_type (monitor, structure, "layout", G_TYPE_STRING, GST_TYPE_LIST,
180       0);
181   _check_field_type (monitor, structure, "rate", G_TYPE_INT, GST_TYPE_LIST,
182       GST_TYPE_INT_RANGE, 0);
183   _check_field_type (monitor, structure, "channels", G_TYPE_INT, GST_TYPE_LIST,
184       GST_TYPE_INT_RANGE, 0);
185   _check_field_type (monitor, structure, "channel-mask", GST_TYPE_BITMASK,
186       GST_TYPE_LIST, 0);
187 }
188
189 static void
190 gst_validate_pad_monitor_check_caps_complete (GstValidatePadMonitor * monitor,
191     GstCaps * caps)
192 {
193   GstStructure *structure;
194   gint i;
195
196   GST_DEBUG_OBJECT (monitor, "Checking caps %" GST_PTR_FORMAT, caps);
197
198   for (i = 0; i < gst_caps_get_size (caps); i++) {
199     structure = gst_caps_get_structure (caps, i);
200
201     if (_structure_is_raw_video (structure)) {
202       gst_validate_pad_monitor_check_raw_video_caps_complete (monitor,
203           structure);
204
205     } else if (_structure_is_raw_audio (structure)) {
206       gst_validate_pad_monitor_check_raw_audio_caps_complete (monitor,
207           structure);
208     }
209   }
210 }
211
212 static GstCaps *
213 gst_validate_pad_monitor_get_othercaps (GstValidatePadMonitor * monitor)
214 {
215   GstCaps *caps = gst_caps_new_empty ();
216   GstIterator *iter;
217   gboolean done;
218   GstPad *otherpad;
219   GstCaps *peercaps;
220
221   iter =
222       gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
223       (monitor));
224   done = FALSE;
225   while (!done) {
226     GValue value = { 0, };
227     switch (gst_iterator_next (iter, &value)) {
228       case GST_ITERATOR_OK:
229         otherpad = g_value_get_object (&value);
230
231         /* TODO What would be the correct caps operation to merge the caps in
232          * case one sink is internally linked to multiple srcs? */
233         peercaps = gst_pad_peer_query_caps (otherpad, NULL);
234         if (peercaps)
235           caps = gst_caps_merge (caps, peercaps);
236
237         g_value_reset (&value);
238         break;
239       case GST_ITERATOR_RESYNC:
240         gst_iterator_resync (iter);
241         gst_caps_replace (&caps, gst_caps_new_empty ());
242         break;
243       case GST_ITERATOR_ERROR:
244         GST_WARNING_OBJECT (monitor, "Internal links pad iteration error");
245         done = TRUE;
246         break;
247       case GST_ITERATOR_DONE:
248         done = TRUE;
249         break;
250     }
251   }
252   gst_iterator_free (iter);
253
254   GST_DEBUG_OBJECT (monitor, "Otherpad caps: %" GST_PTR_FORMAT, caps);
255
256   return caps;
257 }
258
259 static gboolean
260 _structure_is_video (GstStructure * structure)
261 {
262   const gchar *name = gst_structure_get_name (structure);
263
264   return g_strstr_len (name, 6, "video/")
265       && strcmp (name, "video/quicktime") != 0;
266 }
267
268 static gboolean
269 _structure_is_audio (GstStructure * structure)
270 {
271   const gchar *name = gst_structure_get_name (structure);
272
273   return g_strstr_len (name, 6, "audio/") != NULL;
274 }
275
276 static gboolean
277 gst_validate_pad_monitor_pad_should_proxy_othercaps (GstValidatePadMonitor *
278     monitor)
279 {
280   GstValidateMonitor *parent = GST_VALIDATE_MONITOR_GET_PARENT (monitor);
281   /* We only know how to handle othercaps checks for codecs so far */
282   return GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DECODER (parent) ||
283       GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_ENCODER (parent);
284 }
285
286
287 /* Check if the field @f from @s2 (if present) is represented in @s1
288  * Represented here means either equal or @s1's value is in a list/range
289  * from @s2
290  */
291 static gboolean
292 _structures_field_is_contained (GstStructure * s1, GstStructure * s2,
293     const gchar * f)
294 {
295   const GValue *v1;
296   const GValue *v2;
297
298   v2 = gst_structure_get_value (s2, f);
299   if (!v2)
300     return TRUE;                /* nothing to compare to */
301
302   v1 = gst_structure_get_value (s1, f);
303   if (!v1)
304     return FALSE;
305
306   if (gst_value_compare (v1, v2) == GST_VALUE_EQUAL)
307     return TRUE;
308
309   if (GST_VALUE_HOLDS_LIST (v2)) {
310     gint i;
311     for (i = 0; i < gst_value_list_get_size (v2); i++) {
312       const GValue *v2_subvalue = gst_value_list_get_value (v2, i);
313       if (gst_value_compare (v1, v2_subvalue) == GST_VALUE_EQUAL)
314         return TRUE;
315     }
316   }
317
318   if (GST_VALUE_HOLDS_ARRAY (v2)) {
319     gint i;
320     for (i = 0; i < gst_value_array_get_size (v2); i++) {
321       const GValue *v2_subvalue = gst_value_array_get_value (v2, i);
322       if (gst_value_compare (v1, v2_subvalue) == GST_VALUE_EQUAL)
323         return TRUE;
324     }
325   }
326
327   if (GST_VALUE_HOLDS_INT_RANGE (v2)) {
328     gint min, max;
329
330     min = gst_value_get_int_range_min (v2);
331     max = gst_value_get_int_range_max (v2);
332
333     if (G_VALUE_HOLDS_INT (v1)) {
334       gint v = g_value_get_int (v1);
335
336       return v >= min && v <= max;
337     } else {
338       /* TODO compare int ranges with int ranges
339        * or with lists if useful */
340     }
341   }
342
343   if (GST_VALUE_HOLDS_FRACTION_RANGE (v2)) {
344     const GValue *min, *max;
345
346     min = gst_value_get_fraction_range_min (v2);
347     max = gst_value_get_fraction_range_max (v2);
348
349     if (GST_VALUE_HOLDS_FRACTION (v1)) {
350       gint v_min = gst_value_compare (v1, min);
351       gint v_max = gst_value_compare (v1, max);
352
353       return (v_min == GST_VALUE_EQUAL || v_min == GST_VALUE_GREATER_THAN) &&
354           (v_max == GST_VALUE_EQUAL || v_max == GST_VALUE_LESS_THAN);
355     } else {
356       /* TODO compare fraction ranges with fraction ranges
357        * or with lists if useful */
358     }
359   }
360
361   return FALSE;
362 }
363
364 static void
365 gst_validate_pad_monitor_check_caps_fields_proxied (GstValidatePadMonitor *
366     monitor, GstCaps * caps)
367 {
368   GstStructure *structure;
369   GstStructure *otherstructure;
370   GstCaps *othercaps;
371   gint i, j;
372
373   if (!gst_validate_pad_monitor_pad_should_proxy_othercaps (monitor))
374     return;
375
376   othercaps = gst_validate_pad_monitor_get_othercaps (monitor);
377
378   for (i = 0; i < gst_caps_get_size (othercaps); i++) {
379     gboolean found = FALSE;
380     gboolean type_match = FALSE;
381
382     otherstructure = gst_caps_get_structure (othercaps, i);
383
384     /* look for a proxied version of 'otherstructure' */
385     if (_structure_is_video (otherstructure)) {
386       for (j = 0; j < gst_caps_get_size (caps); j++) {
387         structure = gst_caps_get_structure (caps, j);
388         if (_structure_is_video (structure)) {
389           type_match = TRUE;
390           if (_structures_field_is_contained (structure, otherstructure,
391                   "width")
392               && _structures_field_is_contained (structure, otherstructure,
393                   "height")
394               && _structures_field_is_contained (structure, otherstructure,
395                   "framerate")
396               && _structures_field_is_contained (structure, otherstructure,
397                   "pixel-aspect-ratio")) {
398             found = TRUE;
399             break;
400           }
401         }
402       }
403     } else if (_structure_is_audio (otherstructure)) {
404       for (j = 0; j < gst_caps_get_size (caps); j++) {
405         structure = gst_caps_get_structure (caps, j);
406         if (_structure_is_audio (structure)) {
407           type_match = TRUE;
408           if (_structures_field_is_contained (structure, otherstructure, "rate")
409               && _structures_field_is_contained (structure, otherstructure,
410                   "channels")) {
411             found = TRUE;
412             break;
413           }
414         }
415       }
416     }
417
418     if (type_match && !found) {
419       GST_VALIDATE_REPORT (monitor, GET_CAPS_NOT_PROXYING_FIELDS,
420           "Peer pad structure '%" GST_PTR_FORMAT "' has no similar version "
421           "on pad's caps '%" GST_PTR_FORMAT "'", otherstructure, caps);
422     }
423   }
424 }
425
426 static void
427 gst_validate_pad_monitor_check_late_serialized_events (GstValidatePadMonitor *
428     monitor, GstClockTime ts)
429 {
430   gint i;
431   if (!GST_CLOCK_TIME_IS_VALID (ts))
432     return;
433
434   for (i = 0; i < monitor->serialized_events->len; i++) {
435     SerializedEventData *data =
436         g_ptr_array_index (monitor->serialized_events, i);
437     if (data->timestamp < ts) {
438       GST_VALIDATE_REPORT (monitor, SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME,
439           "Serialized event %" GST_PTR_FORMAT " wasn't pushed before expected "
440           "timestamp %" GST_TIME_FORMAT " on pad %s:%s", data->event,
441           GST_TIME_ARGS (data->timestamp),
442           GST_DEBUG_PAD_NAME (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor)));
443     } else {
444       /* events should be ordered by ts */
445       break;
446     }
447   }
448
449   if (i)
450     g_ptr_array_remove_range (monitor->serialized_events, 0, i);
451 }
452
453 static void
454 gst_validate_pad_monitor_dispose (GObject * object)
455 {
456   GstValidatePadMonitor *monitor = GST_VALIDATE_PAD_MONITOR_CAST (object);
457   GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor);
458
459   if (pad) {
460     if (monitor->pad_probe_id)
461       gst_pad_remove_probe (pad, monitor->pad_probe_id);
462   }
463
464   if (monitor->expected_segment)
465     gst_event_unref (monitor->expected_segment);
466
467   gst_structure_free (monitor->pending_setcaps_fields);
468   g_ptr_array_unref (monitor->serialized_events);
469
470   G_OBJECT_CLASS (parent_class)->dispose (object);
471 }
472
473 static void
474 gst_validate_pad_monitor_class_init (GstValidatePadMonitorClass * klass)
475 {
476   GObjectClass *gobject_class;
477   GstValidateMonitorClass *monitor_klass;
478
479   gobject_class = G_OBJECT_CLASS (klass);
480   monitor_klass = GST_VALIDATE_MONITOR_CLASS (klass);
481
482   gobject_class->dispose = gst_validate_pad_monitor_dispose;
483
484   monitor_klass->setup = gst_validate_pad_monitor_do_setup;
485   monitor_klass->get_element = gst_validate_pad_monitor_get_element;
486 }
487
488 static void
489 gst_validate_pad_monitor_init (GstValidatePadMonitor * pad_monitor)
490 {
491   pad_monitor->pending_setcaps_fields =
492       gst_structure_new_empty (PENDING_FIELDS);
493   pad_monitor->serialized_events =
494       g_ptr_array_new_with_free_func ((GDestroyNotify)
495       _serialized_event_data_free);
496   gst_segment_init (&pad_monitor->segment, GST_FORMAT_BYTES);
497   pad_monitor->first_buffer = TRUE;
498
499   pad_monitor->timestamp_range_start = GST_CLOCK_TIME_NONE;
500   pad_monitor->timestamp_range_end = GST_CLOCK_TIME_NONE;
501 }
502
503 /**
504  * gst_validate_pad_monitor_new:
505  * @pad: (transfer-none): a #GstPad to run Validate on
506  */
507 GstValidatePadMonitor *
508 gst_validate_pad_monitor_new (GstPad * pad, GstValidateRunner * runner,
509     GstValidateElementMonitor * parent)
510 {
511   GstValidatePadMonitor *monitor = g_object_new (GST_TYPE_VALIDATE_PAD_MONITOR,
512       "object", pad, "qa-runner", runner, "qa-parent",
513       parent, NULL);
514
515   if (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor) == NULL) {
516     g_object_unref (monitor);
517     return NULL;
518   }
519   return monitor;
520 }
521
522 static GstElement *
523 gst_validate_pad_monitor_get_element (GstValidateMonitor * monitor)
524 {
525   GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor);
526
527   return GST_PAD_PARENT (pad);
528 }
529
530 static void
531 gst_validate_pad_monitor_event_overrides (GstValidatePadMonitor * pad_monitor,
532     GstEvent * event)
533 {
534   GList *iter;
535
536   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
537   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
538       iter = g_list_next (iter)) {
539     GstValidateOverride *override = iter->data;
540
541     gst_validate_override_event_handler (override,
542         GST_VALIDATE_MONITOR_CAST (pad_monitor), event);
543   }
544   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
545 }
546
547 static void
548 gst_validate_pad_monitor_buffer_overrides (GstValidatePadMonitor * pad_monitor,
549     GstBuffer * buffer)
550 {
551   GList *iter;
552
553   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
554   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
555       iter = g_list_next (iter)) {
556     GstValidateOverride *override = iter->data;
557
558     gst_validate_override_buffer_handler (override,
559         GST_VALIDATE_MONITOR_CAST (pad_monitor), buffer);
560   }
561   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
562 }
563
564 static void
565 gst_validate_pad_monitor_buffer_probe_overrides (GstValidatePadMonitor *
566     pad_monitor, GstBuffer * buffer)
567 {
568   GList *iter;
569
570   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
571   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
572       iter = g_list_next (iter)) {
573     GstValidateOverride *override = iter->data;
574
575     gst_validate_override_buffer_probe_handler (override,
576         GST_VALIDATE_MONITOR_CAST (pad_monitor), buffer);
577   }
578   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
579 }
580
581 static void
582 gst_validate_pad_monitor_query_overrides (GstValidatePadMonitor * pad_monitor,
583     GstQuery * query)
584 {
585   GList *iter;
586
587   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
588   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
589       iter = g_list_next (iter)) {
590     GstValidateOverride *override = iter->data;
591
592     gst_validate_override_query_handler (override,
593         GST_VALIDATE_MONITOR_CAST (pad_monitor), query);
594   }
595   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
596 }
597
598 static void
599 gst_validate_pad_monitor_setcaps_overrides (GstValidatePadMonitor * pad_monitor,
600     GstCaps * caps)
601 {
602   GList *iter;
603
604   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
605   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
606       iter = g_list_next (iter)) {
607     GstValidateOverride *override = iter->data;
608
609     gst_validate_override_setcaps_handler (override,
610         GST_VALIDATE_MONITOR_CAST (pad_monitor), caps);
611   }
612   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
613 }
614
615 static gboolean
616 gst_validate_pad_monitor_timestamp_is_in_received_range (GstValidatePadMonitor *
617     monitor, GstClockTime ts)
618 {
619   GST_DEBUG_OBJECT (monitor, "Checking if timestamp %" GST_TIME_FORMAT
620       " is in range: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT " for pad "
621       "%s:%s", GST_TIME_ARGS (ts),
622       GST_TIME_ARGS (monitor->timestamp_range_start),
623       GST_TIME_ARGS (monitor->timestamp_range_end),
624       GST_DEBUG_PAD_NAME (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor)));
625   return !GST_CLOCK_TIME_IS_VALID (monitor->timestamp_range_start) ||
626       !GST_CLOCK_TIME_IS_VALID (monitor->timestamp_range_end) ||
627       (monitor->timestamp_range_start <= ts
628       && ts <= monitor->timestamp_range_end);
629 }
630
631 /* Iterates over internal links (sinkpads) to check that this buffer has
632  * a timestamp that is in the range of the lastly received buffers */
633 static void
634     gst_validate_pad_monitor_check_buffer_timestamp_in_received_range
635     (GstValidatePadMonitor * monitor, GstBuffer * buffer)
636 {
637   GstClockTime ts;
638   GstClockTime ts_end;
639   GstIterator *iter;
640   gboolean has_one = FALSE;
641   gboolean found = FALSE;
642   gboolean done;
643   GstPad *otherpad;
644   GstValidatePadMonitor *othermonitor;
645
646   if (!GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))
647       || !GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) {
648     GST_DEBUG_OBJECT (monitor,
649         "Can't check buffer timestamps range as "
650         "buffer has no valid timestamp/duration");
651     return;
652   }
653   ts = GST_BUFFER_TIMESTAMP (buffer);
654   ts_end = ts + GST_BUFFER_DURATION (buffer);
655
656   iter =
657       gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
658       (monitor));
659   done = FALSE;
660   while (!done) {
661     GValue value = { 0, };
662     switch (gst_iterator_next (iter, &value)) {
663       case GST_ITERATOR_OK:
664         otherpad = g_value_get_object (&value);
665         GST_DEBUG_OBJECT (monitor, "Checking pad %s:%s input timestamps",
666             GST_DEBUG_PAD_NAME (otherpad));
667         othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor");
668         GST_VALIDATE_MONITOR_LOCK (othermonitor);
669         if (gst_validate_pad_monitor_timestamp_is_in_received_range
670             (othermonitor, ts)
671             &&
672             gst_validate_pad_monitor_timestamp_is_in_received_range
673             (othermonitor, ts_end)) {
674           done = TRUE;
675           found = TRUE;
676         }
677         GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
678         g_value_reset (&value);
679         has_one = TRUE;
680         break;
681       case GST_ITERATOR_RESYNC:
682         gst_iterator_resync (iter);
683         has_one = FALSE;
684         found = FALSE;
685         break;
686       case GST_ITERATOR_ERROR:
687         GST_WARNING_OBJECT (monitor, "Internal links pad iteration error");
688         done = TRUE;
689         break;
690       case GST_ITERATOR_DONE:
691         done = TRUE;
692         break;
693     }
694   }
695   gst_iterator_free (iter);
696
697   if (!has_one) {
698     GST_DEBUG_OBJECT (monitor, "Skipping timestamp in range check as no "
699         "internal linked pad was found");
700     return;
701   }
702   if (!found) {
703     GST_VALIDATE_REPORT (monitor, BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE,
704         "Timestamp %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT
705         " is out of range of received input", GST_TIME_ARGS (ts),
706         GST_TIME_ARGS (ts_end));
707   }
708 }
709
710 static void
711 gst_validate_pad_monitor_check_first_buffer (GstValidatePadMonitor *
712     pad_monitor, GstBuffer * buffer)
713 {
714   if (G_UNLIKELY (pad_monitor->first_buffer)) {
715     pad_monitor->first_buffer = FALSE;
716
717     if (!pad_monitor->has_segment
718         && PAD_IS_IN_PUSH_MODE (GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor)))
719     {
720       GST_VALIDATE_REPORT (pad_monitor, BUFFER_BEFORE_SEGMENT,
721           "Received buffer before Segment event");
722     }
723     if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) {
724       gint64 running_time = gst_segment_to_running_time (&pad_monitor->segment,
725           pad_monitor->segment.format, GST_BUFFER_TIMESTAMP (buffer));
726       if (running_time != 0) {
727         GST_VALIDATE_REPORT (pad_monitor, FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO,
728             "First buffer running time is not 0, it is: %" GST_TIME_FORMAT,
729             GST_TIME_ARGS (running_time));
730       }
731     }
732   }
733 }
734
735 static void
736 gst_validate_pad_monitor_update_buffer_data (GstValidatePadMonitor *
737     pad_monitor, GstBuffer * buffer)
738 {
739   pad_monitor->current_timestamp = GST_BUFFER_TIMESTAMP (buffer);
740   pad_monitor->current_duration = GST_BUFFER_DURATION (buffer);
741   if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) {
742     if (GST_CLOCK_TIME_IS_VALID (pad_monitor->timestamp_range_start)) {
743       pad_monitor->timestamp_range_start =
744           MIN (pad_monitor->timestamp_range_start,
745           GST_BUFFER_TIMESTAMP (buffer));
746     } else {
747       pad_monitor->timestamp_range_start = GST_BUFFER_TIMESTAMP (buffer);
748     }
749
750     if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) {
751       GstClockTime endts =
752           GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer);
753       if (GST_CLOCK_TIME_IS_VALID (pad_monitor->timestamp_range_end)) {
754         pad_monitor->timestamp_range_end =
755             MAX (pad_monitor->timestamp_range_end, endts);
756       } else {
757         pad_monitor->timestamp_range_end = endts;
758       }
759     }
760   }
761   GST_DEBUG_OBJECT (pad_monitor, "Current stored range: %" GST_TIME_FORMAT
762       " - %" GST_TIME_FORMAT,
763       GST_TIME_ARGS (pad_monitor->timestamp_range_start),
764       GST_TIME_ARGS (pad_monitor->timestamp_range_end));
765 }
766
767 static GstFlowReturn
768 _combine_flows (GstFlowReturn ret1, GstFlowReturn ret2)
769 {
770   if (ret1 == ret2)
771     return ret1;
772   if (ret1 <= GST_FLOW_NOT_NEGOTIATED)
773     return ret1;
774   if (ret2 <= GST_FLOW_NOT_NEGOTIATED)
775     return ret2;
776   if (ret1 == GST_FLOW_FLUSHING || ret2 == GST_FLOW_FLUSHING)
777     return GST_FLOW_FLUSHING;
778   if (ret1 == GST_FLOW_OK || ret2 == GST_FLOW_OK)
779     return GST_FLOW_OK;
780   return ret2;
781 }
782
783 static void
784 gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor *
785     monitor, GstFlowReturn ret)
786 {
787   GstIterator *iter;
788   gboolean done;
789   GstPad *otherpad;
790   GstPad *peerpad;
791   GstValidatePadMonitor *othermonitor;
792   GstFlowReturn aggregated = GST_FLOW_NOT_LINKED;
793   gboolean found_a_pad = FALSE;
794
795   iter =
796       gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
797       (monitor));
798   done = FALSE;
799   while (!done) {
800     GValue value = { 0, };
801     switch (gst_iterator_next (iter, &value)) {
802       case GST_ITERATOR_OK:
803         otherpad = g_value_get_object (&value);
804         peerpad = gst_pad_get_peer (otherpad);
805         if (peerpad) {
806           othermonitor = g_object_get_data ((GObject *) peerpad, "qa-monitor");
807           if (othermonitor) {
808             found_a_pad = TRUE;
809             GST_VALIDATE_MONITOR_LOCK (othermonitor);
810             aggregated =
811                 _combine_flows (aggregated, othermonitor->last_flow_return);
812             GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
813           }
814
815           gst_object_unref (peerpad);
816         }
817         g_value_reset (&value);
818         break;
819       case GST_ITERATOR_RESYNC:
820         gst_iterator_resync (iter);
821         break;
822       case GST_ITERATOR_ERROR:
823         GST_WARNING_OBJECT (monitor, "Internal links pad iteration error");
824         done = TRUE;
825         break;
826       case GST_ITERATOR_DONE:
827         done = TRUE;
828         break;
829     }
830   }
831   gst_iterator_free (iter);
832   if (!found_a_pad) {
833     /* no peer pad found, nothing to do */
834     return;
835   }
836   if (aggregated == GST_FLOW_OK || aggregated == GST_FLOW_EOS) {
837     /* those are acceptable situations */
838
839     if (monitor->is_eos && ret == GST_FLOW_EOS) {
840       /* this element received eos and returned eos */
841       return;
842     }
843
844     if (GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DEMUXER (monitor)
845         && ret == GST_FLOW_EOS) {
846       /* a demuxer can return EOS when the samples end */
847       return;
848     }
849   }
850
851   if (aggregated != ret) {
852     GST_VALIDATE_REPORT (monitor, WRONG_FLOW_RETURN,
853         "Wrong combined flow return %s(%d). Expected: %s(%d)",
854         gst_flow_get_name (ret), ret, gst_flow_get_name (aggregated),
855         aggregated);
856   }
857 }
858
859 static void
860     gst_validate_pad_monitor_otherpad_add_pending_serialized_event
861     (GstValidatePadMonitor * monitor, GstEvent * event, GstClockTime last_ts)
862 {
863   GstIterator *iter;
864   gboolean done;
865   GstPad *otherpad;
866   GstValidatePadMonitor *othermonitor;
867
868   if (!GST_EVENT_IS_SERIALIZED (event))
869     return;
870
871   iter =
872       gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
873       (monitor));
874   if (iter == NULL) {
875     /* inputselector will return NULL if the sinkpad is not the active one .... */
876     GST_FIXME_OBJECT (GST_VALIDATE_PAD_MONITOR_GET_PAD
877         (monitor), "No iterator");
878     return;
879   }
880   done = FALSE;
881   while (!done) {
882     GValue value = { 0, };
883     switch (gst_iterator_next (iter, &value)) {
884       case GST_ITERATOR_OK:
885         otherpad = g_value_get_object (&value);
886         othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor");
887         if (othermonitor) {
888           SerializedEventData *data = g_slice_new0 (SerializedEventData);
889           data->timestamp = last_ts;
890           data->event = gst_event_ref (event);
891           GST_VALIDATE_MONITOR_LOCK (othermonitor);
892           g_ptr_array_add (othermonitor->serialized_events, data);
893           GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
894         }
895         g_value_reset (&value);
896         break;
897       case GST_ITERATOR_RESYNC:
898         gst_iterator_resync (iter);
899         break;
900       case GST_ITERATOR_ERROR:
901         GST_WARNING_OBJECT (monitor, "Internal links pad iteration error");
902         done = TRUE;
903         break;
904       case GST_ITERATOR_DONE:
905         done = TRUE;
906         break;
907     }
908   }
909   gst_iterator_free (iter);
910 }
911
912 static void
913 gst_validate_pad_monitor_otherpad_add_pending_field (GstValidatePadMonitor *
914     monitor, GstStructure * structure, const gchar * field)
915 {
916   GstIterator *iter;
917   gboolean done;
918   GstPad *otherpad;
919   GstValidatePadMonitor *othermonitor;
920   const GValue *v;
921
922   v = gst_structure_get_value (structure, field);
923   if (v == NULL) {
924     GST_DEBUG_OBJECT (monitor, "Not adding pending field %s as it isn't "
925         "present on structure %" GST_PTR_FORMAT, field, structure);
926     return;
927   }
928
929   iter =
930       gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
931       (monitor));
932   done = FALSE;
933   while (!done) {
934     GValue value = { 0, };
935     switch (gst_iterator_next (iter, &value)) {
936       case GST_ITERATOR_OK:
937         otherpad = g_value_get_object (&value);
938         othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor");
939         if (othermonitor) {
940           GST_VALIDATE_MONITOR_LOCK (othermonitor);
941           g_assert (othermonitor->pending_setcaps_fields != NULL);
942           gst_structure_set_value (othermonitor->pending_setcaps_fields,
943               field, v);
944           GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
945         }
946         g_value_reset (&value);
947         break;
948       case GST_ITERATOR_RESYNC:
949         gst_iterator_resync (iter);
950         break;
951       case GST_ITERATOR_ERROR:
952         GST_WARNING_OBJECT (monitor, "Internal links pad iteration error");
953         done = TRUE;
954         break;
955       case GST_ITERATOR_DONE:
956         done = TRUE;
957         break;
958     }
959   }
960   gst_iterator_free (iter);
961 }
962
963 static void
964 gst_validate_pad_monitor_otherpad_clear_pending_fields (GstValidatePadMonitor *
965     monitor)
966 {
967   GstIterator *iter;
968   gboolean done;
969   GstPad *otherpad;
970   GstValidatePadMonitor *othermonitor;
971
972   iter =
973       gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
974       (monitor));
975   done = FALSE;
976   while (!done) {
977     GValue value = { 0, };
978     switch (gst_iterator_next (iter, &value)) {
979       case GST_ITERATOR_OK:
980         otherpad = g_value_get_object (&value);
981         othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor");
982         if (othermonitor) {
983           GST_VALIDATE_MONITOR_LOCK (othermonitor);
984           g_assert (othermonitor->pending_setcaps_fields != NULL);
985           gst_structure_free (othermonitor->pending_setcaps_fields);
986           othermonitor->pending_setcaps_fields =
987               gst_structure_new_empty (PENDING_FIELDS);
988           GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
989         }
990         g_value_reset (&value);
991         break;
992       case GST_ITERATOR_RESYNC:
993         gst_iterator_resync (iter);
994         break;
995       case GST_ITERATOR_ERROR:
996         GST_WARNING_OBJECT (monitor, "Internal links pad iteration error");
997         done = TRUE;
998         break;
999       case GST_ITERATOR_DONE:
1000         done = TRUE;
1001         break;
1002     }
1003   }
1004   gst_iterator_free (iter);
1005 }
1006
1007 static void
1008 gst_validate_pad_monitor_add_expected_newsegment (GstValidatePadMonitor *
1009     monitor, GstEvent * event)
1010 {
1011   GstIterator *iter;
1012   gboolean done;
1013   GstPad *otherpad;
1014   GstValidatePadMonitor *othermonitor;
1015
1016   iter =
1017       gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
1018       (monitor));
1019   done = FALSE;
1020   while (!done) {
1021     GValue value = { 0, };
1022     switch (gst_iterator_next (iter, &value)) {
1023       case GST_ITERATOR_OK:
1024         otherpad = g_value_get_object (&value);
1025         othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor");
1026         GST_VALIDATE_MONITOR_LOCK (othermonitor);
1027         if (othermonitor->expected_segment) {
1028           GST_VALIDATE_REPORT (othermonitor, EVENT_NEWSEGMENT_NOT_PUSHED, "");
1029           gst_event_unref (othermonitor->expected_segment);
1030         }
1031         othermonitor->expected_segment = gst_event_ref (event);
1032         GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1033         g_value_reset (&value);
1034         break;
1035       case GST_ITERATOR_RESYNC:
1036         gst_iterator_resync (iter);
1037         break;
1038       case GST_ITERATOR_ERROR:
1039         GST_WARNING_OBJECT (monitor, "Internal links pad iteration error");
1040         done = TRUE;
1041         break;
1042       case GST_ITERATOR_DONE:
1043         done = TRUE;
1044         break;
1045     }
1046   }
1047   gst_iterator_free (iter);
1048 }
1049
1050 static void
1051 gst_validate_pad_monitor_flush (GstValidatePadMonitor * pad_monitor)
1052 {
1053   pad_monitor->current_timestamp = GST_CLOCK_TIME_NONE;
1054   pad_monitor->current_duration = GST_CLOCK_TIME_NONE;
1055   pad_monitor->timestamp_range_start = GST_CLOCK_TIME_NONE;
1056   pad_monitor->timestamp_range_end = GST_CLOCK_TIME_NONE;
1057   pad_monitor->has_segment = FALSE;
1058   pad_monitor->is_eos = FALSE;
1059   gst_caps_replace (&pad_monitor->last_caps, NULL);
1060 }
1061
1062 /* common checks for both sink and src event functions */
1063 static void
1064 gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor *
1065     pad_monitor, GstEvent * event)
1066 {
1067   guint32 seqnum = gst_event_get_seqnum (event);
1068
1069   switch (GST_EVENT_TYPE (event)) {
1070     case GST_EVENT_FLUSH_START:
1071     {
1072       if (pad_monitor->pending_flush_start_seqnum) {
1073         if (seqnum == pad_monitor->pending_flush_start_seqnum) {
1074           pad_monitor->pending_flush_start_seqnum = 0;
1075         } else {
1076           GST_VALIDATE_REPORT (pad_monitor, EVENT_HAS_WRONG_SEQNUM,
1077               "The expected flush-start seqnum should be the same as the "
1078               "one from the event that caused it (probably a seek). Got: %u."
1079               " Expected: %u", seqnum, pad_monitor->pending_flush_start_seqnum);
1080         }
1081       }
1082
1083       if (pad_monitor->pending_flush_stop) {
1084         GST_VALIDATE_REPORT (pad_monitor, EVENT_FLUSH_START_UNEXPECTED,
1085             "Received flush-start from " " when flush-stop was expected");
1086       }
1087       pad_monitor->pending_flush_stop = TRUE;
1088     }
1089       break;
1090     case GST_EVENT_FLUSH_STOP:
1091     {
1092       if (pad_monitor->pending_flush_stop_seqnum) {
1093         if (seqnum == pad_monitor->pending_flush_stop_seqnum) {
1094           pad_monitor->pending_flush_stop_seqnum = 0;
1095         } else {
1096           GST_VALIDATE_REPORT (pad_monitor, EVENT_HAS_WRONG_SEQNUM,
1097               "The expected flush-stop seqnum should be the same as the "
1098               "one from the event that caused it (probably a seek). Got: %u."
1099               " Expected: %u", seqnum, pad_monitor->pending_flush_stop_seqnum);
1100         }
1101       }
1102
1103       if (!pad_monitor->pending_flush_stop) {
1104         GST_VALIDATE_REPORT (pad_monitor, EVENT_FLUSH_STOP_UNEXPECTED,
1105             "Unexpected flush-stop %p" GST_PTR_FORMAT, event);
1106       }
1107       pad_monitor->pending_flush_stop = FALSE;
1108
1109       /* cleanup our data */
1110       gst_validate_pad_monitor_flush (pad_monitor);
1111     }
1112       break;
1113     default:
1114       break;
1115   }
1116 }
1117
1118 static gboolean
1119 gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor *
1120     pad_monitor, GstObject * parent, GstEvent * event,
1121     GstPadEventFunction handler)
1122 {
1123   gboolean ret = TRUE;
1124   const GstSegment *segment;
1125   guint32 seqnum = gst_event_get_seqnum (event);
1126   GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor);
1127
1128   gst_validate_pad_monitor_common_event_check (pad_monitor, event);
1129
1130   /* pre checks */
1131   switch (GST_EVENT_TYPE (event)) {
1132     case GST_EVENT_SEGMENT:
1133       /* parse segment data to be used if event is handled */
1134       gst_event_parse_segment (event, &segment);
1135
1136       if (pad_monitor->pending_newsegment_seqnum) {
1137         if (pad_monitor->pending_newsegment_seqnum == seqnum) {
1138           pad_monitor->pending_newsegment_seqnum = 0;
1139         } else {
1140           /* TODO is this an error? could be a segment from the start
1141            * received just before the seek segment */
1142         }
1143       }
1144
1145       if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
1146         gst_validate_pad_monitor_add_expected_newsegment (pad_monitor, event);
1147       } else {
1148         /* check if this segment is the expected one */
1149         if (pad_monitor->expected_segment) {
1150           const GstSegment *exp_segment;
1151
1152           if (pad_monitor->expected_segment != event) {
1153             gst_event_parse_segment (pad_monitor->expected_segment,
1154                 &exp_segment);
1155             if (segment->format == exp_segment->format) {
1156               if ((exp_segment->rate * exp_segment->applied_rate !=
1157                       segment->rate * segment->applied_rate)
1158                   || exp_segment->start != segment->start
1159                   || exp_segment->stop != segment->stop
1160                   || exp_segment->position != segment->position) {
1161                 GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH,
1162                     "Expected segment didn't match received segment event");
1163               }
1164             }
1165           }
1166           gst_event_replace (&pad_monitor->expected_segment, NULL);
1167         }
1168       }
1169       break;
1170     case GST_EVENT_EOS:
1171       pad_monitor->is_eos = TRUE;
1172       /*
1173        * TODO add end of stream checks for
1174        *  - events not pushed
1175        *  - buffer data not pushed
1176        *  - pending events not received
1177        */
1178       break;
1179
1180       /* both flushes are handled by the common event function */
1181     case GST_EVENT_FLUSH_START:
1182     case GST_EVENT_FLUSH_STOP:
1183     case GST_EVENT_TAG:
1184     case GST_EVENT_SINK_MESSAGE:
1185     default:
1186       break;
1187   }
1188
1189   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1190   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
1191   gst_validate_pad_monitor_event_overrides (pad_monitor, event);
1192   if (handler) {
1193     gst_event_ref (event);
1194     ret = pad_monitor->event_func (pad, parent, event);
1195   }
1196   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
1197   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1198
1199   /* post checks */
1200   switch (GST_EVENT_TYPE (event)) {
1201     case GST_EVENT_SEGMENT:
1202       if (ret) {
1203         if (!pad_monitor->has_segment
1204             && pad_monitor->segment.format != segment->format) {
1205           gst_segment_init (&pad_monitor->segment, segment->format);
1206         }
1207         gst_segment_copy_into (segment, &pad_monitor->segment);
1208         pad_monitor->has_segment = TRUE;
1209       }
1210       break;
1211     case GST_EVENT_FLUSH_START:
1212     case GST_EVENT_FLUSH_STOP:
1213     case GST_EVENT_EOS:
1214     case GST_EVENT_TAG:
1215     case GST_EVENT_SINK_MESSAGE:
1216     default:
1217       break;
1218   }
1219
1220   if (handler)
1221     gst_event_unref (event);
1222   return ret;
1223 }
1224
1225 static gboolean
1226 gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor,
1227     GstObject * parent, GstEvent * event, GstPadEventFunction handler)
1228 {
1229   gboolean ret = TRUE;
1230   gdouble rate;
1231   GstFormat format;
1232   gint64 start, stop;
1233   GstSeekFlags seek_flags;
1234   GstSeekType start_type, stop_type;
1235   guint32 seqnum = gst_event_get_seqnum (event);
1236   GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor);
1237
1238   gst_validate_pad_monitor_common_event_check (pad_monitor, event);
1239
1240   /* pre checks */
1241   switch (GST_EVENT_TYPE (event)) {
1242     case GST_EVENT_SEEK:
1243     {
1244       gst_event_parse_seek (event, &rate, &format, &seek_flags, &start_type,
1245           &start, &stop_type, &stop);
1246       /* upstream seek - store the seek event seqnum to check
1247        * flushes and newsegments share the same */
1248
1249       /* TODO we might need to use a list as multiple seeks can be sent
1250        * before the flushes arrive here */
1251       if (seek_flags & GST_SEEK_FLAG_FLUSH) {
1252         pad_monitor->pending_flush_start_seqnum = seqnum;
1253         pad_monitor->pending_flush_stop_seqnum = seqnum;
1254       }
1255       pad_monitor->pending_newsegment_seqnum = seqnum;
1256     }
1257       break;
1258       /* both flushes are handled by the common event handling function */
1259     case GST_EVENT_FLUSH_START:
1260     case GST_EVENT_FLUSH_STOP:
1261     case GST_EVENT_NAVIGATION:
1262     case GST_EVENT_LATENCY:
1263     case GST_EVENT_STEP:
1264     case GST_EVENT_QOS:
1265     default:
1266       break;
1267   }
1268
1269   if (handler) {
1270     GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1271     gst_event_ref (event);
1272     ret = pad_monitor->event_func (pad, parent, event);
1273     GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1274   }
1275
1276   /* post checks */
1277   switch (GST_EVENT_TYPE (event)) {
1278     case GST_EVENT_FLUSH_START:
1279     case GST_EVENT_FLUSH_STOP:
1280     case GST_EVENT_QOS:
1281     case GST_EVENT_SEEK:
1282     case GST_EVENT_NAVIGATION:
1283     case GST_EVENT_LATENCY:
1284     case GST_EVENT_STEP:
1285     default:
1286       break;
1287   }
1288
1289   if (handler)
1290     gst_event_unref (event);
1291   return ret;
1292 }
1293
1294 static GstFlowReturn
1295 gst_validate_pad_monitor_chain_func (GstPad * pad, GstObject * parent,
1296     GstBuffer * buffer)
1297 {
1298   GstValidatePadMonitor *pad_monitor =
1299       g_object_get_data ((GObject *) pad, "qa-monitor");
1300   GstFlowReturn ret;
1301
1302   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
1303   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1304
1305   gst_validate_pad_monitor_check_first_buffer (pad_monitor, buffer);
1306   gst_validate_pad_monitor_update_buffer_data (pad_monitor, buffer);
1307
1308   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1309   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
1310
1311   gst_validate_pad_monitor_buffer_overrides (pad_monitor, buffer);
1312
1313   ret = pad_monitor->chain_func (pad, parent, buffer);
1314
1315   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
1316   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1317
1318   pad_monitor->last_flow_return = ret;
1319   gst_validate_pad_monitor_check_aggregated_return (pad_monitor, ret);
1320
1321   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1322   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
1323
1324   return ret;
1325 }
1326
1327 static gboolean
1328 gst_validate_pad_monitor_sink_event_func (GstPad * pad, GstObject * parent,
1329     GstEvent * event)
1330 {
1331   GstValidatePadMonitor *pad_monitor =
1332       g_object_get_data ((GObject *) pad, "qa-monitor");
1333   gboolean ret;
1334
1335   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
1336   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1337
1338   if (GST_EVENT_IS_SERIALIZED (event)) {
1339     GstClockTime last_ts;
1340     if (GST_CLOCK_TIME_IS_VALID (pad_monitor->current_timestamp)) {
1341       last_ts = pad_monitor->current_timestamp;
1342       if (GST_CLOCK_TIME_IS_VALID (pad_monitor->current_duration)) {
1343         last_ts += pad_monitor->current_duration;
1344       }
1345     } else {
1346       last_ts = 0;
1347     }
1348     gst_validate_pad_monitor_otherpad_add_pending_serialized_event (pad_monitor,
1349         event, last_ts);
1350   }
1351
1352   /* pre checks */
1353   switch (GST_EVENT_TYPE (event)) {
1354     case GST_EVENT_CAPS:{
1355       GstCaps *caps;
1356
1357       gst_event_parse_caps (event, &caps);
1358       gst_validate_pad_monitor_setcaps_pre (pad_monitor, caps);
1359       break;
1360     }
1361     default:
1362       break;
1363   }
1364   ret =
1365       gst_validate_pad_monitor_downstream_event_check (pad_monitor, parent,
1366       event, pad_monitor->event_func);
1367   /* post checks */
1368   switch (GST_EVENT_TYPE (event)) {
1369     case GST_EVENT_CAPS:{
1370       GstCaps *caps;
1371
1372       gst_event_parse_caps (event, &caps);
1373       gst_validate_pad_monitor_setcaps_post (pad_monitor, caps, ret);
1374       break;
1375     }
1376     default:
1377       break;
1378   }
1379
1380   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1381   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
1382   return ret;
1383 }
1384
1385 static gboolean
1386 gst_validate_pad_monitor_src_event_func (GstPad * pad, GstObject * parent,
1387     GstEvent * event)
1388 {
1389   GstValidatePadMonitor *pad_monitor =
1390       g_object_get_data ((GObject *) pad, "qa-monitor");
1391   gboolean ret;
1392
1393   GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1394   ret = gst_validate_pad_monitor_src_event_check (pad_monitor, parent, event,
1395       pad_monitor->event_func);
1396   GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1397   return ret;
1398 }
1399
1400 static gboolean
1401 gst_validate_pad_monitor_query_func (GstPad * pad, GstObject * parent,
1402     GstQuery * query)
1403 {
1404   GstValidatePadMonitor *pad_monitor =
1405       g_object_get_data ((GObject *) pad, "qa-monitor");
1406   gboolean ret;
1407
1408   gst_validate_pad_monitor_query_overrides (pad_monitor, query);
1409
1410   ret = pad_monitor->query_func (pad, parent, query);
1411
1412   if (ret) {
1413     switch (GST_QUERY_TYPE (query)) {
1414       case GST_QUERY_CAPS:{
1415         GstCaps *res;
1416         /* We shouldn't need to lock the parent as this doesn't modify
1417          * other monitors, just does some peer_pad_caps */
1418         GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1419
1420         gst_query_parse_caps_result (query, &res);
1421         if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
1422           gst_validate_pad_monitor_check_caps_fields_proxied (pad_monitor, res);
1423         }
1424         GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1425         break;
1426       }
1427       default:
1428         break;
1429     }
1430   }
1431
1432   return ret;
1433 }
1434
1435 static gboolean
1436 gst_validate_pad_get_range_func (GstPad * pad, GstObject * parent,
1437     guint64 offset, guint size, GstBuffer ** buffer)
1438 {
1439   GstValidatePadMonitor *pad_monitor =
1440       g_object_get_data ((GObject *) pad, "qa-monitor");
1441   gboolean ret;
1442   ret = pad_monitor->getrange_func (pad, parent, offset, size, buffer);
1443   return ret;
1444 }
1445
1446 static gboolean
1447 gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer,
1448     gpointer udata)
1449 {
1450   GstValidatePadMonitor *monitor = udata;
1451   GstValidateMonitor *parent = GST_VALIDATE_MONITOR_GET_PARENT (monitor);
1452
1453   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor);
1454   GST_VALIDATE_MONITOR_LOCK (monitor);
1455
1456   gst_validate_pad_monitor_check_first_buffer (monitor, buffer);
1457   gst_validate_pad_monitor_update_buffer_data (monitor, buffer);
1458
1459   gst_validate_pad_monitor_check_buffer_timestamp_in_received_range (monitor,
1460       buffer);
1461
1462   gst_validate_pad_monitor_check_late_serialized_events (monitor,
1463       GST_BUFFER_TIMESTAMP (buffer));
1464
1465   if (G_LIKELY (parent)) {
1466     /* a GstValidatePadMonitor parent must be a GstValidateElementMonitor */
1467     if (GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DECODER (parent)) {
1468       /* should not push out of segment data */
1469       if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer)) &&
1470           GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer)) &&
1471           !gst_segment_clip (&monitor->segment, monitor->segment.format,
1472               GST_BUFFER_TIMESTAMP (buffer), GST_BUFFER_TIMESTAMP (buffer) +
1473               GST_BUFFER_DURATION (buffer), NULL, NULL)) {
1474         /* TODO is this a timestamp issue? */
1475         GST_VALIDATE_REPORT (monitor, BUFFER_IS_OUT_OF_SEGMENT,
1476             "buffer is out of segment and shouldn't be pushed. Timestamp: %"
1477             GST_TIME_FORMAT " - duration: %" GST_TIME_FORMAT ". Range: %"
1478             GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
1479             GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
1480             GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)),
1481             GST_TIME_ARGS (monitor->segment.start),
1482             GST_TIME_ARGS (monitor->segment.stop));
1483       }
1484     }
1485   }
1486
1487   GST_VALIDATE_MONITOR_UNLOCK (monitor);
1488   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (monitor);
1489   gst_validate_pad_monitor_buffer_probe_overrides (monitor, buffer);
1490   return TRUE;
1491 }
1492
1493 static gboolean
1494 gst_validate_pad_monitor_event_probe (GstPad * pad, GstEvent * event,
1495     gpointer udata)
1496 {
1497   GstValidatePadMonitor *monitor = GST_VALIDATE_PAD_MONITOR_CAST (udata);
1498   gboolean ret;
1499
1500   GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor);
1501   GST_VALIDATE_MONITOR_LOCK (monitor);
1502
1503   if (GST_EVENT_IS_SERIALIZED (event)) {
1504     gint i;
1505
1506     if (monitor->serialized_events->len > 0) {
1507       SerializedEventData *next_event =
1508           g_ptr_array_index (monitor->serialized_events, 0);
1509
1510       if (event == next_event->event
1511           || GST_EVENT_TYPE (event) == GST_EVENT_TYPE (next_event->event)) {
1512         g_ptr_array_remove_index (monitor->serialized_events, 0);
1513       }
1514     } else {
1515       /* if the event is not the first, it might be out of order */
1516       for (i = 0; i < monitor->serialized_events->len; i++) {
1517         SerializedEventData *stored_event =
1518             g_ptr_array_index (monitor->serialized_events, i);
1519
1520         if (event == stored_event->event
1521             || GST_EVENT_TYPE (event) == GST_EVENT_TYPE (stored_event->event)) {
1522           GST_VALIDATE_REPORT (monitor, EVENT_SERIALIZED_OUT_OF_ORDER,
1523               "Serialized event %" GST_PTR_FORMAT " was pushed out of original "
1524               "serialization order in pad %s:%s", event,
1525               GST_DEBUG_PAD_NAME (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor)));
1526         }
1527       }
1528     }
1529   }
1530
1531   /* This so far is just like an event that is flowing downstream,
1532    * so we do the same checks as a sinkpad event handler */
1533   ret =
1534       gst_validate_pad_monitor_downstream_event_check (monitor, NULL, event,
1535       NULL);
1536   GST_VALIDATE_MONITOR_UNLOCK (monitor);
1537   GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (monitor);
1538
1539   return ret;
1540 }
1541
1542 static GstPadProbeReturn
1543 gst_validate_pad_monitor_pad_probe (GstPad * pad, GstPadProbeInfo * info,
1544     gpointer udata)
1545 {
1546   if (info->type & GST_PAD_PROBE_TYPE_BUFFER)
1547     gst_validate_pad_monitor_buffer_probe (pad, info->data, udata);
1548   else if (info->type & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM)
1549     gst_validate_pad_monitor_event_probe (pad, info->data, udata);
1550
1551   return GST_PAD_PROBE_OK;
1552 }
1553
1554 static void
1555 gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor,
1556     GstCaps * caps)
1557 {
1558   GstStructure *structure;
1559
1560   /* Check if caps are identical to last caps and complain if so */
1561   if (pad_monitor->last_caps
1562       && gst_caps_is_equal (caps, pad_monitor->last_caps)) {
1563     GST_VALIDATE_REPORT (pad_monitor, EVENT_CAPS_DUPLICATE, "%" GST_PTR_FORMAT,
1564         caps);
1565   }
1566
1567   gst_validate_pad_monitor_check_caps_complete (pad_monitor, caps);
1568
1569   if (caps) {
1570     structure = gst_caps_get_structure (caps, 0);
1571     if (gst_structure_n_fields (pad_monitor->pending_setcaps_fields)) {
1572       gint i;
1573       for (i = 0;
1574           i < gst_structure_n_fields (pad_monitor->pending_setcaps_fields);
1575           i++) {
1576         const gchar *name =
1577             gst_structure_nth_field_name (pad_monitor->pending_setcaps_fields,
1578             i);
1579         const GValue *v = gst_structure_get_value (structure, name);
1580         const GValue *otherv =
1581             gst_structure_get_value (pad_monitor->pending_setcaps_fields, name);
1582
1583         if (v == NULL) {
1584           GST_VALIDATE_REPORT (pad_monitor, CAPS_EXPECTED_FIELD_NOT_FOUND,
1585               "Field %s is missing from setcaps caps '%" GST_PTR_FORMAT "'",
1586               name, caps);
1587         } else if (gst_value_compare (v, otherv) != GST_VALUE_EQUAL) {
1588           GST_VALIDATE_REPORT (pad_monitor, CAPS_FIELD_UNEXPECTED_VALUE,
1589               "Field %s from setcaps caps '%" GST_PTR_FORMAT "' is different "
1590               "from expected value in caps '%" GST_PTR_FORMAT "'", name, caps,
1591               pad_monitor->pending_setcaps_fields);
1592         }
1593       }
1594     }
1595
1596     if (gst_validate_pad_monitor_pad_should_proxy_othercaps (pad_monitor)) {
1597       if (_structure_is_video (structure)) {
1598         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
1599             structure, "width");
1600         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
1601             structure, "height");
1602         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
1603             structure, "framerate");
1604         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
1605             structure, "pixel-aspect-ratio");
1606       } else if (_structure_is_audio (structure)) {
1607         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
1608             structure, "rate");
1609         gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
1610             structure, "channels");
1611       }
1612     }
1613   }
1614
1615   gst_structure_free (pad_monitor->pending_setcaps_fields);
1616   pad_monitor->pending_setcaps_fields =
1617       gst_structure_new_empty (PENDING_FIELDS);
1618
1619   gst_validate_pad_monitor_setcaps_overrides (pad_monitor, caps);
1620 }
1621
1622 static void
1623 gst_validate_pad_monitor_setcaps_post (GstValidatePadMonitor * pad_monitor,
1624     GstCaps * caps, gboolean ret)
1625 {
1626   if (!ret)
1627     gst_validate_pad_monitor_otherpad_clear_pending_fields (pad_monitor);
1628   else {
1629     if (pad_monitor->last_caps) {
1630       gst_caps_unref (pad_monitor->last_caps);
1631     }
1632     pad_monitor->last_caps = gst_caps_ref (caps);
1633   }
1634 }
1635
1636 static gboolean
1637 gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor)
1638 {
1639   GstValidatePadMonitor *pad_monitor = GST_VALIDATE_PAD_MONITOR_CAST (monitor);
1640   GstPad *pad;
1641   if (!GST_IS_PAD (GST_VALIDATE_MONITOR_GET_OBJECT (monitor))) {
1642     GST_WARNING_OBJECT (monitor, "Trying to create pad monitor with other "
1643         "type of object");
1644     return FALSE;
1645   }
1646
1647   pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor);
1648
1649   if (g_object_get_data ((GObject *) pad, "qa-monitor")) {
1650     GST_WARNING_OBJECT (pad_monitor, "Pad already has a qa-monitor associated");
1651     return FALSE;
1652   }
1653
1654   g_object_set_data ((GObject *) pad, "qa-monitor", pad_monitor);
1655
1656   pad_monitor->pad = pad;
1657
1658   pad_monitor->event_func = GST_PAD_EVENTFUNC (pad);
1659   pad_monitor->query_func = GST_PAD_QUERYFUNC (pad);
1660   if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
1661
1662     pad_monitor->chain_func = GST_PAD_CHAINFUNC (pad);
1663     if (pad_monitor->chain_func)
1664       gst_pad_set_chain_function (pad, gst_validate_pad_monitor_chain_func);
1665
1666     gst_pad_set_event_function (pad, gst_validate_pad_monitor_sink_event_func);
1667   } else {
1668     pad_monitor->getrange_func = GST_PAD_GETRANGEFUNC (pad);
1669     if (pad_monitor->getrange_func)
1670       gst_pad_set_getrange_function (pad, gst_validate_pad_get_range_func);
1671
1672     gst_pad_set_event_function (pad, gst_validate_pad_monitor_src_event_func);
1673
1674     /* add buffer/event probes */
1675     pad_monitor->pad_probe_id =
1676         gst_pad_add_probe (pad,
1677         GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM |
1678         GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1679         (GstPadProbeCallback) gst_validate_pad_monitor_pad_probe, pad_monitor,
1680         NULL);
1681   }
1682   gst_pad_set_query_function (pad, gst_validate_pad_monitor_query_func);
1683
1684   gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (monitor),
1685       g_strdup_printf ("%s:%s", GST_DEBUG_PAD_NAME (pad)));
1686
1687   if (G_UNLIKELY (GST_PAD_PARENT (pad) == NULL))
1688     GST_FIXME ("Saw a pad not belonging to any object");
1689
1690   return TRUE;
1691 }