From b375dde1a7ecebb254cda0c222b0af4417f30c70 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 29 May 2006 15:49:53 +0000 Subject: [PATCH] gst/adder/gstadder.c: Fix adder seeking. Original commit message from CVS: * gst/adder/gstadder.c: (gst_adder_query_duration), (forward_event_func), (forward_event), (gst_adder_src_event): Fix adder seeking. Make query/seeking code threadsafe. * tests/check/Makefile.am: * tests/check/elements/adder.c: (test_event_message_received), (GST_START_TEST), (test_play_twice_message_received): Fix adder test case. --- ChangeLog | 12 +++ gst/adder/gstadder.c | 141 ++++++++++++++++++++++++----------- tests/check/Makefile.am | 1 + tests/check/elements/adder.c | 28 +++++-- 4 files changed, 133 insertions(+), 49 deletions(-) diff --git a/ChangeLog b/ChangeLog index 93ca741957..58bf67586b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2006-05-29 Wim Taymans + + * gst/adder/gstadder.c: (gst_adder_query_duration), + (forward_event_func), (forward_event), (gst_adder_src_event): + Fix adder seeking. + Make query/seeking code threadsafe. + + * tests/check/Makefile.am: + * tests/check/elements/adder.c: (test_event_message_received), + (GST_START_TEST), (test_play_twice_message_received): + Fix adder test case. + 2006-05-29 Tim-Philipp Müller Patch by: Young-Ho Cha diff --git a/gst/adder/gstadder.c b/gst/adder/gstadder.c index f685ec0b67..45528ef1eb 100644 --- a/gst/adder/gstadder.c +++ b/gst/adder/gstadder.c @@ -245,47 +245,70 @@ not_supported: * eachother which we can get from the first timestamps we see. * When we add a new stream (or remove a stream) the duration might * also become invalid again and we need to post a new DURATION - * message to ntify this fact to the parent. + * message to notify this fact to the parent. * For now we take the max of all the upstream elements so the simple * cases work at least somewhat. */ static gboolean gst_adder_query_duration (GstAdder * adder, GstQuery * query) { - GList *pads; gint64 max; gboolean res; GstFormat format; - - max = -1; - res = TRUE; + GstIterator *it; + gboolean done; /* parse format */ gst_query_parse_duration (query, &format, NULL); - GST_OBJECT_LOCK (adder); - pads = GST_ELEMENT_CAST (adder)->sinkpads; - for (; pads; pads = g_list_next (pads)) { - GstPad *pad = GST_PAD_CAST (pads->data); - gint64 duration; + max = -1; + res = TRUE; + done = FALSE; - /* ask sink peer for duration */ - res &= gst_pad_query_peer_duration (pad, &format, &duration); - /* take max from all valid return values */ - if (res) { - /* valid unknown length, stop searching */ - if (duration == -1) { - max = duration; + it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (adder)); + while (!done) { + GstIteratorResult ires; + gpointer item; + + ires = gst_iterator_next (it, &item); + switch (ires) { + case GST_ITERATOR_DONE: + done = TRUE; + break; + case GST_ITERATOR_OK: + { + GstPad *pad = GST_PAD_CAST (item); + gint64 duration; + + /* ask sink peer for duration */ + res &= gst_pad_query_peer_duration (pad, &format, &duration); + /* take max from all valid return values */ + if (res) { + /* valid unknown length, stop searching */ + if (duration == -1) { + max = duration; + done = TRUE; + } + /* else see if bigger than current max */ + else if (duration > max) + max = duration; + } break; } - /* else see if bigger than current max */ - else if (duration > max) - max = duration; + case GST_ITERATOR_RESYNC: + max = -1; + res = TRUE; + break; + default: + res = FALSE; + done = TRUE; + break; } } - GST_OBJECT_UNLOCK (adder); - /* and store the max */ - gst_query_set_duration (query, format, max); + if (res) { + /* and store the max */ + gst_query_set_duration (query, format, max); + } return res; } @@ -332,6 +355,22 @@ gst_adder_query (GstPad * pad, GstQuery * query) return res; } +static gboolean +forward_event_func (GstPad * pad, GValue * ret, GstEvent * event) +{ + gst_event_ref (event); + if (!gst_pad_push_event (pad, event)) { + g_value_set_boolean (ret, FALSE); + GST_WARNING_OBJECT (pad, "Sending event %p (%s) failed.", + event, GST_EVENT_TYPE_NAME (event)); + } else { + GST_LOG_OBJECT (pad, "Sent event %p (%s).", + event, GST_EVENT_TYPE_NAME (event)); + } + gst_object_unref (pad); + return TRUE; +} + /* forwards the event to all sinkpads, takes ownership of the * event * @@ -342,34 +381,24 @@ static gboolean forward_event (GstAdder * adder, GstEvent * event) { gboolean ret; - GList *pads; + GstIterator *it; + GValue vret = { 0 }; GST_LOG_OBJECT (adder, "Forwarding event %p (%s)", event, GST_EVENT_TYPE_NAME (event)); ret = TRUE; - GST_OBJECT_LOCK (adder); - pads = GST_ELEMENT_CAST (adder)->sinkpads; - for (; pads; pads = g_list_next (pads)) { - GstPad *pad = GST_PAD_CAST (pads->data); - - gst_event_ref (event); - ret &= gst_pad_push_event (pad, event); - - if (!ret) { - GST_WARNING_OBJECT (pad, "Sending event %p (%s) failed.", - event, GST_EVENT_TYPE_NAME (event)); - break; - } else { - GST_LOG_OBJECT (pad, "Sent event %p (%s).", - event, GST_EVENT_TYPE_NAME (event)); - } - } - GST_OBJECT_UNLOCK (adder); - + g_value_init (&vret, G_TYPE_BOOLEAN); + g_value_set_boolean (&vret, TRUE); + it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (adder)); + gst_iterator_fold (it, (GstIteratorFoldFunction) forward_event_func, &vret, + event); + gst_iterator_free (it); gst_event_unref (event); + ret = g_value_get_boolean (&vret); + return ret; } @@ -387,9 +416,33 @@ gst_adder_src_event (GstPad * pad, GstEvent * event) result = FALSE; break; case GST_EVENT_SEEK: - /* FIXME seek needs something smarter. */ + { + GstSeekFlags flags; + + /* parse the flushing flag */ + gst_event_parse_seek (event, NULL, NULL, &flags, NULL, NULL, NULL, NULL); + + /* if we are not flushing, just forward */ + if (!flags & GST_SEEK_FLAG_FLUSH) + goto done; + + /* make sure we accept nothing anymore and return WRONG_STATE */ + gst_collect_pads_set_flushing (adder->collect, TRUE); + + /* flushing seek, start flush downstream, the flush will be done + * when all pads received a FLUSH_STOP. */ + gst_pad_push_event (adder->srcpad, gst_event_new_flush_start ()); + + /* now wait for the collected to be finished and mark a new + * segment */ + GST_OBJECT_LOCK (adder->collect); + adder->segment_pending = TRUE; + GST_OBJECT_UNLOCK (adder->collect); + + done: result = forward_event (adder, event); break; + } case GST_EVENT_NAVIGATION: /* navigation is rather pointless. */ result = FALSE; diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index 372133f0f8..5b9e5fef08 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -43,6 +43,7 @@ check_PROGRAMS = \ $(check_alsa) \ $(check_vorbis) \ $(check_theora) \ + elements/adder \ elements/audioconvert \ elements/audioresample \ elements/audiotestsrc \ diff --git a/tests/check/elements/adder.c b/tests/check/elements/adder.c index 7ee89a5670..f20ef43527 100644 --- a/tests/check/elements/adder.c +++ b/tests/check/elements/adder.c @@ -76,6 +76,7 @@ test_event_message_received (GstBus * bus, GstMessage * message, g_main_loop_quit (main_loop); break; default: + g_assert_not_reached (); break; } } @@ -114,7 +115,7 @@ GST_START_TEST (test_event) fail_unless (res == TRUE, NULL); seek_event = gst_event_new_seek (1.0, GST_FORMAT_TIME, - GST_SEEK_FLAG_SEGMENT, + GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, (GstClockTime) 0, GST_SEEK_TYPE_SET, (GstClockTime) 2 * GST_SECOND); @@ -134,9 +135,10 @@ GST_START_TEST (test_event) res = gst_element_set_state (bin, GST_STATE_PAUSED); fail_unless (res != GST_STATE_CHANGE_FAILURE, NULL); - /* FIXME, PAUSED is async and seek might not work before being prerolled. - * though it should work in this case, as audiotestsrc is a live source - */ + /* wait for completion */ + res = gst_element_get_state (bin, NULL, NULL, GST_CLOCK_TIME_NONE); + fail_unless (res != GST_STATE_CHANGE_FAILURE, NULL); + res = gst_element_send_event (bin, seek_event); fail_unless (res == TRUE, NULL); @@ -184,9 +186,18 @@ test_play_twice_message_received (GstBus * bus, GstMessage * message, res = gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PAUSED); fail_unless (res != GST_STATE_CHANGE_FAILURE, NULL); + /* wait for completion */ + res = + gst_element_get_state (GST_ELEMENT (bin), NULL, NULL, + GST_CLOCK_TIME_NONE); + fail_unless (res != GST_STATE_CHANGE_FAILURE, NULL); + res = gst_element_send_event (GST_ELEMENT (bin), play_seek_event); fail_unless (res == TRUE, NULL); + /* event is now gone */ + play_seek_event = NULL; + res = gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PLAYING); fail_unless (res != GST_STATE_CHANGE_FAILURE, NULL); } else { @@ -194,6 +205,7 @@ test_play_twice_message_received (GstBus * bus, GstMessage * message, } break; default: + g_assert_not_reached (); break; } } @@ -228,7 +240,7 @@ GST_START_TEST (test_play_twice) fail_unless (res == TRUE, NULL); play_seek_event = gst_event_new_seek (1.0, GST_FORMAT_TIME, - GST_SEEK_FLAG_SEGMENT, + GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, (GstClockTime) 0, GST_SEEK_TYPE_SET, (GstClockTime) 2 * GST_SECOND); @@ -247,6 +259,12 @@ GST_START_TEST (test_play_twice) res = gst_element_set_state (bin, GST_STATE_PAUSED); fail_unless (res != GST_STATE_CHANGE_FAILURE, NULL); + /* wait for completion */ + res = + gst_element_get_state (GST_ELEMENT (bin), NULL, NULL, + GST_CLOCK_TIME_NONE); + fail_unless (res != GST_STATE_CHANGE_FAILURE, NULL); + res = gst_element_send_event (bin, gst_event_ref (play_seek_event)); fail_unless (res == TRUE, NULL);