3 * Copyright (C) 2013 Collabora Ltd.
4 * Author: Thiago Sousa Santos <thiago.sousa.santos@collabora.com>
6 * gst-validate-pad-monitor.c - Validate PadMonitor class
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.
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.
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.
28 #include "gst-validate-internal.h"
29 #include "gst-validate-pad-monitor.h"
30 #include "gst-validate-element-monitor.h"
31 #include "gst-validate-reporter.h"
36 * SECTION:gst-validate-pad-monitor
37 * @short_description: Class that wraps a #GstPad for Validate checks
42 static GstValidateInterceptionReturn
43 gst_validate_pad_monitor_intercept_report (GstValidateReporter * reporter,
44 GstValidateReport * report);
47 G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, _reporter_iface_init)
50 _reporter_iface_init (GstValidateReporterInterface * iface)
52 iface->intercept_report = gst_validate_pad_monitor_intercept_report;
55 #define gst_validate_pad_monitor_parent_class parent_class
56 G_DEFINE_TYPE_WITH_CODE (GstValidatePadMonitor, gst_validate_pad_monitor,
57 GST_TYPE_VALIDATE_MONITOR, _do_init);
59 #define PENDING_FIELDS "pending-fields"
60 #define AUDIO_TIMESTAMP_TOLERANCE (GST_MSECOND * 100)
62 #define PAD_PARENT_IS_DEMUXER(m) \
63 (GST_VALIDATE_MONITOR_GET_PARENT(m) ? \
64 GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DEMUXER ( \
65 GST_VALIDATE_MONITOR_GET_PARENT(m)) : \
68 #define PAD_PARENT_IS_DECODER(m) \
69 (GST_VALIDATE_MONITOR_GET_PARENT(m) ? \
70 GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DECODER ( \
71 GST_VALIDATE_MONITOR_GET_PARENT(m)) : \
74 #define PAD_PARENT_IS_ENCODER(m) \
75 (GST_VALIDATE_MONITOR_GET_PARENT(m) ? \
76 GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_ENCODER ( \
77 GST_VALIDATE_MONITOR_GET_PARENT(m)) : \
82 * Locking the parent should always be done before locking the
83 * pad-monitor to prevent deadlocks in case another monitor from
84 * another pad on the same element starts an operation that also
85 * requires locking itself and some other monitors from internally
89 * An element has a sink and a src pad. Some test starts running at sinkpad
90 * and it locks the parent, and then it locks itself. In case it needs to get
91 * some information from the srcpad, it is able to lock the srcpad and get it
92 * because the srcpad should never lock itself before locking the parent (which
93 * it won't be able as sinkpad already locked it).
95 * As a side one, it is possible that srcpad locks itself without locking the
96 * parent in case it wants to do a check that won't need to use other internally
97 * linked pads (sinkpad). But in this case it might lock and unlock freely without
100 #define GST_VALIDATE_PAD_MONITOR_PARENT_LOCK(m) \
102 if (G_LIKELY (GST_VALIDATE_MONITOR_GET_PARENT (m))) { \
103 GST_VALIDATE_MONITOR_LOCK (GST_VALIDATE_MONITOR_GET_PARENT (m)); \
105 GST_WARNING_OBJECT (m, "No parent found, can't lock"); \
109 #define GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK(m) \
111 if (G_LIKELY (GST_VALIDATE_MONITOR_GET_PARENT (m))) { \
112 GST_VALIDATE_MONITOR_UNLOCK (GST_VALIDATE_MONITOR_GET_PARENT (m)); \
114 GST_WARNING_OBJECT (m, "No parent found, can't unlock"); \
120 GstClockTime timestamp;
122 } SerializedEventData;
126 _find_master_report_on_pad (GstPad * pad, GstValidateReport * report)
128 GstValidatePadMonitor *pad_monitor;
129 GstValidateReport *prev_report;
131 gboolean result = FALSE;
133 gst_object_ref (pad);
136 /* We don't monitor ghost pads */
137 while (GST_IS_GHOST_PAD (pad)) {
139 pad = gst_ghost_pad_get_target ((GstGhostPad *) pad);
140 gst_object_unref (tmp_pad);
143 while (GST_IS_PROXY_PAD (pad)) {
145 pad = gst_pad_get_peer (pad);
146 gst_object_unref (tmp_pad);
149 pad_monitor = g_object_get_data ((GObject *) pad, "validate-monitor");
151 /* For some reason this pad isn't monitored */
152 if (pad_monitor == NULL)
155 prev_report = gst_validate_reporter_get_report ((GstValidateReporter *)
156 pad_monitor, report->issue->issue_id);
159 if (prev_report->master_report)
160 gst_validate_report_set_master_report (report,
161 prev_report->master_report);
163 gst_validate_report_set_master_report (report, prev_report);
168 gst_object_unref (pad);
174 _find_master_report_for_sink_pad (GstValidatePadMonitor * pad_monitor,
175 GstValidateReport * report)
178 gboolean result = FALSE;
180 peerpad = gst_pad_get_peer (pad_monitor->pad);
182 /* If the peer src pad already has a similar report no need to look
184 if (peerpad && _find_master_report_on_pad (peerpad, report))
188 gst_object_unref (peerpad);
194 _find_master_report_for_src_pad (GstValidatePadMonitor * pad_monitor,
195 GstValidateReport * report)
200 gboolean result = FALSE;
203 gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
207 GValue value = { 0, };
208 switch (gst_iterator_next (iter, &value)) {
209 case GST_ITERATOR_OK:
210 pad = g_value_get_object (&value);
212 if (_find_master_report_on_pad (pad, report)) {
217 g_value_reset (&value);
219 case GST_ITERATOR_RESYNC:
220 gst_iterator_resync (iter);
222 case GST_ITERATOR_ERROR:
223 GST_WARNING_OBJECT (pad_monitor->pad,
224 "Internal links pad iteration error");
227 case GST_ITERATOR_DONE:
232 gst_iterator_free (iter);
237 static GstValidateInterceptionReturn
238 gst_validate_pad_monitor_intercept_report (GstValidateReporter *
239 reporter, GstValidateReport * report)
241 GstValidateReporterInterface *iface_class, *old_iface_class;
242 GstValidatePadMonitor *pad_monitor = GST_VALIDATE_PAD_MONITOR (reporter);
245 G_TYPE_INSTANCE_GET_INTERFACE (reporter, GST_TYPE_VALIDATE_REPORTER,
246 GstValidateReporterInterface);
247 old_iface_class = g_type_interface_peek_parent (iface_class);
249 old_iface_class->intercept_report (reporter, report);
251 if (GST_PAD_IS_SINK (pad_monitor->pad)
252 && _find_master_report_for_sink_pad (pad_monitor, report))
253 return GST_VALIDATE_REPORTER_KEEP;
254 else if (GST_PAD_IS_SRC (pad_monitor->pad)
255 && _find_master_report_for_src_pad (pad_monitor, report))
256 return GST_VALIDATE_REPORTER_KEEP;
258 return GST_VALIDATE_REPORTER_REPORT;
262 debug_pending_event (GstPad * pad, GPtrArray * array)
267 for (i = 0; i < len; i++) {
268 SerializedEventData *data = g_ptr_array_index (array, i);
269 GST_DEBUG_OBJECT (pad, "event #%d %" GST_TIME_FORMAT " %s %p",
270 i, GST_TIME_ARGS (data->timestamp),
271 GST_EVENT_TYPE_NAME (data->event), data->event);
276 _serialized_event_data_free (SerializedEventData * serialized_event)
278 gst_event_unref (serialized_event->event);
279 g_slice_free (SerializedEventData, serialized_event);
282 static gboolean gst_validate_pad_monitor_do_setup (GstValidateMonitor *
284 static GstElement *gst_validate_pad_monitor_get_element (GstValidateMonitor *
287 gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor,
289 static void gst_validate_pad_monitor_setcaps_post (GstValidatePadMonitor *
290 pad_monitor, GstCaps * caps, gboolean ret);
292 #define PAD_IS_IN_PUSH_MODE(p) ((p)->mode == GST_PAD_MODE_PUSH)
295 _structure_is_raw_video (GstStructure * structure)
297 return gst_structure_has_name (structure, "video/x-raw");
301 _structure_is_raw_audio (GstStructure * structure)
303 return gst_structure_has_name (structure, "audio/x-raw");
307 _get_event_string (GstEvent * event)
309 const GstStructure *st;
311 if ((st = gst_event_get_structure (event)))
312 return gst_structure_to_string (st);
314 return g_strdup_printf ("%s", GST_EVENT_TYPE_NAME (event));
318 _check_field_type (GstValidatePadMonitor * monitor,
319 GstStructure * structure, gboolean mandatory, const gchar * field, ...)
323 gchar *joined_types = NULL;
324 const gchar *rejected_types[5];
325 gint rejected_types_index = 0;
328 if (!gst_structure_has_field (structure, field)) {
330 gchar *str = gst_structure_to_string (structure);
332 GST_VALIDATE_REPORT (monitor, CAPS_IS_MISSING_FIELD,
333 "Field '%s' is missing from structure: %s", field, str);
336 GST_DEBUG_OBJECT (monitor, "Field %s is missing but is not mandatory",
342 memset (rejected_types, 0, sizeof (rejected_types));
343 va_start (var_args, field);
344 while ((type = va_arg (var_args, GType)) != 0) {
345 if (gst_structure_has_field_typed (structure, field, type)) {
349 rejected_types[rejected_types_index++] = g_type_name (type);
353 joined_types = g_strjoinv (" / ", (gchar **) rejected_types);
354 struct_str = gst_structure_to_string (structure);
355 GST_VALIDATE_REPORT (monitor, CAPS_FIELD_HAS_BAD_TYPE,
356 "Field '%s' has wrong type %s in structure '%s'. Expected: %s", field,
357 g_type_name (gst_structure_get_field_type (structure, field)), struct_str,
359 g_free (joined_types);
364 gst_validate_pad_monitor_check_raw_video_caps_complete (GstValidatePadMonitor *
365 monitor, GstStructure * structure)
367 _check_field_type (monitor, structure, TRUE, "width", G_TYPE_INT,
368 GST_TYPE_INT_RANGE, 0);
369 _check_field_type (monitor, structure, TRUE, "height", G_TYPE_INT,
370 GST_TYPE_INT_RANGE, 0);
371 _check_field_type (monitor, structure, TRUE, "framerate", GST_TYPE_FRACTION,
372 GST_TYPE_FRACTION_RANGE, 0);
373 _check_field_type (monitor, structure, FALSE, "pixel-aspect-ratio",
374 GST_TYPE_FRACTION, GST_TYPE_FRACTION_RANGE, 0);
375 _check_field_type (monitor, structure, TRUE, "format", G_TYPE_STRING,
380 gst_validate_pad_monitor_check_raw_audio_caps_complete (GstValidatePadMonitor *
381 monitor, GstStructure * structure)
384 _check_field_type (monitor, structure, TRUE, "format", G_TYPE_STRING,
386 _check_field_type (monitor, structure, TRUE, "layout", G_TYPE_STRING,
388 _check_field_type (monitor, structure, TRUE, "rate", G_TYPE_INT,
389 GST_TYPE_LIST, GST_TYPE_INT_RANGE, 0);
390 _check_field_type (monitor, structure, TRUE, "channels", G_TYPE_INT,
391 GST_TYPE_LIST, GST_TYPE_INT_RANGE, 0);
392 if (gst_structure_get_int (structure, "channels", &channels)) {
394 _check_field_type (monitor, structure, TRUE, "channel-mask",
395 GST_TYPE_BITMASK, GST_TYPE_LIST, 0);
400 gst_validate_pad_monitor_check_caps_complete (GstValidatePadMonitor * monitor,
403 GstStructure *structure;
406 GST_DEBUG_OBJECT (monitor->pad, "Checking caps %" GST_PTR_FORMAT, caps);
408 for (i = 0; i < gst_caps_get_size (caps); i++) {
409 structure = gst_caps_get_structure (caps, i);
411 if (_structure_is_raw_video (structure)) {
412 gst_validate_pad_monitor_check_raw_video_caps_complete (monitor,
415 } else if (_structure_is_raw_audio (structure)) {
416 gst_validate_pad_monitor_check_raw_audio_caps_complete (monitor,
423 gst_validate_pad_monitor_get_othercaps (GstValidatePadMonitor * monitor)
425 GstCaps *caps = gst_caps_new_empty ();
432 gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
436 GValue value = { 0, };
437 switch (gst_iterator_next (iter, &value)) {
438 case GST_ITERATOR_OK:
439 otherpad = g_value_get_object (&value);
441 /* TODO What would be the correct caps operation to merge the caps in
442 * case one sink is internally linked to multiple srcs? */
443 peercaps = gst_pad_get_current_caps (otherpad);
445 caps = gst_caps_merge (caps, peercaps);
447 g_value_reset (&value);
449 case GST_ITERATOR_RESYNC:
450 gst_iterator_resync (iter);
451 gst_caps_replace (&caps, gst_caps_new_empty ());
453 case GST_ITERATOR_ERROR:
454 GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error");
457 case GST_ITERATOR_DONE:
462 gst_iterator_free (iter);
464 GST_DEBUG_OBJECT (monitor->pad, "Otherpad caps: %" GST_PTR_FORMAT, caps);
470 _structure_is_video (GstStructure * structure)
472 const gchar *name = gst_structure_get_name (structure);
474 return g_strstr_len (name, 6, "video/")
475 && strcmp (name, "video/quicktime") != 0;
479 _structure_is_audio (GstStructure * structure)
481 const gchar *name = gst_structure_get_name (structure);
483 return g_strstr_len (name, 6, "audio/") != NULL;
487 gst_validate_pad_monitor_pad_should_proxy_othercaps (GstValidatePadMonitor *
490 GstValidateMonitor *parent = GST_VALIDATE_MONITOR_GET_PARENT (monitor);
495 /* We only know how to handle othercaps checks for codecs so far */
496 return GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_DECODER (parent) ||
497 GST_VALIDATE_ELEMENT_MONITOR_ELEMENT_IS_ENCODER (parent);
501 /* Check if the field @f from @s2 (if present) is represented in @s1
502 * Represented here means either equal or @s1's value is in a list/range
506 _structures_field_is_contained (GstStructure * s1, GstStructure * s2,
507 gboolean mandatory, const gchar * f)
512 v2 = gst_structure_get_value (s2, f);
514 return TRUE; /* nothing to compare to */
516 v1 = gst_structure_get_value (s1, f);
520 if (!gst_value_is_fixed (v1))
523 if (gst_value_compare (v1, v2) == GST_VALUE_EQUAL)
526 if (GST_VALUE_HOLDS_LIST (v2)) {
528 for (i = 0; i < gst_value_list_get_size (v2); i++) {
529 const GValue *v2_subvalue = gst_value_list_get_value (v2, i);
530 if (gst_value_compare (v1, v2_subvalue) == GST_VALUE_EQUAL)
535 if (GST_VALUE_HOLDS_ARRAY (v2)) {
537 for (i = 0; i < gst_value_array_get_size (v2); i++) {
538 const GValue *v2_subvalue = gst_value_array_get_value (v2, i);
539 if (gst_value_compare (v1, v2_subvalue) == GST_VALUE_EQUAL)
544 if (GST_VALUE_HOLDS_INT_RANGE (v2)) {
547 min = gst_value_get_int_range_min (v2);
548 max = gst_value_get_int_range_max (v2);
550 if (G_VALUE_HOLDS_INT (v1)) {
551 gint v = g_value_get_int (v1);
553 return v >= min && v <= max;
555 /* TODO compare int ranges with int ranges
556 * or with lists if useful */
560 if (GST_VALUE_HOLDS_FRACTION_RANGE (v2)) {
561 const GValue *min, *max;
563 min = gst_value_get_fraction_range_min (v2);
564 max = gst_value_get_fraction_range_max (v2);
566 if (GST_VALUE_HOLDS_FRACTION (v1)) {
567 gint v_min = gst_value_compare (v1, min);
568 gint v_max = gst_value_compare (v1, max);
570 return (v_min == GST_VALUE_EQUAL || v_min == GST_VALUE_GREATER_THAN) &&
571 (v_max == GST_VALUE_EQUAL || v_max == GST_VALUE_LESS_THAN);
573 /* TODO compare fraction ranges with fraction ranges
574 * or with lists if useful */
582 gst_validate_pad_monitor_check_caps_fields_proxied (GstValidatePadMonitor *
583 monitor, GstCaps * caps)
585 GstStructure *structure;
586 GstStructure *otherstructure;
590 if (!gst_validate_pad_monitor_pad_should_proxy_othercaps (monitor))
593 othercaps = gst_validate_pad_monitor_get_othercaps (monitor);
595 for (i = 0; i < gst_caps_get_size (othercaps); i++) {
596 gboolean found = FALSE;
597 gboolean type_match = FALSE;
599 otherstructure = gst_caps_get_structure (othercaps, i);
601 /* look for a proxied version of 'otherstructure' */
602 if (_structure_is_video (otherstructure)) {
603 for (j = 0; j < gst_caps_get_size (caps); j++) {
604 structure = gst_caps_get_structure (caps, j);
605 if (_structure_is_video (structure)) {
607 if (_structures_field_is_contained (structure, otherstructure, TRUE,
609 && _structures_field_is_contained (structure, otherstructure,
611 && _structures_field_is_contained (structure, otherstructure,
613 && _structures_field_is_contained (structure, otherstructure,
614 FALSE, "pixel-aspect-ratio")) {
620 } else if (_structure_is_audio (otherstructure)) {
621 for (j = 0; j < gst_caps_get_size (caps); j++) {
622 structure = gst_caps_get_structure (caps, j);
623 if (_structure_is_audio (structure)) {
625 if (_structures_field_is_contained (structure, otherstructure, TRUE,
627 && _structures_field_is_contained (structure, otherstructure,
636 if (type_match && !found) {
637 gchar *otherstruct_str = gst_structure_to_string (otherstructure),
638 *caps_str = gst_caps_to_string (caps);
640 GST_VALIDATE_REPORT (monitor, GET_CAPS_NOT_PROXYING_FIELDS,
641 "Peer pad structure '%s' has no similar version "
642 "on pad's caps '%s'", otherstruct_str, caps_str);
644 g_free (otherstruct_str);
651 gst_validate_pad_monitor_check_late_serialized_events (GstValidatePadMonitor *
652 monitor, GstClockTime ts)
656 if (!GST_CLOCK_TIME_IS_VALID (ts))
659 GST_DEBUG_OBJECT (monitor->pad, "Timestamp to check %" GST_TIME_FORMAT,
662 for (i = 0; i < monitor->serialized_events->len; i++) {
663 SerializedEventData *data =
664 g_ptr_array_index (monitor->serialized_events, i);
666 GST_DEBUG_OBJECT (monitor->pad, "Event #%d (%s) ts: %" GST_TIME_FORMAT,
667 i, GST_EVENT_TYPE_NAME (data->event), GST_TIME_ARGS (data->timestamp));
669 if (GST_CLOCK_TIME_IS_VALID (data->timestamp) && data->timestamp < ts) {
670 gchar *event_str = _get_event_string (data->event);
672 GST_VALIDATE_REPORT (monitor, SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME,
673 "Serialized event %s wasn't pushed before expected " "timestamp %"
674 GST_TIME_FORMAT " on pad %s:%s", event_str,
675 GST_TIME_ARGS (data->timestamp),
676 GST_DEBUG_PAD_NAME (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor)));
680 /* events should be ordered by ts */
686 debug_pending_event (monitor->pad, monitor->serialized_events);
687 g_ptr_array_remove_range (monitor->serialized_events, 0, i);
692 gst_validate_pad_monitor_dispose (GObject * object)
694 GstValidatePadMonitor *monitor = GST_VALIDATE_PAD_MONITOR_CAST (object);
695 GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor);
698 if (monitor->pad_probe_id)
699 gst_pad_remove_probe (pad, monitor->pad_probe_id);
702 if (monitor->expected_segment)
703 gst_event_unref (monitor->expected_segment);
705 gst_structure_free (monitor->pending_setcaps_fields);
706 g_ptr_array_unref (monitor->serialized_events);
707 g_list_free_full (monitor->expired_events, (GDestroyNotify) gst_event_unref);
709 G_OBJECT_CLASS (parent_class)->dispose (object);
713 gst_validate_pad_monitor_class_init (GstValidatePadMonitorClass * klass)
715 GObjectClass *gobject_class;
716 GstValidateMonitorClass *monitor_klass;
718 gobject_class = G_OBJECT_CLASS (klass);
719 monitor_klass = GST_VALIDATE_MONITOR_CLASS (klass);
721 gobject_class->dispose = gst_validate_pad_monitor_dispose;
723 monitor_klass->setup = gst_validate_pad_monitor_do_setup;
724 monitor_klass->get_element = gst_validate_pad_monitor_get_element;
728 gst_validate_pad_monitor_init (GstValidatePadMonitor * pad_monitor)
730 pad_monitor->pending_setcaps_fields =
731 gst_structure_new_empty (PENDING_FIELDS);
732 pad_monitor->serialized_events =
733 g_ptr_array_new_with_free_func ((GDestroyNotify)
734 _serialized_event_data_free);
735 pad_monitor->expired_events = NULL;
736 gst_segment_init (&pad_monitor->segment, GST_FORMAT_BYTES);
737 pad_monitor->first_buffer = TRUE;
739 pad_monitor->timestamp_range_start = GST_CLOCK_TIME_NONE;
740 pad_monitor->timestamp_range_end = GST_CLOCK_TIME_NONE;
744 * gst_validate_pad_monitor_new:
745 * @pad: (transfer-none): a #GstPad to run Validate on
747 GstValidatePadMonitor *
748 gst_validate_pad_monitor_new (GstPad * pad, GstValidateRunner * runner,
749 GstValidateElementMonitor * parent)
751 GstValidatePadMonitor *monitor = g_object_new (GST_TYPE_VALIDATE_PAD_MONITOR,
752 "object", pad, "validate-runner", runner, "validate-parent",
755 if (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor) == NULL) {
756 g_object_unref (monitor);
763 gst_validate_pad_monitor_get_element (GstValidateMonitor * monitor)
765 GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor);
767 return GST_PAD_PARENT (pad);
771 gst_validate_pad_monitor_event_overrides (GstValidatePadMonitor * pad_monitor,
776 GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
777 for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
778 iter = g_list_next (iter)) {
779 GstValidateOverride *override = iter->data;
781 gst_validate_override_event_handler (override,
782 GST_VALIDATE_MONITOR_CAST (pad_monitor), event);
784 GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
788 gst_validate_pad_monitor_buffer_overrides (GstValidatePadMonitor * pad_monitor,
793 GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
794 for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
795 iter = g_list_next (iter)) {
796 GstValidateOverride *override = iter->data;
798 gst_validate_override_buffer_handler (override,
799 GST_VALIDATE_MONITOR_CAST (pad_monitor), buffer);
801 GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
805 gst_validate_pad_monitor_buffer_probe_overrides (GstValidatePadMonitor *
806 pad_monitor, GstBuffer * buffer)
810 GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
811 for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
812 iter = g_list_next (iter)) {
813 GstValidateOverride *override = iter->data;
815 gst_validate_override_buffer_probe_handler (override,
816 GST_VALIDATE_MONITOR_CAST (pad_monitor), buffer);
818 GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
822 gst_validate_pad_monitor_query_overrides (GstValidatePadMonitor * pad_monitor,
827 GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
828 for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
829 iter = g_list_next (iter)) {
830 GstValidateOverride *override = iter->data;
832 gst_validate_override_query_handler (override,
833 GST_VALIDATE_MONITOR_CAST (pad_monitor), query);
835 GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
839 gst_validate_pad_monitor_setcaps_overrides (GstValidatePadMonitor * pad_monitor,
844 GST_VALIDATE_MONITOR_OVERRIDES_LOCK (pad_monitor);
845 for (iter = GST_VALIDATE_MONITOR_OVERRIDES (pad_monitor).head; iter;
846 iter = g_list_next (iter)) {
847 GstValidateOverride *override = iter->data;
849 gst_validate_override_setcaps_handler (override,
850 GST_VALIDATE_MONITOR_CAST (pad_monitor), caps);
852 GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (pad_monitor);
855 /* FIXME : This is a bit dubious, what's the point of this check ? */
857 gst_validate_pad_monitor_timestamp_is_in_received_range (GstValidatePadMonitor *
858 monitor, GstClockTime ts, GstClockTime tolerance)
860 GST_DEBUG_OBJECT (monitor->pad, "Checking if timestamp %" GST_TIME_FORMAT
861 " is in range: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT " for pad "
862 "%s:%s with tolerance: %" GST_TIME_FORMAT, GST_TIME_ARGS (ts),
863 GST_TIME_ARGS (monitor->timestamp_range_start),
864 GST_TIME_ARGS (monitor->timestamp_range_end),
865 GST_DEBUG_PAD_NAME (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor)),
866 GST_TIME_ARGS (tolerance));
867 return !GST_CLOCK_TIME_IS_VALID (monitor->timestamp_range_start) ||
868 !GST_CLOCK_TIME_IS_VALID (monitor->timestamp_range_end) ||
869 ((monitor->timestamp_range_start >= tolerance ?
870 monitor->timestamp_range_start - tolerance : 0) <= ts
871 && (ts >= tolerance ? ts - tolerance : 0) <=
872 monitor->timestamp_range_end);
875 /* Iterates over internal links (sinkpads) to check that this buffer has
876 * a timestamp that is in the range of the lastly received buffers */
878 gst_validate_pad_monitor_check_buffer_timestamp_in_received_range
879 (GstValidatePadMonitor * monitor, GstBuffer * buffer,
880 GstClockTime tolerance)
885 gboolean has_one = FALSE;
886 gboolean found = FALSE;
889 GstValidatePadMonitor *othermonitor;
891 if (!GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))
892 || !GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) {
893 GST_DEBUG_OBJECT (monitor->pad,
894 "Can't check buffer timestamps range as "
895 "buffer has no valid timestamp/duration");
898 ts = GST_BUFFER_TIMESTAMP (buffer);
899 ts_end = ts + GST_BUFFER_DURATION (buffer);
902 gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
906 GST_WARNING_OBJECT (GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor),
907 "No iterator available");
913 GValue value = { 0, };
914 switch (gst_iterator_next (iter, &value)) {
915 case GST_ITERATOR_OK:
916 otherpad = g_value_get_object (&value);
917 GST_DEBUG_OBJECT (monitor->pad, "Checking pad %s:%s input timestamps",
918 GST_DEBUG_PAD_NAME (otherpad));
920 g_object_get_data ((GObject *) otherpad, "validate-monitor");
921 GST_VALIDATE_MONITOR_LOCK (othermonitor);
922 if (gst_validate_pad_monitor_timestamp_is_in_received_range
923 (othermonitor, ts, tolerance)
925 gst_validate_pad_monitor_timestamp_is_in_received_range
926 (othermonitor, ts_end, tolerance)) {
930 GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
931 g_value_reset (&value);
934 case GST_ITERATOR_RESYNC:
935 gst_iterator_resync (iter);
939 case GST_ITERATOR_ERROR:
940 GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error");
943 case GST_ITERATOR_DONE:
948 gst_iterator_free (iter);
951 GST_DEBUG_OBJECT (monitor->pad, "Skipping timestamp in range check as no "
952 "internal linked pad was found");
956 GST_VALIDATE_REPORT (monitor, BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE,
957 "Timestamp %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT
958 " is out of range of received input", GST_TIME_ARGS (ts),
959 GST_TIME_ARGS (ts_end));
964 gst_validate_pad_monitor_check_first_buffer (GstValidatePadMonitor *
965 pad_monitor, GstBuffer * buffer)
967 if (G_UNLIKELY (pad_monitor->first_buffer)) {
968 pad_monitor->first_buffer = FALSE;
970 if (!pad_monitor->has_segment
971 && PAD_IS_IN_PUSH_MODE (GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor)))
973 GST_VALIDATE_REPORT (pad_monitor, BUFFER_BEFORE_SEGMENT,
974 "Received buffer before Segment event");
977 GST_DEBUG_OBJECT (pad_monitor->pad,
978 "Checking first buffer (pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
979 ")", GST_TIME_ARGS (GST_BUFFER_PTS (buffer)),
980 GST_TIME_ARGS (GST_BUFFER_DTS (buffer)));
982 if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) {
983 gint64 running_time = gst_segment_to_running_time (&pad_monitor->segment,
984 pad_monitor->segment.format, GST_BUFFER_TIMESTAMP (buffer));
985 /* Only check for in-segment buffers */
986 if (GST_CLOCK_TIME_IS_VALID (running_time) && running_time != 0) {
987 GST_VALIDATE_REPORT (pad_monitor, FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO,
988 "First buffer running time is not 0, it is: %" GST_TIME_FORMAT,
989 GST_TIME_ARGS (running_time));
996 gst_validate_pad_monitor_check_eos (GstValidatePadMonitor *
997 pad_monitor, GstBuffer * buffer)
999 if (G_UNLIKELY (pad_monitor->is_eos)) {
1000 GST_VALIDATE_REPORT (pad_monitor, BUFFER_AFTER_EOS,
1001 "Received buffer %" GST_PTR_FORMAT " after EOS", buffer);
1006 gst_validate_pad_monitor_update_buffer_data (GstValidatePadMonitor *
1007 pad_monitor, GstBuffer * buffer)
1009 pad_monitor->current_timestamp = GST_BUFFER_TIMESTAMP (buffer);
1010 pad_monitor->current_duration = GST_BUFFER_DURATION (buffer);
1011 if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) {
1012 if (GST_CLOCK_TIME_IS_VALID (pad_monitor->timestamp_range_start)) {
1013 pad_monitor->timestamp_range_start =
1014 MIN (pad_monitor->timestamp_range_start,
1015 GST_BUFFER_TIMESTAMP (buffer));
1017 pad_monitor->timestamp_range_start = GST_BUFFER_TIMESTAMP (buffer);
1020 if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) {
1021 GstClockTime endts =
1022 GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer);
1023 if (GST_CLOCK_TIME_IS_VALID (pad_monitor->timestamp_range_end)) {
1024 pad_monitor->timestamp_range_end =
1025 MAX (pad_monitor->timestamp_range_end, endts);
1027 pad_monitor->timestamp_range_end = endts;
1031 GST_DEBUG_OBJECT (pad_monitor->pad, "Current stored range: %" GST_TIME_FORMAT
1032 " - %" GST_TIME_FORMAT,
1033 GST_TIME_ARGS (pad_monitor->timestamp_range_start),
1034 GST_TIME_ARGS (pad_monitor->timestamp_range_end));
1037 static GstFlowReturn
1038 _combine_flows (GstFlowReturn ret1, GstFlowReturn ret2)
1042 if (ret1 <= GST_FLOW_NOT_NEGOTIATED)
1044 if (ret2 <= GST_FLOW_NOT_NEGOTIATED)
1046 if (ret1 == GST_FLOW_FLUSHING || ret2 == GST_FLOW_FLUSHING)
1047 return GST_FLOW_FLUSHING;
1048 if (ret1 == GST_FLOW_OK || ret2 == GST_FLOW_OK)
1054 gst_validate_pad_monitor_check_aggregated_return (GstValidatePadMonitor *
1055 monitor, GstFlowReturn ret)
1061 GstValidatePadMonitor *othermonitor;
1062 GstFlowReturn aggregated = GST_FLOW_NOT_LINKED;
1063 gboolean found_a_pad = FALSE;
1064 GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (monitor);
1066 iter = gst_pad_iterate_internal_links (pad);
1069 GValue value = { 0, };
1070 switch (gst_iterator_next (iter, &value)) {
1071 case GST_ITERATOR_OK:
1072 otherpad = g_value_get_object (&value);
1073 peerpad = gst_pad_get_peer (otherpad);
1076 g_object_get_data ((GObject *) peerpad, "validate-monitor");
1079 GST_VALIDATE_MONITOR_LOCK (othermonitor);
1081 _combine_flows (aggregated, othermonitor->last_flow_return);
1082 GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1085 gst_object_unref (peerpad);
1087 g_value_reset (&value);
1089 case GST_ITERATOR_RESYNC:
1090 gst_iterator_resync (iter);
1092 case GST_ITERATOR_ERROR:
1093 GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error");
1096 case GST_ITERATOR_DONE:
1101 gst_iterator_free (iter);
1103 /* no peer pad found, nothing to do */
1106 if (aggregated == GST_FLOW_OK || aggregated == GST_FLOW_EOS) {
1107 /* those are acceptable situations */
1109 if (GST_PAD_IS_FLUSHING (pad) && ret == GST_FLOW_FLUSHING) {
1110 /* pad is flushing, always acceptable to return flushing */
1114 if (monitor->is_eos && ret == GST_FLOW_EOS) {
1115 /* this element received eos and returned eos */
1119 if (PAD_PARENT_IS_DEMUXER (monitor) && ret == GST_FLOW_EOS) {
1120 /* a demuxer can return EOS when the samples end */
1125 if (aggregated != ret) {
1126 GST_VALIDATE_REPORT (monitor, WRONG_FLOW_RETURN,
1127 "Wrong combined flow return %s(%d). Expected: %s(%d)",
1128 gst_flow_get_name (ret), ret, gst_flow_get_name (aggregated),
1134 gst_validate_pad_monitor_otherpad_add_pending_serialized_event
1135 (GstValidatePadMonitor * monitor, GstEvent * event, GstClockTime last_ts)
1140 GstValidatePadMonitor *othermonitor;
1142 if (!GST_EVENT_IS_SERIALIZED (event))
1146 gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
1149 /* inputselector will return NULL if the sinkpad is not the active one .... */
1150 GST_FIXME_OBJECT (GST_VALIDATE_PAD_MONITOR_GET_PAD
1151 (monitor), "No iterator");
1156 GValue value = { 0, };
1157 switch (gst_iterator_next (iter, &value)) {
1158 case GST_ITERATOR_OK:
1159 otherpad = g_value_get_object (&value);
1161 g_object_get_data ((GObject *) otherpad, "validate-monitor");
1163 SerializedEventData *data = g_slice_new0 (SerializedEventData);
1164 data->timestamp = last_ts;
1165 data->event = gst_event_ref (event);
1166 GST_VALIDATE_MONITOR_LOCK (othermonitor);
1167 GST_DEBUG_OBJECT (monitor->pad, "Storing for pad %s:%s event %p %s",
1168 GST_DEBUG_PAD_NAME (otherpad), event,
1169 GST_EVENT_TYPE_NAME (event));
1170 g_ptr_array_add (othermonitor->serialized_events, data);
1171 debug_pending_event (otherpad, othermonitor->serialized_events);
1172 GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1174 g_value_reset (&value);
1176 case GST_ITERATOR_RESYNC:
1177 gst_iterator_resync (iter);
1179 case GST_ITERATOR_ERROR:
1180 GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error");
1183 case GST_ITERATOR_DONE:
1188 gst_iterator_free (iter);
1192 gst_validate_pad_monitor_otherpad_add_pending_field (GstValidatePadMonitor *
1193 monitor, GstStructure * structure, const gchar * field)
1198 GstValidatePadMonitor *othermonitor;
1201 v = gst_structure_get_value (structure, field);
1203 GST_DEBUG_OBJECT (monitor->pad, "Not adding pending field %s as it isn't "
1204 "present on structure %" GST_PTR_FORMAT, field, structure);
1209 gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
1213 GValue value = { 0, };
1214 switch (gst_iterator_next (iter, &value)) {
1215 case GST_ITERATOR_OK:
1216 otherpad = g_value_get_object (&value);
1218 g_object_get_data ((GObject *) otherpad, "validate-monitor");
1220 GST_VALIDATE_MONITOR_LOCK (othermonitor);
1221 g_assert (othermonitor->pending_setcaps_fields != NULL);
1222 gst_structure_set_value (othermonitor->pending_setcaps_fields,
1224 GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1226 g_value_reset (&value);
1228 case GST_ITERATOR_RESYNC:
1229 gst_iterator_resync (iter);
1231 case GST_ITERATOR_ERROR:
1232 GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error");
1235 case GST_ITERATOR_DONE:
1240 gst_iterator_free (iter);
1244 gst_validate_pad_monitor_otherpad_clear_pending_fields (GstValidatePadMonitor *
1250 GstValidatePadMonitor *othermonitor;
1253 gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
1257 GST_DEBUG_OBJECT (monitor, "No internally linked pad");
1264 GValue value = { 0, };
1265 switch (gst_iterator_next (iter, &value)) {
1266 case GST_ITERATOR_OK:
1267 otherpad = g_value_get_object (&value);
1269 g_object_get_data ((GObject *) otherpad, "validate-monitor");
1271 GST_VALIDATE_MONITOR_LOCK (othermonitor);
1272 g_assert (othermonitor->pending_setcaps_fields != NULL);
1273 gst_structure_free (othermonitor->pending_setcaps_fields);
1274 othermonitor->pending_setcaps_fields =
1275 gst_structure_new_empty (PENDING_FIELDS);
1276 GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1278 g_value_reset (&value);
1280 case GST_ITERATOR_RESYNC:
1281 gst_iterator_resync (iter);
1283 case GST_ITERATOR_ERROR:
1284 GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error");
1287 case GST_ITERATOR_DONE:
1292 gst_iterator_free (iter);
1296 gst_validate_pad_monitor_add_expected_newsegment (GstValidatePadMonitor *
1297 monitor, GstEvent * event)
1302 GstValidatePadMonitor *othermonitor;
1305 gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
1309 GST_DEBUG_OBJECT (monitor, "No internally linked pad");
1315 GValue value = { 0, };
1316 switch (gst_iterator_next (iter, &value)) {
1317 case GST_ITERATOR_OK:
1318 otherpad = g_value_get_object (&value);
1322 g_object_get_data ((GObject *) otherpad, "validate-monitor");
1323 GST_VALIDATE_MONITOR_LOCK (othermonitor);
1324 gst_event_replace (&othermonitor->expected_segment, event);
1325 GST_VALIDATE_MONITOR_UNLOCK (othermonitor);
1326 g_value_reset (&value);
1328 case GST_ITERATOR_RESYNC:
1329 gst_iterator_resync (iter);
1331 case GST_ITERATOR_ERROR:
1332 GST_WARNING_OBJECT (monitor->pad, "Internal links pad iteration error");
1335 case GST_ITERATOR_DONE:
1340 gst_iterator_free (iter);
1344 gst_validate_pad_monitor_flush (GstValidatePadMonitor * pad_monitor)
1346 pad_monitor->current_timestamp = GST_CLOCK_TIME_NONE;
1347 pad_monitor->current_duration = GST_CLOCK_TIME_NONE;
1348 pad_monitor->timestamp_range_start = GST_CLOCK_TIME_NONE;
1349 pad_monitor->timestamp_range_end = GST_CLOCK_TIME_NONE;
1350 pad_monitor->has_segment = FALSE;
1351 pad_monitor->is_eos = FALSE;
1352 pad_monitor->last_flow_return = GST_FLOW_OK;
1353 gst_caps_replace (&pad_monitor->last_caps, NULL);
1354 pad_monitor->caps_is_audio = pad_monitor->caps_is_video =
1355 pad_monitor->caps_is_raw = FALSE;
1357 g_list_free_full (pad_monitor->expired_events,
1358 (GDestroyNotify) gst_event_unref);
1359 pad_monitor->expired_events = NULL;
1361 if (pad_monitor->serialized_events->len)
1362 g_ptr_array_remove_range (pad_monitor->serialized_events, 0,
1363 pad_monitor->serialized_events->len);
1366 /* common checks for both sink and src event functions */
1368 gst_validate_pad_monitor_common_event_check (GstValidatePadMonitor *
1369 pad_monitor, GstEvent * event)
1371 guint32 seqnum = gst_event_get_seqnum (event);
1373 switch (GST_EVENT_TYPE (event)) {
1374 case GST_EVENT_FLUSH_START:
1376 if (pad_monitor->pending_flush_start_seqnum) {
1377 if (seqnum == pad_monitor->pending_flush_start_seqnum) {
1378 pad_monitor->pending_flush_start_seqnum = 0;
1380 GST_VALIDATE_REPORT (pad_monitor, EVENT_HAS_WRONG_SEQNUM,
1381 "The expected flush-start seqnum should be the same as the "
1382 "one from the event that caused it (probably a seek). Got: %u."
1383 " Expected: %u", seqnum, pad_monitor->pending_flush_start_seqnum);
1387 if (pad_monitor->pending_flush_stop) {
1388 GST_VALIDATE_REPORT (pad_monitor, EVENT_FLUSH_START_UNEXPECTED,
1389 "Received flush-start from " " when flush-stop was expected");
1391 pad_monitor->pending_flush_stop = TRUE;
1394 case GST_EVENT_FLUSH_STOP:
1396 if (pad_monitor->pending_flush_stop_seqnum) {
1397 if (seqnum == pad_monitor->pending_flush_stop_seqnum) {
1398 pad_monitor->pending_flush_stop_seqnum = 0;
1400 GST_VALIDATE_REPORT (pad_monitor, EVENT_HAS_WRONG_SEQNUM,
1401 "The expected flush-stop seqnum should be the same as the "
1402 "one from the event that caused it (probably a seek). Got: %u."
1403 " Expected: %u", seqnum, pad_monitor->pending_flush_stop_seqnum);
1407 if (!pad_monitor->pending_flush_stop) {
1408 gchar *event_str = _get_event_string (event);
1410 GST_VALIDATE_REPORT (pad_monitor, EVENT_FLUSH_STOP_UNEXPECTED,
1411 "Unexpected flush-stop %s", event_str);
1414 pad_monitor->pending_flush_stop = FALSE;
1416 /* cleanup our data */
1417 gst_validate_pad_monitor_flush (pad_monitor);
1426 gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor *
1427 pad_monitor, GstObject * parent, GstEvent * event,
1428 GstPadEventFunction handler)
1430 gboolean ret = TRUE;
1431 const GstSegment *segment;
1432 guint32 seqnum = gst_event_get_seqnum (event);
1433 GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor);
1435 gst_validate_pad_monitor_common_event_check (pad_monitor, event);
1438 switch (GST_EVENT_TYPE (event)) {
1439 case GST_EVENT_SEGMENT:
1440 /* parse segment data to be used if event is handled */
1441 gst_event_parse_segment (event, &segment);
1443 GST_DEBUG_OBJECT (pad_monitor->pad, "Got segment %" GST_SEGMENT_FORMAT,
1446 if (pad_monitor->pending_newsegment_seqnum) {
1447 if (pad_monitor->pending_newsegment_seqnum == seqnum) {
1448 pad_monitor->pending_newsegment_seqnum = 0;
1450 /* TODO is this an error? could be a segment from the start
1451 * received just before the seek segment */
1455 /* got a segment, no need for EOS now */
1456 pad_monitor->pending_eos_seqnum = 0;
1458 if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
1459 gst_validate_pad_monitor_add_expected_newsegment (pad_monitor, event);
1461 /* check if this segment is the expected one */
1462 if (pad_monitor->expected_segment) {
1463 const GstSegment *exp_segment;
1465 if (pad_monitor->expected_segment != event) {
1466 gst_event_parse_segment (pad_monitor->expected_segment,
1468 if (segment->format == exp_segment->format) {
1469 if ((exp_segment->rate * exp_segment->applied_rate !=
1470 segment->rate * segment->applied_rate)
1471 || exp_segment->start != segment->start
1472 || exp_segment->stop != segment->stop
1473 || exp_segment->position != segment->position) {
1474 GST_VALIDATE_REPORT (pad_monitor, EVENT_NEW_SEGMENT_MISMATCH,
1475 "Expected segment didn't match received segment event");
1479 gst_event_replace (&pad_monitor->expected_segment, NULL);
1483 case GST_EVENT_CAPS:{
1486 gst_event_parse_caps (event, &caps);
1487 gst_validate_pad_monitor_setcaps_pre (pad_monitor, caps);
1491 pad_monitor->is_eos = TRUE;
1492 if (pad_monitor->pending_eos_seqnum &&
1493 pad_monitor->pending_eos_seqnum != seqnum) {
1494 GST_VALIDATE_REPORT (pad_monitor, EVENT_HAS_WRONG_SEQNUM,
1495 "The expected EOS seqnum should be the same as the "
1496 "one from the seek that caused it. Got: %u."
1497 " Expected: %u", seqnum, pad_monitor->pending_eos_seqnum);
1500 * TODO add end of stream checks for
1501 * - events not pushed
1502 * - buffer data not pushed
1503 * - pending events not received
1507 /* both flushes are handled by the common event function */
1508 case GST_EVENT_FLUSH_START:
1509 case GST_EVENT_FLUSH_STOP:
1511 case GST_EVENT_SINK_MESSAGE:
1516 GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1517 GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
1518 gst_validate_pad_monitor_event_overrides (pad_monitor, event);
1520 gst_event_ref (event);
1521 ret = pad_monitor->event_func (pad, parent, event);
1523 GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
1524 GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1527 switch (GST_EVENT_TYPE (event)) {
1528 case GST_EVENT_SEGMENT:
1530 if (!pad_monitor->has_segment
1531 && pad_monitor->segment.format != segment->format) {
1532 gst_segment_init (&pad_monitor->segment, segment->format);
1534 gst_segment_copy_into (segment, &pad_monitor->segment);
1535 pad_monitor->has_segment = TRUE;
1538 case GST_EVENT_CAPS:{
1541 gst_event_parse_caps (event, &caps);
1542 gst_validate_pad_monitor_setcaps_post (pad_monitor, caps, ret);
1545 case GST_EVENT_FLUSH_START:
1546 case GST_EVENT_FLUSH_STOP:
1549 case GST_EVENT_SINK_MESSAGE:
1555 gst_event_unref (event);
1560 gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor,
1561 GstObject * parent, GstEvent * event, GstPadEventFunction handler)
1563 gboolean ret = TRUE;
1567 GstSeekFlags seek_flags;
1568 GstSeekType start_type, stop_type;
1569 guint32 seqnum = gst_event_get_seqnum (event);
1570 GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor);
1572 gst_validate_pad_monitor_common_event_check (pad_monitor, event);
1575 switch (GST_EVENT_TYPE (event)) {
1576 case GST_EVENT_SEEK:
1578 gst_event_parse_seek (event, &rate, &format, &seek_flags, &start_type,
1579 &start, &stop_type, &stop);
1580 /* upstream seek - store the seek event seqnum to check
1581 * flushes and newsegments share the same */
1583 /* TODO we might need to use a list as multiple seeks can be sent
1584 * before the flushes arrive here */
1585 if (seek_flags & GST_SEEK_FLAG_FLUSH) {
1586 pad_monitor->pending_flush_start_seqnum = seqnum;
1587 pad_monitor->pending_flush_stop_seqnum = seqnum;
1589 pad_monitor->pending_newsegment_seqnum = seqnum;
1590 pad_monitor->pending_eos_seqnum = seqnum;
1593 /* both flushes are handled by the common event handling function */
1594 case GST_EVENT_FLUSH_START:
1595 case GST_EVENT_FLUSH_STOP:
1596 case GST_EVENT_NAVIGATION:
1597 case GST_EVENT_LATENCY:
1598 case GST_EVENT_STEP:
1605 GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1606 gst_event_ref (event);
1607 ret = pad_monitor->event_func (pad, parent, event);
1608 GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1612 switch (GST_EVENT_TYPE (event)) {
1613 case GST_EVENT_FLUSH_START:
1614 case GST_EVENT_FLUSH_STOP:
1616 case GST_EVENT_SEEK:
1619 /* do not expect any of these events anymore */
1620 pad_monitor->pending_flush_start_seqnum = 0;
1621 pad_monitor->pending_flush_stop_seqnum = 0;
1622 pad_monitor->pending_newsegment_seqnum = 0;
1623 pad_monitor->pending_eos_seqnum = 0;
1627 case GST_EVENT_NAVIGATION:
1628 case GST_EVENT_LATENCY:
1629 case GST_EVENT_STEP:
1635 gst_event_unref (event);
1639 static GstFlowReturn
1640 gst_validate_pad_monitor_chain_func (GstPad * pad, GstObject * parent,
1643 GstValidatePadMonitor *pad_monitor =
1644 g_object_get_data ((GObject *) pad, "validate-monitor");
1647 GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
1648 GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1650 gst_validate_pad_monitor_check_first_buffer (pad_monitor, buffer);
1651 gst_validate_pad_monitor_update_buffer_data (pad_monitor, buffer);
1652 gst_validate_pad_monitor_check_eos (pad_monitor, buffer);
1654 GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1655 GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
1657 gst_validate_pad_monitor_buffer_overrides (pad_monitor, buffer);
1659 ret = pad_monitor->chain_func (pad, parent, buffer);
1661 GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
1662 GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1664 pad_monitor->last_flow_return = ret;
1665 if (ret == GST_FLOW_EOS) {
1666 pad_monitor->is_eos = ret;
1668 if (PAD_PARENT_IS_DEMUXER (pad_monitor))
1669 gst_validate_pad_monitor_check_aggregated_return (pad_monitor, ret);
1671 GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1672 GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
1678 gst_validate_pad_monitor_event_is_tracked (GstValidatePadMonitor * monitor,
1681 if (!GST_EVENT_IS_SERIALIZED (event)) {
1685 /* we don't track Tag events because they mutate too much and it is hard
1686 * to match a tag event pushed on a source pad with the one that was received
1688 * One idea would be to use seqnum, but it seems that it is undefined whether
1689 * seqnums should be maintained in tag events that are created from others
1690 * up to today. (2013-08-29)
1692 if (GST_EVENT_TYPE (event) == GST_EVENT_TAG)
1699 gst_validate_pad_monitor_sink_event_func (GstPad * pad, GstObject * parent,
1702 GstValidatePadMonitor *pad_monitor =
1703 g_object_get_data ((GObject *) pad, "validate-monitor");
1706 GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
1707 GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1709 if (gst_validate_pad_monitor_event_is_tracked (pad_monitor, event)) {
1710 GstClockTime last_ts = GST_CLOCK_TIME_NONE;
1711 if (GST_CLOCK_TIME_IS_VALID (pad_monitor->current_timestamp)) {
1712 last_ts = pad_monitor->current_timestamp;
1713 if (GST_CLOCK_TIME_IS_VALID (pad_monitor->current_duration)) {
1714 last_ts += pad_monitor->current_duration;
1717 gst_validate_pad_monitor_otherpad_add_pending_serialized_event (pad_monitor,
1722 gst_validate_pad_monitor_downstream_event_check (pad_monitor, parent,
1723 event, pad_monitor->event_func);
1725 GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1726 GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (pad_monitor);
1731 gst_validate_pad_monitor_src_event_func (GstPad * pad, GstObject * parent,
1734 GstValidatePadMonitor *pad_monitor =
1735 g_object_get_data ((GObject *) pad, "validate-monitor");
1738 GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1739 ret = gst_validate_pad_monitor_src_event_check (pad_monitor, parent, event,
1740 pad_monitor->event_func);
1741 GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1746 gst_validate_pad_monitor_query_func (GstPad * pad, GstObject * parent,
1749 GstValidatePadMonitor *pad_monitor =
1750 g_object_get_data ((GObject *) pad, "validate-monitor");
1753 gst_validate_pad_monitor_query_overrides (pad_monitor, query);
1755 ret = pad_monitor->query_func (pad, parent, query);
1758 switch (GST_QUERY_TYPE (query)) {
1759 case GST_QUERY_CAPS:{
1761 /* We shouldn't need to lock the parent as this doesn't modify
1762 * other monitors, just does some peer_pad_caps */
1763 GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1765 gst_query_parse_caps_result (query, &res);
1766 if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
1767 gst_validate_pad_monitor_check_caps_fields_proxied (pad_monitor, res);
1769 GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1781 gst_validate_pad_monitor_activatemode_func (GstPad * pad, GstObject * parent,
1782 GstPadMode mode, gboolean active)
1784 GstValidatePadMonitor *pad_monitor =
1785 g_object_get_data ((GObject *) pad, "validate-monitor");
1786 gboolean ret = TRUE;
1788 /* TODO add overrides for activate func */
1790 if (pad_monitor->activatemode_func)
1791 ret = pad_monitor->activatemode_func (pad, parent, mode, active);
1792 if (ret && active == FALSE) {
1793 GST_VALIDATE_MONITOR_LOCK (pad_monitor);
1794 gst_validate_pad_monitor_flush (pad_monitor);
1795 GST_VALIDATE_MONITOR_UNLOCK (pad_monitor);
1802 gst_validate_pad_get_range_func (GstPad * pad, GstObject * parent,
1803 guint64 offset, guint size, GstBuffer ** buffer)
1805 GstValidatePadMonitor *pad_monitor =
1806 g_object_get_data ((GObject *) pad, "validate-monitor");
1808 ret = pad_monitor->getrange_func (pad, parent, offset, size, buffer);
1813 gst_validate_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer,
1816 GstValidatePadMonitor *monitor = udata;
1818 GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor);
1819 GST_VALIDATE_MONITOR_LOCK (monitor);
1821 gst_validate_pad_monitor_check_first_buffer (monitor, buffer);
1822 gst_validate_pad_monitor_update_buffer_data (monitor, buffer);
1823 gst_validate_pad_monitor_check_eos (monitor, buffer);
1825 if (PAD_PARENT_IS_DECODER (monitor) || PAD_PARENT_IS_ENCODER (monitor)) {
1826 GstClockTime tolerance = 0;
1828 if (monitor->caps_is_audio)
1829 tolerance = AUDIO_TIMESTAMP_TOLERANCE;
1831 gst_validate_pad_monitor_check_buffer_timestamp_in_received_range (monitor,
1835 gst_validate_pad_monitor_check_late_serialized_events (monitor,
1836 GST_BUFFER_TIMESTAMP (buffer));
1838 /* a GstValidatePadMonitor parent must be a GstValidateElementMonitor */
1839 if (PAD_PARENT_IS_DECODER (monitor)) {
1841 /* should not push out of segment data */
1842 if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer)) &&
1843 GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer)) &&
1844 ((!gst_segment_clip (&monitor->segment, monitor->segment.format,
1845 GST_BUFFER_TIMESTAMP (buffer),
1846 GST_BUFFER_TIMESTAMP (buffer) +
1847 GST_BUFFER_DURATION (buffer), NULL, NULL)) ||
1848 /* In the case of raw data, buffers should be strictly contained inside the
1850 (monitor->caps_is_raw &&
1851 GST_BUFFER_PTS (buffer) + GST_BUFFER_DURATION (buffer) <
1852 monitor->segment.start))
1854 /* TODO is this a timestamp issue? */
1855 GST_VALIDATE_REPORT (monitor, BUFFER_IS_OUT_OF_SEGMENT,
1856 "buffer is out of segment and shouldn't be pushed. Timestamp: %"
1857 GST_TIME_FORMAT " - duration: %" GST_TIME_FORMAT ". Range: %"
1858 GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
1859 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
1860 GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)),
1861 GST_TIME_ARGS (monitor->segment.start),
1862 GST_TIME_ARGS (monitor->segment.stop));
1866 GST_VALIDATE_MONITOR_UNLOCK (monitor);
1867 GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (monitor);
1868 gst_validate_pad_monitor_buffer_probe_overrides (monitor, buffer);
1873 gst_validate_pad_monitor_event_probe (GstPad * pad, GstEvent * event,
1876 GstValidatePadMonitor *monitor = GST_VALIDATE_PAD_MONITOR_CAST (udata);
1879 GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (monitor);
1880 GST_VALIDATE_MONITOR_LOCK (monitor);
1882 GST_DEBUG_OBJECT (pad, "event %p %s", event, GST_EVENT_TYPE_NAME (event));
1884 if (GST_EVENT_IS_SERIALIZED (event)) {
1887 /* Detect if events the element received are being forwarded in the same order
1889 * Several scenarios:
1890 * 1) The element pushes the event as-is
1891 * 2) The element consumes the event and does not forward it
1892 * 3) The element consumes the event and creates another one instead
1893 * 4) The element pushes other serialized event before pushing out the
1896 * For each pad we have two lists to track serialized events:
1897 * 1) We received on input and expect to see (serialized_events)
1898 * 2) We received on input but don't expect to see (expired_events)
1900 * To detect events that are pushed in a different order from the one they were
1901 * received in we check that:
1903 * For each event being outputted:
1904 * If it is in the expired_events list:
1906 * If it is in the serialized_events list:
1907 * If there are other events that were received before:
1908 * Put those events on the expired_events list
1909 * Remove that event and any previous ones from the serialized_events list
1911 * Clear expired events list when flushing or on pad deactivation
1915 if (g_list_find (monitor->expired_events, event)) {
1916 gchar *event_str = _get_event_string (event);
1917 /* If it's the expired events, we've failed */
1918 GST_WARNING_OBJECT (pad, "Did not expect event %p %s", event,
1919 GST_EVENT_TYPE_NAME (event));
1920 GST_VALIDATE_REPORT (monitor, EVENT_SERIALIZED_OUT_OF_ORDER,
1921 "Serialized event was pushed out of order: %s", event_str);
1924 monitor->expired_events = g_list_remove (monitor->expired_events, event);
1925 gst_event_unref (event); /* remove the ref that was on the list */
1926 } else if (monitor->serialized_events->len) {
1927 for (i = 0; i < monitor->serialized_events->len; i++) {
1928 SerializedEventData *next_event =
1929 g_ptr_array_index (monitor->serialized_events, i);
1930 GST_DEBUG_OBJECT (pad, "Checking against stored event #%d: %p %s", i,
1931 next_event->event, GST_EVENT_TYPE_NAME (next_event->event));
1933 if (event == next_event->event
1934 || GST_EVENT_TYPE (event) == GST_EVENT_TYPE (next_event->event)) {
1935 /* We have found our event */
1936 GST_DEBUG_OBJECT (pad, "Found matching event");
1938 while (monitor->serialized_events->len > i
1939 && GST_EVENT_TYPE (event) == GST_EVENT_TYPE (next_event->event)) {
1940 /* Swallow all expected events of the same type */
1941 g_ptr_array_remove_index (monitor->serialized_events, i);
1942 next_event = g_ptr_array_index (monitor->serialized_events, i);
1945 /* Move all previous events to expired events */
1946 if (G_UNLIKELY (i > 0)) {
1947 GST_DEBUG_OBJECT (pad,
1948 "Moving previous expected events to expired list");
1950 next_event = g_ptr_array_index (monitor->serialized_events, 0);
1951 monitor->expired_events =
1952 g_list_append (monitor->expired_events,
1953 gst_event_ref (next_event->event));
1954 g_ptr_array_remove_index (monitor->serialized_events, 0);
1957 debug_pending_event (pad, monitor->serialized_events);
1964 /* This so far is just like an event that is flowing downstream,
1965 * so we do the same checks as a sinkpad event handler */
1967 gst_validate_pad_monitor_downstream_event_check (monitor, NULL, event,
1969 GST_VALIDATE_MONITOR_UNLOCK (monitor);
1970 GST_VALIDATE_PAD_MONITOR_PARENT_UNLOCK (monitor);
1975 static GstPadProbeReturn
1976 gst_validate_pad_monitor_pad_probe (GstPad * pad, GstPadProbeInfo * info,
1979 if (info->type & GST_PAD_PROBE_TYPE_BUFFER)
1980 gst_validate_pad_monitor_buffer_probe (pad, info->data, udata);
1981 else if (info->type & GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM)
1982 gst_validate_pad_monitor_event_probe (pad, info->data, udata);
1984 return GST_PAD_PROBE_OK;
1988 gst_validate_pad_monitor_update_caps_info (GstValidatePadMonitor * pad_monitor,
1991 GstStructure *structure;
1993 g_return_if_fail (gst_caps_is_fixed (caps));
1995 pad_monitor->caps_is_audio = FALSE;
1996 pad_monitor->caps_is_video = FALSE;
1998 structure = gst_caps_get_structure (caps, 0);
1999 if (g_str_has_prefix (gst_structure_get_name (structure), "audio/")) {
2000 pad_monitor->caps_is_audio = TRUE;
2001 } else if (g_str_has_prefix (gst_structure_get_name (structure), "video/")) {
2002 pad_monitor->caps_is_video = TRUE;
2005 if (g_str_has_prefix (gst_structure_get_name (structure), "audio/x-raw") ||
2006 g_str_has_prefix (gst_structure_get_name (structure), "video/x-raw")) {
2007 pad_monitor->caps_is_raw = TRUE;
2009 pad_monitor->caps_is_raw = FALSE;
2014 gst_validate_pad_monitor_setcaps_pre (GstValidatePadMonitor * pad_monitor,
2017 GstStructure *structure;
2019 /* Check if caps are identical to last caps and complain if so
2020 * Only checked for sink pads as src pads might push the same caps
2021 * multiple times during unlinked/autoplugging scenarios */
2022 if (GST_PAD_IS_SINK (GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor)) &&
2023 pad_monitor->last_caps
2024 && gst_caps_is_equal (caps, pad_monitor->last_caps)) {
2025 gchar *caps_str = gst_caps_to_string (caps);
2027 GST_VALIDATE_REPORT (pad_monitor, EVENT_CAPS_DUPLICATE, "%s", caps_str);
2032 gst_validate_pad_monitor_check_caps_complete (pad_monitor, caps);
2035 structure = gst_caps_get_structure (caps, 0);
2036 if (gst_structure_n_fields (pad_monitor->pending_setcaps_fields)) {
2039 i < gst_structure_n_fields (pad_monitor->pending_setcaps_fields);
2042 gst_structure_nth_field_name (pad_monitor->pending_setcaps_fields,
2044 const GValue *v = gst_structure_get_value (structure, name);
2045 const GValue *otherv =
2046 gst_structure_get_value (pad_monitor->pending_setcaps_fields, name);
2049 gchar *caps_str = gst_caps_to_string (caps);
2051 GST_VALIDATE_REPORT (pad_monitor, CAPS_EXPECTED_FIELD_NOT_FOUND,
2052 "Field %s is missing from setcaps caps '%s'", name, caps_str);
2054 } else if (gst_value_compare (v, otherv) != GST_VALUE_EQUAL) {
2055 gchar *caps_str = gst_caps_to_string (caps),
2056 *pending_setcaps_fields_str =
2057 gst_structure_to_string (pad_monitor->pending_setcaps_fields);
2060 GST_VALIDATE_REPORT (pad_monitor, CAPS_FIELD_UNEXPECTED_VALUE,
2061 "Field %s from setcaps caps '%s' is different "
2062 "from expected value in caps '%s'", name, caps_str,
2063 pending_setcaps_fields_str);
2065 g_free (pending_setcaps_fields_str);
2071 if (gst_validate_pad_monitor_pad_should_proxy_othercaps (pad_monitor)) {
2072 if (_structure_is_video (structure)) {
2073 gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2074 structure, "width");
2075 gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2076 structure, "height");
2077 gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2078 structure, "framerate");
2079 gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2080 structure, "pixel-aspect-ratio");
2081 } else if (_structure_is_audio (structure)) {
2082 gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2084 gst_validate_pad_monitor_otherpad_add_pending_field (pad_monitor,
2085 structure, "channels");
2090 gst_structure_free (pad_monitor->pending_setcaps_fields);
2091 pad_monitor->pending_setcaps_fields =
2092 gst_structure_new_empty (PENDING_FIELDS);
2094 gst_validate_pad_monitor_setcaps_overrides (pad_monitor, caps);
2098 gst_validate_pad_monitor_setcaps_post (GstValidatePadMonitor * pad_monitor,
2099 GstCaps * caps, gboolean ret)
2102 gst_validate_pad_monitor_otherpad_clear_pending_fields (pad_monitor);
2104 if (pad_monitor->last_caps) {
2105 gst_caps_unref (pad_monitor->last_caps);
2107 pad_monitor->last_caps = gst_caps_ref (caps);
2108 gst_validate_pad_monitor_update_caps_info (pad_monitor, caps);
2113 gst_validate_pad_monitor_do_setup (GstValidateMonitor * monitor)
2115 GstValidatePadMonitor *pad_monitor = GST_VALIDATE_PAD_MONITOR_CAST (monitor);
2117 if (!GST_IS_PAD (GST_VALIDATE_MONITOR_GET_OBJECT (monitor))) {
2118 GST_WARNING_OBJECT (monitor, "Trying to create pad monitor with other "
2123 pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor);
2125 if (g_object_get_data ((GObject *) pad, "validate-monitor")) {
2126 GST_WARNING_OBJECT (pad_monitor,
2127 "Pad already has a validate-monitor associated");
2131 g_object_set_data ((GObject *) pad, "validate-monitor", pad_monitor);
2133 pad_monitor->pad = pad;
2135 pad_monitor->event_func = GST_PAD_EVENTFUNC (pad);
2136 pad_monitor->query_func = GST_PAD_QUERYFUNC (pad);
2137 pad_monitor->activatemode_func = GST_PAD_ACTIVATEMODEFUNC (pad);
2138 if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) {
2140 pad_monitor->chain_func = GST_PAD_CHAINFUNC (pad);
2141 if (pad_monitor->chain_func)
2142 gst_pad_set_chain_function (pad, gst_validate_pad_monitor_chain_func);
2144 gst_pad_set_event_function (pad, gst_validate_pad_monitor_sink_event_func);
2146 pad_monitor->getrange_func = GST_PAD_GETRANGEFUNC (pad);
2147 if (pad_monitor->getrange_func)
2148 gst_pad_set_getrange_function (pad, gst_validate_pad_get_range_func);
2150 gst_pad_set_event_function (pad, gst_validate_pad_monitor_src_event_func);
2152 /* add buffer/event probes */
2153 pad_monitor->pad_probe_id =
2154 gst_pad_add_probe (pad,
2155 GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM |
2156 GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2157 (GstPadProbeCallback) gst_validate_pad_monitor_pad_probe, pad_monitor,
2160 gst_pad_set_query_function (pad, gst_validate_pad_monitor_query_func);
2161 gst_pad_set_activatemode_function (pad,
2162 gst_validate_pad_monitor_activatemode_func);
2164 gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (monitor),
2165 g_strdup_printf ("%s:%s", GST_DEBUG_PAD_NAME (pad)));
2167 if (G_UNLIKELY (GST_PAD_PARENT (pad) == NULL))
2168 GST_FIXME ("Saw a pad not belonging to any object");