diff options
author | Alessandro Decina <alessandro.decina@collabora.co.uk> | 2009-03-05 16:52:13 +0100 |
---|---|---|
committer | Alessandro Decina <alessandro.decina@collabora.co.uk> | 2009-03-06 14:02:31 +0100 |
commit | 3b47c9695a5b6ae13290e72a79933e863b766677 (patch) | |
tree | d557781bcb75e2a6415975e84c12ca27253cf5e0 | |
parent | 4bae76ebf73508937f0cc58501a1e402aa068f5e (diff) |
GnlComposition: rebuild the stack when an object in the current stack is moved
outside the active segment.
-rw-r--r-- | gnl/gnlcomposition.c | 10 | ||||
-rw-r--r-- | tests/check/Makefile.am | 3 | ||||
-rw-r--r-- | tests/check/gnlcomposition.c | 244 |
3 files changed, 254 insertions, 3 deletions
diff --git a/gnl/gnlcomposition.c b/gnl/gnlcomposition.c index 975c926..85f2309 100644 --- a/gnl/gnlcomposition.c +++ b/gnl/gnlcomposition.c @@ -2164,6 +2164,8 @@ update_pipeline (GnlComposition * comp, GstClockTime currenttime, gnl_object_remove_ghost_pad ((GnlObject *) comp, comp->private->ghostpad); comp->private->ghostpad = NULL; + comp->private->segment_start = 0; + comp->private->segment_stop = GST_CLOCK_TIME_NONE; } } } else { @@ -2191,7 +2193,9 @@ object_start_changed (GnlObject * object, GParamSpec * arg, comp->private->objects_stop = g_list_sort (comp->private->objects_stop, (GCompareFunc) objects_stop_compare); - if (comp->private->current && OBJECT_IN_ACTIVE_SEGMENT (comp, object)) { + if (comp->private->current && (OBJECT_IN_ACTIVE_SEGMENT (comp, object) || + g_node_find (comp->private->current, + G_IN_ORDER, G_TRAVERSE_ALL, object))) { GstClockTime curpos = get_current_position (comp); if (curpos == GST_CLOCK_TIME_NONE) curpos = comp->private->segment->start = comp->private->segment_start; @@ -2213,7 +2217,9 @@ object_stop_changed (GnlObject * object, GParamSpec * arg, comp->private->objects_start = g_list_sort (comp->private->objects_start, (GCompareFunc) objects_start_compare); - if (comp->private->current && OBJECT_IN_ACTIVE_SEGMENT (comp, object)) { + if (comp->private->current && (OBJECT_IN_ACTIVE_SEGMENT (comp, object) || + g_node_find (comp->private->current, + G_IN_ORDER, G_TRAVERSE_ALL, object))) { GstClockTime curpos = get_current_position (comp); if (curpos == GST_CLOCK_TIME_NONE) curpos = comp->private->segment->start = comp->private->segment_start; diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index 6bc3bf0..af258ba 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -25,7 +25,8 @@ check_PROGRAMS = \ ./simple \ ./complex \ ./gnlsource \ - ./gnloperation + ./gnloperation \ + ./gnlcomposition noinst_HEADERS = \ common.h diff --git a/tests/check/gnlcomposition.c b/tests/check/gnlcomposition.c new file mode 100644 index 0000000..8b7f7a0 --- /dev/null +++ b/tests/check/gnlcomposition.c @@ -0,0 +1,244 @@ +/* Gnonlin + * Copyright (C) <2009> Alessandro Decina <alessandro.decina@collabora.co.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#include "common.h" + +static int composition_pad_added; +static int composition_pad_removed; +static int seek_events; + +static gboolean +on_source1_pad_event_cb (GstPad * pad, GstEvent * event, gpointer user_data) +{ + if (event->type == GST_EVENT_SEEK) + ++seek_events; + + return TRUE; +} + +static void +on_source1_pad_added_cb (GstElement * source, GstPad * pad, gpointer user_data) +{ + gst_pad_add_event_probe (pad, G_CALLBACK (on_source1_pad_event_cb), NULL); +} + +static void +on_composition_pad_added_cb (GstElement * composition, GstPad * pad, + GstElement * sink) +{ + GstPad *s = gst_element_get_pad (sink, "sink"); + gst_pad_link (pad, s); + ++composition_pad_added; +} + +static void +on_composition_pad_removed_cb (GstElement * composition, GstPad * pad, + GstElement * sink) +{ + ++composition_pad_removed; +} + +GST_START_TEST (test_change_object_start_stop_in_current_stack) +{ + GstElement *pipeline; + guint64 start, stop; + gint64 duration; + GstElement *comp, *source1, *def, *sink; + GstBus *bus; + GstMessage *message; + gboolean carry_on; + int seek_events_before; + + pipeline = gst_pipeline_new ("test_pipeline"); + comp = + gst_element_factory_make_or_warn ("gnlcomposition", "test_composition"); + + sink = gst_element_factory_make_or_warn ("fakesink", "sink"); + gst_bin_add_many (GST_BIN (pipeline), comp, sink, NULL); + + /* connect to pad-added */ + g_object_connect (comp, "signal::pad-added", + on_composition_pad_added_cb, sink, NULL); + g_object_connect (comp, "signal::pad-removed", + on_composition_pad_removed_cb, NULL, NULL); + + /* + source1 + Start : 0s + Duration : 2s + Priority : 2 + */ + + source1 = videotest_gnl_src ("source1", 0, 2 * GST_SECOND, 1, 2); + g_object_connect (source1, "signal::pad-added", + on_source1_pad_added_cb, NULL, NULL); + + check_start_stop_duration (source1, 0, 2 * GST_SECOND, 2 * GST_SECOND); + + /* + def (default source) + Priority = G_MAXUINT32 + */ + def = + videotest_gnl_src ("default", 0 * GST_SECOND, 0 * GST_SECOND, 1, + G_MAXUINT32); + + ASSERT_OBJECT_REFCOUNT (source1, "source1", 1); + ASSERT_OBJECT_REFCOUNT (def, "default", 1); + + /* Add source 1 */ + + /* keep an extra ref to source1 as we remove it from the bin */ + gst_object_ref (source1); + gst_bin_add (GST_BIN (comp), source1); + check_start_stop_duration (comp, 0, 2 * GST_SECOND, 2 * GST_SECOND); + + /* Add default */ + + gst_bin_add (GST_BIN (comp), def); + check_start_stop_duration (comp, 0, 2 * GST_SECOND, 2 * GST_SECOND); + + bus = gst_element_get_bus (GST_ELEMENT (pipeline)); + + GST_DEBUG ("Setting pipeline to PLAYING"); + ASSERT_OBJECT_REFCOUNT (source1, "source1", 2); + + fail_if (gst_element_set_state (GST_ELEMENT (pipeline), + GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE); + + GST_DEBUG ("Let's poll the bus"); + + carry_on = TRUE; + while (carry_on) { + message = gst_bus_poll (bus, GST_MESSAGE_ANY, GST_SECOND / 2); + if (message) { + switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_STATE_CHANGED: + { + GstState old, current, pending; + gst_message_parse_state_changed (message, &old, ¤t, &pending); + + if (message->src == GST_OBJECT (pipeline)) { + if (current == GST_STATE_PAUSED) + carry_on = FALSE; + } + break; + } + case GST_MESSAGE_EOS: + { + GST_WARNING ("Saw EOS"); + + fail_if (TRUE); + } + case GST_MESSAGE_ERROR: + { + GError *error; + char *debug; + + gst_message_parse_error (message, &error, &debug); + + GST_WARNING ("Saw an ERROR %s: %s (%s)", + gst_object_get_name (message->src), error->message, debug); + + g_error_free (error); + fail_if (TRUE); + } + default: + break; + } + gst_mini_object_unref (GST_MINI_OBJECT (message)); + } + } + + fail_unless_equals_int (composition_pad_added, 1); + fail_unless_equals_int (composition_pad_removed, 0); + + seek_events_before = seek_events; + + /* pipeline is paused at this point */ + + /* move source1 out of the active segment */ + g_object_set (source1, "start", 4 * GST_SECOND, NULL); + fail_unless (seek_events > seek_events_before); + + /* remove source1 from the composition, which will become empty and remove the + * ghostpad */ + gst_bin_remove (GST_BIN (comp), source1); + ASSERT_OBJECT_REFCOUNT (source1, "source1", 1); + + fail_unless_equals_int (composition_pad_added, 1); + fail_unless_equals_int (composition_pad_removed, 1); + + g_object_set (source1, "start", 0 * GST_SECOND, NULL); + /* add the source again and check that the ghostpad is added again */ + gst_bin_add (GST_BIN (comp), source1); + + fail_unless_equals_int (composition_pad_added, 2); + fail_unless_equals_int (composition_pad_removed, 1); + + seek_events_before = seek_events; + + g_object_set (source1, "duration", 1 * GST_SECOND, NULL); + fail_unless (seek_events > seek_events_before); + + GST_DEBUG ("Setting pipeline to NULL"); + + fail_if (gst_element_set_state (GST_ELEMENT (pipeline), + GST_STATE_NULL) == GST_STATE_CHANGE_FAILURE); + gst_element_set_state (source1, GST_STATE_NULL); + gst_object_unref (source1); + + GST_DEBUG ("Resetted pipeline to READY"); + + ASSERT_OBJECT_REFCOUNT_BETWEEN (pipeline, "main pipeline", 1, 2); + gst_object_unref (pipeline); + ASSERT_OBJECT_REFCOUNT_BETWEEN (bus, "main bus", 1, 2); + gst_object_unref (bus); +} + +GST_END_TEST; + +Suite * +gnonlin_suite (void) +{ + Suite *s = suite_create ("gnonlin"); + TCase *tc_chain = tcase_create ("gnlcomposition"); + + suite_add_tcase (s, tc_chain); + + tcase_add_test (tc_chain, test_change_object_start_stop_in_current_stack); + + return s; +} + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = gnonlin_suite (); + SRunner *sr = srunner_create (s); + + gst_check_init (&argc, &argv); + + srunner_run_all (sr, CK_NORMAL); + nf = srunner_ntests_failed (sr); + srunner_free (sr); + + return nf; +} |