From: Edward Hervey Date: Tue, 14 Aug 2012 16:50:39 +0000 (+0200) Subject: check: Add streamsynchronizer unit test X-Git-Tag: RELEASE-0.11.94~130 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=784ca61cede6b6f85be1c98ebe5b577d2f0155ba;p=platform%2Fupstream%2Fgst-plugins-base.git check: Add streamsynchronizer unit test --- diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index bc67a7c..cd0a279 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -94,6 +94,7 @@ check_PROGRAMS = \ elements/audioconvert \ elements/audiotestsrc \ elements/decodebin \ + elements/streamsynchronizer \ $(check_encodebin) \ generic/clock-selection \ generic/states \ diff --git a/tests/check/elements/streamsynchronizer.c b/tests/check/elements/streamsynchronizer.c new file mode 100644 index 0000000..6119d89 --- /dev/null +++ b/tests/check/elements/streamsynchronizer.c @@ -0,0 +1,303 @@ +/* GStreamer unit tests for streamsynchronizer + * + * Copyright (C) 2012 Edward Hervey , Collabora Ltd + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#define GLIB_DISABLE_DEPRECATION_WARNINGS + +#include "../../../gst/playback/gststreamsynchronizer.c" + +#undef GST_CAT_DEFAULT +#include + +static GstStaticPadTemplate mysinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); +static GstStaticPadTemplate mysrctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +typedef struct +{ + GstPad *pad; + GList *to_push; +} MyPushInfo; + +GMutex push_mutex; +GCond push_cond; + +static GstPad * +get_other_pad (GstPad * pad) +{ + GstIterator *it; + GValue item = G_VALUE_INIT; + GstPad *otherpad; + + it = gst_pad_iterate_internal_links (pad); + fail_unless (gst_iterator_next (it, &item) == GST_ITERATOR_OK); + otherpad = g_value_dup_object (&item); + g_value_unset (&item); + gst_iterator_free (it); + + return otherpad; +} + +static GstFlowReturn +my_sink_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) +{ + GList **expected = GST_PAD_ELEMENT_PRIVATE (pad); + GList *next; + GstBuffer *exp; + + fail_if (*expected == NULL, + "streamsynchronizer pushed a buffer/event but we didn't expect any"); + + next = (*expected)->next; + + fail_if (GST_IS_EVENT ((*expected)->data), + "Expected an event (%s) but got a buffer instead", + GST_EVENT_TYPE_NAME (GST_EVENT ((*expected)->data))); + + exp = GST_BUFFER ((*expected)->data); + + fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (buf), + GST_BUFFER_TIMESTAMP (exp)); + + GST_DEBUG ("Properly received expected buffer"); + gst_buffer_unref (exp); + gst_buffer_unref (buf); + + g_list_free1 (*expected); + *expected = next; + + /* When done signal main thread */ + if (next == NULL) { + g_mutex_lock (&push_mutex); + g_cond_signal (&push_cond); + g_mutex_unlock (&push_mutex); + } + + return GST_FLOW_OK; +} + +static gboolean +my_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) +{ + GList **expected = GST_PAD_ELEMENT_PRIVATE (pad); + GList *next; + GstEvent *exp; + + fail_if (*expected == NULL, + "streamsynchronizer pushed a buffer/event but we didn't expect any"); + + next = (*expected)->next; + + fail_unless (GST_IS_EVENT ((*expected)->data), + "We were not expecting an event (But got an event of type %s)", + GST_EVENT_TYPE_NAME (event)); + exp = GST_EVENT ((*expected)->data); + fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_TYPE (exp), + "Got event of type %s but expected of type %s", + GST_EVENT_TYPE_NAME (event), GST_EVENT_TYPE_NAME (exp)); + fail_unless_equals_int (GST_EVENT_SEQNUM (event), GST_EVENT_SEQNUM (exp)); + /* FIXME : Check more types */ + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_SEGMENT: + { + const GstSegment *recvseg, *expectseg; + + /* Compare segment values */ + gst_event_parse_segment (event, &recvseg); + gst_event_parse_segment (exp, &expectseg); + + fail_unless_equals_int (recvseg->format, expectseg->format); + fail_unless_equals_uint64 (recvseg->base, expectseg->base); + fail_unless_equals_uint64 (recvseg->offset, expectseg->offset); + fail_unless_equals_uint64 (recvseg->start, expectseg->start); + fail_unless_equals_uint64 (recvseg->stop, expectseg->stop); + fail_unless_equals_uint64 (recvseg->time, expectseg->time); + fail_unless_equals_uint64 (recvseg->position, expectseg->position); + fail_unless_equals_uint64 (recvseg->duration, expectseg->duration); + } + break; + default: + break; + } + + GST_DEBUG ("Properly received expected event %s", GST_EVENT_TYPE_NAME (exp)); + + gst_event_unref (exp); + gst_event_unref (event); + + g_list_free1 (*expected); + *expected = next; + + /* When done signal main thread */ + if (next == NULL) { + g_mutex_lock (&push_mutex); + g_cond_signal (&push_cond); + g_mutex_unlock (&push_mutex); + } + + return TRUE; +} + +static void +my_push_thread (MyPushInfo * pushinfo) +{ + GList *tmp; + + /* FIXME : Do this in a thread */ + for (tmp = pushinfo->to_push; tmp; tmp = tmp->next) { + if (GST_IS_EVENT (tmp->data)) + gst_pad_push_event (pushinfo->pad, GST_EVENT (tmp->data)); + else + gst_pad_push (pushinfo->pad, GST_BUFFER (tmp->data)); + } +} + +GST_START_TEST (test_basic) +{ + GstElement *synchr; + GstPad *sinkpad, *srcpad; + GstPad *mysrcpad, *mysinkpad; + GList *to_push = NULL, *expected = NULL; + GstEvent *event; + GstBuffer *buf; + GThread *thread; + MyPushInfo pushinfo; + guint i; + GstSegment segment; + guint32 seqnum; + + synchr = g_object_new (GST_TYPE_STREAM_SYNCHRONIZER, NULL); + + /* Get sinkpad/srcpad */ + sinkpad = gst_element_get_request_pad (synchr, "sink_%u"); + fail_unless (sinkpad != NULL); + srcpad = get_other_pad (sinkpad); + fail_unless (srcpad != NULL); + + gst_element_set_state (synchr, GST_STATE_PLAYING); + + mysrcpad = gst_pad_new_from_static_template (&mysrctemplate, "src"); + fail_if (mysrcpad == NULL); + fail_unless (gst_pad_link (mysrcpad, sinkpad) == GST_PAD_LINK_OK); + fail_unless (gst_pad_set_active (mysrcpad, TRUE)); + + mysinkpad = gst_pad_new_from_static_template (&mysinktemplate, "sink"); + gst_pad_set_chain_function (mysinkpad, my_sink_chain); + gst_pad_set_event_function (mysinkpad, my_sink_event); + fail_if (mysinkpad == NULL); + fail_unless (gst_pad_link (srcpad, mysinkpad) == GST_PAD_LINK_OK); + fail_unless (gst_pad_set_active (mysinkpad, TRUE)); + GST_PAD_ELEMENT_PRIVATE (mysinkpad) = &expected; + + /* Start with a stream START and a new segment */ + event = gst_event_new_stream_start ("lala"); + to_push = g_list_append (to_push, event); + expected = g_list_append (expected, gst_event_ref (event)); + + gst_segment_init (&segment, GST_FORMAT_TIME); + event = gst_event_new_segment (&segment); + to_push = g_list_append (to_push, event); + expected = g_list_append (expected, gst_event_ref (event)); + + /* Then 10 buffers */ + for (i = 0; i < 10; i++) { + buf = gst_buffer_new (); + GST_BUFFER_TIMESTAMP (buf) = i * GST_SECOND; + GST_BUFFER_DURATION (buf) = GST_SECOND; + to_push = g_list_append (to_push, buf); + expected = g_list_append (expected, gst_buffer_ref (buf)); + } + + /* Then a new stream start */ + event = gst_event_new_stream_start ("lala again"); + to_push = g_list_append (to_push, event); + expected = g_list_append (expected, gst_event_ref (event)); + + /* This newsegment will be updated */ + gst_segment_init (&segment, GST_FORMAT_TIME); + event = gst_event_new_segment (&segment); + seqnum = gst_event_get_seqnum (event); + to_push = g_list_append (to_push, event); + /* The received segment's base should be updated by streamsynchronizer to + * take into account the amount of data played before (i.e. 10s) */ + segment.base = 10 * GST_SECOND; + event = gst_event_new_segment (&segment); + gst_event_set_seqnum (event, seqnum); + expected = g_list_append (expected, event); + + /* Then 10 buffers */ + for (i = 0; i < 10; i++) { + buf = gst_buffer_new (); + GST_BUFFER_TIMESTAMP (buf) = i * GST_SECOND; + GST_BUFFER_DURATION (buf) = GST_SECOND; + to_push = g_list_append (to_push, buf); + expected = g_list_append (expected, gst_buffer_ref (buf)); + } + + g_mutex_init (&push_mutex); + g_cond_init (&push_cond); + + pushinfo.pad = mysrcpad; + pushinfo.to_push = to_push; + g_mutex_lock (&push_mutex); + thread = + g_thread_create ((GThreadFunc) my_push_thread, &pushinfo, FALSE, NULL); + fail_unless (thread != NULL); + + g_cond_wait (&push_cond, &push_mutex); + g_mutex_unlock (&push_mutex); + + fail_if (expected != NULL); + + /* Cleanup */ + g_list_free (to_push); + gst_element_release_request_pad (synchr, sinkpad); + gst_object_unref (srcpad); + gst_object_unref (sinkpad); + gst_object_unref (mysinkpad); + gst_object_unref (mysrcpad); + gst_element_set_state (synchr, GST_STATE_NULL); + gst_object_unref (synchr); +} + +GST_END_TEST; + +static Suite * +streamsynchronizer_suite (void) +{ + Suite *s = suite_create ("streamsynchronizer"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_basic); + + return s; +} + +GST_CHECK_MAIN (streamsynchronizer);