validate-pad-monitor: concatenate issues.

Fixes https://bugzilla.gnome.org/show_bug.cgi?id=735665

The process is to check for a similar report in intercept_report on
the pads of the upstream element, set that report as the master report
of the intercepted report, and return REPORTER_KEEP instead
of REPORTER_REPORT.
This commit is contained in:
Mathieu Duponchelle 2014-10-02 02:50:29 +02:00 committed by Mathieu Duponchelle
parent d747e1cd05
commit 6e08079f8b
2 changed files with 262 additions and 0 deletions

View file

@ -122,11 +122,124 @@ typedef struct
} SerializedEventData;
static gboolean
_find_master_report_on_pad (GstPad * pad, GstValidateReport * report)
{
GstValidatePadMonitor *pad_monitor;
GstValidateReport *prev_report;
GstPad *tmp_pad;
gboolean result = FALSE;
gst_object_ref (pad);
/* We don't monitor ghost pads */
while (GST_IS_GHOST_PAD (pad)) {
tmp_pad = pad;
pad = gst_ghost_pad_get_target ((GstGhostPad *) pad);
gst_object_unref (tmp_pad);
}
while (GST_IS_PROXY_PAD (pad)) {
tmp_pad = pad;
pad = gst_pad_get_peer (pad);
gst_object_unref (tmp_pad);
}
pad_monitor = g_object_get_data ((GObject *) pad, "validate-monitor");
/* For some reason this pad isn't monitored */
if (pad_monitor == NULL)
goto done;
prev_report = gst_validate_reporter_get_report ((GstValidateReporter *)
pad_monitor, report->issue->issue_id);
if (prev_report) {
if (prev_report->master_report)
gst_validate_report_set_master_report (report,
prev_report->master_report);
else
gst_validate_report_set_master_report (report, prev_report);
result = TRUE;
}
done:
gst_object_unref (pad);
return result;
}
static gboolean
_find_master_report_for_sink_pad (GstValidatePadMonitor * pad_monitor,
GstValidateReport * report)
{
GstPad *peerpad;
gboolean result = FALSE;
peerpad = gst_pad_get_peer (pad_monitor->pad);
/* If the peer src pad already has a similar report no need to look
* any further */
if (peerpad && _find_master_report_on_pad (peerpad, report))
result = TRUE;
if (peerpad)
gst_object_unref (peerpad);
return result;
}
static gboolean
_find_master_report_for_src_pad (GstValidatePadMonitor * pad_monitor,
GstValidateReport * report)
{
GstIterator *iter;
gboolean done;
GstPad *pad;
gboolean result = FALSE;
iter =
gst_pad_iterate_internal_links (GST_VALIDATE_PAD_MONITOR_GET_PAD
(pad_monitor));
done = FALSE;
while (!done) {
GValue value = { 0, };
switch (gst_iterator_next (iter, &value)) {
case GST_ITERATOR_OK:
pad = g_value_get_object (&value);
if (_find_master_report_on_pad (pad, report)) {
result = TRUE;
done = TRUE;
}
g_value_reset (&value);
break;
case GST_ITERATOR_RESYNC:
gst_iterator_resync (iter);
break;
case GST_ITERATOR_ERROR:
GST_WARNING_OBJECT (pad_monitor->pad,
"Internal links pad iteration error");
done = TRUE;
break;
case GST_ITERATOR_DONE:
done = TRUE;
break;
}
}
gst_iterator_free (iter);
return result;
}
static GstValidateInterceptionReturn
gst_validate_pad_monitor_intercept_report (GstValidateReporter *
reporter, GstValidateReport * report)
{
GstValidateReporterInterface *iface_class, *old_iface_class;
GstValidatePadMonitor *pad_monitor = GST_VALIDATE_PAD_MONITOR (reporter);
iface_class =
G_TYPE_INSTANCE_GET_INTERFACE (reporter, GST_TYPE_VALIDATE_REPORTER,
@ -134,6 +247,14 @@ gst_validate_pad_monitor_intercept_report (GstValidateReporter *
old_iface_class = g_type_interface_peek_parent (iface_class);
old_iface_class->intercept_report (reporter, report);
if (GST_PAD_IS_SINK (pad_monitor->pad)
&& _find_master_report_for_sink_pad (pad_monitor, report))
return GST_VALIDATE_REPORTER_KEEP;
else if (GST_PAD_IS_SRC (pad_monitor->pad)
&& _find_master_report_for_src_pad (pad_monitor, report))
return GST_VALIDATE_REPORTER_KEEP;
return GST_VALIDATE_REPORTER_REPORT;
}

View file

@ -378,6 +378,146 @@ GST_START_TEST (flow_aggregation)
GST_END_TEST;
static GstPadProbeReturn
drop_buffers (GstPad * pad, GstPadProbeInfo * info, gpointer unused)
{
return GST_PAD_PROBE_DROP;
}
GST_START_TEST (issue_concatenation)
{
GstPad *srcpad1, *srcpad2, *sinkpad, *funnel_sink1, *funnel_sink2;
GstElement *src1, *src2, *sink, *funnel;
GstValidateRunner *runner;
GstValidatePadMonitor *srcpad_monitor1, *srcpad_monitor2, *sinkpad_monitor;
GstValidatePadMonitor *funnel_sink_monitor1, *funnel_sink_monitor2;
GstSegment segment;
GList *reports;
gint n_reports;
gulong probe_id1, probe_id2;
runner = gst_validate_runner_new ();
src1 = create_and_monitor_element ("fakesrc", "fakesrc1", runner);
src2 = create_and_monitor_element ("fakesrc", "fakesrc2", runner);
funnel = create_and_monitor_element ("funnel", "funnel", runner);
sink = create_and_monitor_element ("fakesink", "fakesink", runner);
srcpad1 = gst_element_get_static_pad (src1, "src");
srcpad_monitor1 = g_object_get_data (G_OBJECT(srcpad1), "validate-monitor");
srcpad2 = gst_element_get_static_pad (src2, "src");
srcpad_monitor2 = g_object_get_data (G_OBJECT(srcpad2), "validate-monitor");
funnel_sink1 = gst_element_get_request_pad (funnel, "sink_%u");
funnel_sink_monitor1 = g_object_get_data (G_OBJECT(funnel_sink1), "validate-monitor");
funnel_sink2 = gst_element_get_request_pad (funnel, "sink_%u");
funnel_sink_monitor2 = g_object_get_data (G_OBJECT(funnel_sink2), "validate-monitor");
sinkpad = gst_element_get_static_pad (sink, "sink");
sinkpad_monitor = g_object_get_data (G_OBJECT(sinkpad), "validate-monitor");
fail_unless (gst_element_link (funnel, sink));
fail_unless (gst_pad_link (srcpad1, funnel_sink1) == GST_PAD_LINK_OK);
fail_unless (gst_pad_link (srcpad2, funnel_sink2) == GST_PAD_LINK_OK);
/* There's gonna be some clunkiness in here because of funnel*/
probe_id1 = gst_pad_add_probe (srcpad1,
GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST,
(GstPadProbeCallback) drop_buffers, NULL, NULL);
probe_id2 = gst_pad_add_probe (srcpad2,
GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BUFFER_LIST,
(GstPadProbeCallback) drop_buffers, NULL, NULL);
/* We want to handle the src behaviour ourselves */
fail_unless (gst_pad_activate_mode (srcpad1, GST_PAD_MODE_PUSH, TRUE));
fail_unless (gst_pad_activate_mode (srcpad2, GST_PAD_MODE_PUSH, TRUE));
/* Setup all needed events */
gst_segment_init (&segment, GST_FORMAT_TIME);
segment.start = 0;
segment.stop = GST_SECOND;
fail_unless (gst_pad_push_event (srcpad1,
gst_event_new_stream_start ("the-stream")));
fail_unless (gst_pad_push_event (srcpad1, gst_event_new_segment (&segment)));
fail_unless (gst_pad_push_event (srcpad2,
gst_event_new_stream_start ("the-stream")));
fail_unless (gst_pad_push_event (srcpad2, gst_event_new_segment (&segment)));
fail_unless_equals_int (gst_element_set_state (funnel, GST_STATE_PLAYING),
GST_STATE_CHANGE_SUCCESS);
fail_unless_equals_int (gst_element_set_state (sink, GST_STATE_PLAYING),
GST_STATE_CHANGE_ASYNC);
/* Send an unexpected flush stop */
_gst_check_expecting_log = TRUE;
fail_unless (gst_pad_push_event (srcpad1, gst_event_new_flush_stop (TRUE)));
/* The runner only sees one report */
reports = gst_validate_runner_get_reports (runner);
assert_equals_int (g_list_length (reports), 1);
g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref);
/* Each pad monitor on the way actually holds a report */
n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) srcpad_monitor1);
fail_unless_equals_int (n_reports, 1);
n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) sinkpad_monitor);
fail_unless_equals_int (n_reports, 1);
n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) funnel_sink_monitor1);
fail_unless_equals_int (n_reports, 1);
/* But not the pad monitor of the other funnel sink */
n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) funnel_sink_monitor2);
fail_unless_equals_int (n_reports, 0);
n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) srcpad_monitor2);
fail_unless_equals_int (n_reports, 0);
/* Once again but on the other funnel sink */
fail_unless (gst_pad_push_event (srcpad2, gst_event_new_flush_stop (TRUE)));
/* The runner now sees two reports */
reports = gst_validate_runner_get_reports (runner);
assert_equals_int (g_list_length (reports), 2);
g_list_free_full (reports, (GDestroyNotify) gst_validate_report_unref);
/* These monitors already saw that issue */
n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) srcpad_monitor1);
fail_unless_equals_int (n_reports, 1);
n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) sinkpad_monitor);
fail_unless_equals_int (n_reports, 1);
n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) funnel_sink_monitor1);
fail_unless_equals_int (n_reports, 1);
n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) funnel_sink_monitor2);
fail_unless_equals_int (n_reports, 1);
n_reports = gst_validate_reporter_get_reports_count ((GstValidateReporter *) srcpad_monitor2);
fail_unless_equals_int (n_reports, 1);
/* clean up */
fail_unless (gst_pad_activate_mode (srcpad1, GST_PAD_MODE_PUSH, FALSE));
fail_unless (gst_pad_activate_mode (srcpad2, GST_PAD_MODE_PUSH, FALSE));
fail_unless_equals_int (gst_element_set_state (funnel, GST_STATE_NULL),
GST_STATE_CHANGE_SUCCESS);
fail_unless_equals_int (gst_element_set_state (sink, GST_STATE_NULL),
GST_STATE_CHANGE_SUCCESS);
gst_pad_remove_probe (srcpad1, probe_id1);
gst_pad_remove_probe (srcpad2, probe_id2);
gst_object_unref (srcpad1);
gst_object_unref (srcpad2);
gst_object_unref (sinkpad);
gst_object_unref (funnel_sink1);
gst_object_unref (funnel_sink2);
check_destroyed (funnel, funnel_sink1, funnel_sink2, NULL);
check_destroyed (src1, srcpad1, NULL);
check_destroyed (src2, srcpad2, NULL);
check_destroyed (sink, sinkpad, NULL);
check_destroyed (runner, NULL, NULL);
}
GST_END_TEST;
static Suite *
gst_validate_suite (void)
{
@ -391,6 +531,7 @@ gst_validate_suite (void)
tcase_add_test (tc_chain, buffer_outside_segment);
tcase_add_test (tc_chain, first_buffer_running_time);
tcase_add_test (tc_chain, flow_aggregation);
tcase_add_test (tc_chain, issue_concatenation);
return s;
}