mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-20 21:16:24 +00:00
pad: Handle changing sticky events in pad probes
In the case where the user sets a new padprobeinfo->data in a probe where the data is a sticky event, the new sticky event should be automatically sticked on the probed pad. https://bugzilla.gnome.org/show_bug.cgi?id=795330
This commit is contained in:
parent
588e054e6d
commit
11e0f451eb
2 changed files with 87 additions and 12 deletions
42
gst/gstpad.c
42
gst/gstpad.c
|
@ -192,7 +192,7 @@ static GstFlowReturn gst_pad_chain_list_default (GstPad * pad,
|
|||
static GstFlowReturn gst_pad_send_event_unchecked (GstPad * pad,
|
||||
GstEvent * event, GstPadProbeType type);
|
||||
static GstFlowReturn gst_pad_push_event_unchecked (GstPad * pad,
|
||||
GstEvent * event, GstPadProbeType type);
|
||||
GstEvent ** event, GstPadProbeType type);
|
||||
|
||||
static gboolean activate_mode_internal (GstPad * pad, GstObject * parent,
|
||||
GstPadMode mode, gboolean active);
|
||||
|
@ -647,7 +647,8 @@ restart:
|
|||
|
||||
/* should be called with LOCK */
|
||||
static GstEvent *
|
||||
_apply_pad_offset (GstPad * pad, GstEvent * event, gboolean upstream)
|
||||
_apply_pad_offset (GstPad * pad, GstEvent * event, gint64 applied_offset,
|
||||
gboolean upstream)
|
||||
{
|
||||
gint64 offset;
|
||||
|
||||
|
@ -663,16 +664,16 @@ _apply_pad_offset (GstPad * pad, GstEvent * event, gboolean upstream)
|
|||
gst_event_copy_segment (event, &segment);
|
||||
gst_event_unref (event);
|
||||
|
||||
gst_segment_offset_running_time (&segment, segment.format, pad->offset);
|
||||
gst_segment_offset_running_time (&segment, segment.format, applied_offset);
|
||||
event = gst_event_new_segment (&segment);
|
||||
}
|
||||
|
||||
event = gst_event_make_writable (event);
|
||||
offset = gst_event_get_running_time_offset (event);
|
||||
if (upstream)
|
||||
offset -= pad->offset;
|
||||
offset -= applied_offset;
|
||||
else
|
||||
offset += pad->offset;
|
||||
offset += applied_offset;
|
||||
gst_event_set_running_time_offset (event, offset);
|
||||
|
||||
return event;
|
||||
|
@ -682,7 +683,7 @@ static inline GstEvent *
|
|||
apply_pad_offset (GstPad * pad, GstEvent * event, gboolean upstream)
|
||||
{
|
||||
if (G_UNLIKELY (pad->offset != 0))
|
||||
return _apply_pad_offset (pad, event, upstream);
|
||||
return _apply_pad_offset (pad, event, pad->offset, upstream);
|
||||
return event;
|
||||
}
|
||||
|
||||
|
@ -3803,9 +3804,16 @@ gst_pad_get_offset (GstPad * pad)
|
|||
return result;
|
||||
}
|
||||
|
||||
/* This function will make sure that previously set offset is
|
||||
* reverted as otherwise we would end up applying the new offset
|
||||
* on top of the previously set one, which is not what we want.
|
||||
* The event is also marked as not received. */
|
||||
static gboolean
|
||||
mark_event_not_received (GstPad * pad, PadEvent * ev, gpointer user_data)
|
||||
reschedule_event (GstPad * pad, PadEvent * ev, gint64 * prev_offset)
|
||||
{
|
||||
if (*prev_offset != 0)
|
||||
ev->event = _apply_pad_offset (pad, ev->event, -*prev_offset, FALSE);
|
||||
|
||||
ev->received = FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -3820,6 +3828,7 @@ mark_event_not_received (GstPad * pad, PadEvent * ev, gpointer user_data)
|
|||
void
|
||||
gst_pad_set_offset (GstPad * pad, gint64 offset)
|
||||
{
|
||||
gint64 prev_offset;
|
||||
g_return_if_fail (GST_IS_PAD (pad));
|
||||
|
||||
GST_OBJECT_LOCK (pad);
|
||||
|
@ -3827,14 +3836,16 @@ gst_pad_set_offset (GstPad * pad, gint64 offset)
|
|||
if (pad->offset == offset)
|
||||
goto done;
|
||||
|
||||
prev_offset = pad->offset;
|
||||
pad->offset = offset;
|
||||
GST_DEBUG_OBJECT (pad, "changed offset to %" GST_STIME_FORMAT,
|
||||
GST_STIME_ARGS (offset));
|
||||
|
||||
/* resend all sticky events with updated offset on next buffer push */
|
||||
events_foreach (pad, mark_event_not_received, NULL);
|
||||
events_foreach (pad, (PadEventFunction) reschedule_event, &prev_offset);
|
||||
GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_PENDING_EVENTS);
|
||||
|
||||
|
||||
done:
|
||||
GST_OBJECT_UNLOCK (pad);
|
||||
}
|
||||
|
@ -3876,8 +3887,10 @@ push_sticky (GstPad * pad, PadEvent * ev, gpointer user_data)
|
|||
GST_EVENT_TYPE (data->event) < GST_EVENT_TYPE (event)) {
|
||||
data->ret = GST_FLOW_CUSTOM_SUCCESS_1;
|
||||
} else {
|
||||
data->ret = gst_pad_push_event_unchecked (pad, gst_event_ref (event),
|
||||
gst_event_ref (event);
|
||||
data->ret = gst_pad_push_event_unchecked (pad, &event,
|
||||
GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM);
|
||||
gst_event_replace (&ev->event, event);
|
||||
if (data->ret == GST_FLOW_CUSTOM_SUCCESS_1)
|
||||
data->ret = GST_FLOW_OK;
|
||||
}
|
||||
|
@ -3948,7 +3961,8 @@ check_sticky (GstPad * pad, GstEvent * event)
|
|||
PadEvent *ev = find_event_by_type (pad, GST_EVENT_EOS, 0);
|
||||
|
||||
if (ev && !ev->received) {
|
||||
data.ret = gst_pad_push_event_unchecked (pad, gst_event_ref (ev->event),
|
||||
gst_event_ref (ev->event);
|
||||
data.ret = gst_pad_push_event_unchecked (pad, &ev->event,
|
||||
GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM);
|
||||
/* the event could have been dropped. Because this can only
|
||||
* happen if the user asked for it, it's not an error */
|
||||
|
@ -5250,12 +5264,13 @@ sticky_changed (GstPad * pad, PadEvent * ev, gpointer user_data)
|
|||
|
||||
/* should be called with pad LOCK */
|
||||
static GstFlowReturn
|
||||
gst_pad_push_event_unchecked (GstPad * pad, GstEvent * event,
|
||||
gst_pad_push_event_unchecked (GstPad * pad, GstEvent ** in_event,
|
||||
GstPadProbeType type)
|
||||
{
|
||||
GstFlowReturn ret;
|
||||
GstPad *peerpad;
|
||||
GstEventType event_type;
|
||||
GstEvent *event = *in_event;
|
||||
|
||||
/* pass the adjusted event on. We need to do this even if
|
||||
* there is no peer pad because of the probes. */
|
||||
|
@ -5367,6 +5382,9 @@ gst_pad_push_event_unchecked (GstPad * pad, GstEvent * event,
|
|||
PROBE_NO_DATA (pad, GST_PAD_PROBE_TYPE_PUSH | GST_PAD_PROBE_TYPE_IDLE,
|
||||
idle_probe_stopped, ret);
|
||||
}
|
||||
|
||||
*in_event = event;
|
||||
|
||||
return ret;
|
||||
|
||||
/* ERROR handling */
|
||||
|
@ -5487,7 +5505,7 @@ gst_pad_push_event (GstPad * pad, GstEvent * event)
|
|||
GstFlowReturn ret;
|
||||
|
||||
/* other events are pushed right away */
|
||||
ret = gst_pad_push_event_unchecked (pad, event, type);
|
||||
ret = gst_pad_push_event_unchecked (pad, &event, type);
|
||||
/* dropped events by a probe are not an error */
|
||||
res = (ret == GST_FLOW_OK || ret == GST_FLOW_CUSTOM_SUCCESS
|
||||
|| ret == GST_FLOW_CUSTOM_SUCCESS_1);
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#endif
|
||||
|
||||
#include <gst/check/gstcheck.h>
|
||||
#include <gst/check/gstharness.h>
|
||||
|
||||
static GstSegment dummy_segment;
|
||||
|
||||
|
@ -3282,6 +3283,61 @@ GST_START_TEST (test_pad_offset_src)
|
|||
|
||||
GST_END_TEST;
|
||||
|
||||
static GstPadProbeReturn
|
||||
update_stream_start_event_cb (GstPad * pad, GstPadProbeInfo * info,
|
||||
const gchar * wanted_stream_id)
|
||||
{
|
||||
GstEvent *event = info->data;
|
||||
|
||||
if (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_START) {
|
||||
const gchar *stream_id;
|
||||
|
||||
gst_event_parse_stream_start (event, &stream_id);
|
||||
g_assert_cmpstr (stream_id, !=, wanted_stream_id);
|
||||
|
||||
gst_event_unref (event);
|
||||
|
||||
info->data = gst_event_new_stream_start (wanted_stream_id);
|
||||
}
|
||||
|
||||
return GST_PAD_PROBE_OK;
|
||||
}
|
||||
|
||||
GST_START_TEST (test_sticky_events_changed_in_probe)
|
||||
{
|
||||
GstPad *srcpad;
|
||||
GstHarness *harness;
|
||||
GstEvent *stream_start;
|
||||
const gchar *stream_id;
|
||||
const gchar *wanted_stream_id = "The right stream ID";
|
||||
harness = gst_harness_new ("fakesrc");
|
||||
|
||||
gst_harness_add_probe (harness, "fakesrc", "src",
|
||||
GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
|
||||
(GstPadProbeCallback) update_stream_start_event_cb,
|
||||
(gpointer) wanted_stream_id, NULL);
|
||||
gst_harness_play (harness);
|
||||
gst_harness_set_blocking_push_mode (harness);
|
||||
gst_buffer_unref (gst_harness_pull (harness));
|
||||
|
||||
stream_start =
|
||||
gst_pad_get_sticky_event (harness->sinkpad, GST_EVENT_STREAM_START, 0);
|
||||
gst_event_parse_stream_start (stream_start, &stream_id);
|
||||
fail_unless_equals_string (stream_id, wanted_stream_id);
|
||||
gst_event_unref (stream_start);
|
||||
|
||||
srcpad = gst_element_get_static_pad (harness->element, "src");
|
||||
stream_start = gst_pad_get_sticky_event (srcpad, GST_EVENT_STREAM_START, 0);
|
||||
gst_event_unref (stream_start);
|
||||
gst_object_unref (srcpad);
|
||||
gst_event_parse_stream_start (stream_start, &stream_id);
|
||||
fail_unless_equals_string (stream_id, wanted_stream_id);
|
||||
|
||||
gst_harness_teardown (harness);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
static Suite *
|
||||
gst_pad_suite (void)
|
||||
{
|
||||
|
@ -3335,6 +3391,7 @@ gst_pad_suite (void)
|
|||
tcase_add_test (tc_chain, test_block_async_full_destroy_dispose);
|
||||
tcase_add_test (tc_chain, test_block_async_replace_callback_no_flush);
|
||||
tcase_add_test (tc_chain, test_sticky_events);
|
||||
tcase_add_test (tc_chain, test_sticky_events_changed_in_probe);
|
||||
tcase_add_test (tc_chain, test_last_flow_return_push);
|
||||
tcase_add_test (tc_chain, test_last_flow_return_pull);
|
||||
tcase_add_test (tc_chain, test_flush_stop_inactive);
|
||||
|
|
Loading…
Reference in a new issue