X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=tests%2Fcheck%2Felements%2Fqueue.c;h=50f28964b517f703afe4f2f4516b5976b21d795d;hb=3b54dace2ded6c7a1e7577ef13014079923e3af1;hp=7ccfec7866244545ea5723846cbba20f8113e672;hpb=df6044f7ebdaf0c38217c95b7d9cc5340567d800;p=platform%2Fupstream%2Fgstreamer.git diff --git a/tests/check/elements/queue.c b/tests/check/elements/queue.c index 7ccfec7..50f2896 100644 --- a/tests/check/elements/queue.c +++ b/tests/check/elements/queue.c @@ -16,18 +16,19 @@ * * 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ - -#include +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include -#define UNDERRUN_LOCK() (g_mutex_lock (underrun_mutex)) -#define UNDERRUN_UNLOCK() (g_mutex_unlock (underrun_mutex)) -#define UNDERRUN_SIGNAL() (g_cond_signal (underrun_cond)) -#define UNDERRUN_WAIT() (g_cond_wait (underrun_cond, underrun_mutex)) +#define UNDERRUN_LOCK() (g_mutex_lock (&underrun_mutex)) +#define UNDERRUN_UNLOCK() (g_mutex_unlock (&underrun_mutex)) +#define UNDERRUN_SIGNAL() (g_cond_signal (&underrun_cond)) +#define UNDERRUN_WAIT() (g_cond_wait (&underrun_cond, &underrun_mutex)) static GstElement *queue; @@ -36,13 +37,18 @@ static GstElement *queue; * get_peer, and then remove references in every test function */ static GstPad *mysrcpad; static GstPad *mysinkpad; +static GstPad *qsrcpad; +static gulong probe_id; static gint overrun_count; -static GMutex *underrun_mutex; -static GCond *underrun_cond; +static GMutex underrun_mutex; +static GCond underrun_cond; static gint underrun_count; +static GMutex events_lock; +static GCond events_cond; +static gint events_count; static GList *events; static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", @@ -57,36 +63,49 @@ static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", static void queue_overrun (GstElement * queue, gpointer user_data) { - GST_DEBUG ("queue overrun"); overrun_count++; + GST_DEBUG ("queue overrun %d", overrun_count); } static void queue_underrun (GstElement * queue, gpointer user_data) { - GST_DEBUG ("queue underrun"); UNDERRUN_LOCK (); underrun_count++; + GST_DEBUG ("queue underrun %d", underrun_count); UNDERRUN_SIGNAL (); UNDERRUN_UNLOCK (); } static gboolean -event_func (GstPad * pad, GstEvent * event) +event_func (GstPad * pad, GstObject * parent, GstEvent * event) { - GST_DEBUG ("%s event", gst_event_type_get_name (GST_EVENT_TYPE (event))); + GST_DEBUG ("%s event", GST_EVENT_TYPE_NAME (event)); + + g_mutex_lock (&events_lock); + events = g_list_append (events, event); + ++events_count; + + g_cond_broadcast (&events_cond); + g_mutex_unlock (&events_lock); return TRUE; } static void -drop_events (void) +block_src (void) { - while (events != NULL) { - gst_event_unref (GST_EVENT (events->data)); - events = g_list_delete_link (events, events); - } + qsrcpad = gst_element_get_static_pad (queue, "src"); + probe_id = gst_pad_add_probe (qsrcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, + NULL, NULL, NULL); +} + +static void +unblock_src (void) +{ + gst_pad_remove_probe (qsrcpad, probe_id); + gst_object_unref (qsrcpad); } static void @@ -97,17 +116,19 @@ setup (void) queue = gst_check_setup_element ("queue"); g_signal_connect (queue, "underrun", G_CALLBACK (queue_underrun), NULL); - mysrcpad = gst_check_setup_src_pad (queue, &srctemplate, NULL); + mysrcpad = gst_check_setup_src_pad (queue, &srctemplate); gst_pad_set_active (mysrcpad, TRUE); mysinkpad = NULL; overrun_count = 0; - underrun_mutex = g_mutex_new (); - underrun_cond = g_cond_new (); underrun_count = 0; + + g_mutex_init (&events_lock); + g_cond_init (&events_cond); + events_count = 0; events = NULL; } @@ -118,12 +139,13 @@ cleanup (void) gst_check_drop_buffers (); - drop_events (); - - g_cond_free (underrun_cond); - underrun_cond = NULL; - g_mutex_free (underrun_mutex); - underrun_mutex = NULL; + while (events != NULL) { + gst_event_unref (GST_EVENT (events->data)); + events = g_list_delete_link (events, events); + } + events_count = 0; + g_mutex_clear (&events_lock); + g_cond_clear (&events_cond); if (mysinkpad != NULL) { gst_pad_set_active (mysinkpad, FALSE); @@ -167,7 +189,7 @@ GST_START_TEST (test_non_leaky_underrun) { g_signal_connect (queue, "overrun", G_CALLBACK (queue_overrun), NULL); g_object_set (G_OBJECT (queue), "max-size-buffers", 2, NULL); - mysinkpad = gst_check_setup_sink_pad (queue, &sinktemplate, NULL); + mysinkpad = gst_check_setup_sink_pad (queue, &sinktemplate); gst_pad_set_active (mysinkpad, TRUE); GST_DEBUG ("starting"); @@ -197,6 +219,8 @@ queue_overrun_link_and_activate (GstElement * queue, gpointer user_data) /* link the src pad of the queue to make it dequeue buffers */ mysinkpad = setup_sink_pad (queue, &sinktemplate); + + unblock_src (); } /* set queue size to 2 buffers @@ -211,18 +235,29 @@ GST_START_TEST (test_non_leaky_overrun) GstBuffer *buffer2; GstBuffer *buffer3; GstBuffer *buffer; + GstSegment segment; g_signal_connect (queue, "overrun", G_CALLBACK (queue_overrun_link_and_activate), NULL); g_object_set (G_OBJECT (queue), "max-size-buffers", 2, NULL); + block_src (); + GST_DEBUG ("starting"); + UNDERRUN_LOCK (); fail_unless (gst_element_set_state (queue, GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, "could not set to playing"); + UNDERRUN_WAIT (); + UNDERRUN_UNLOCK (); + + gst_segment_init (&segment, GST_FORMAT_BYTES); + gst_pad_push_event (mysrcpad, gst_event_new_stream_start ("test")); + gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)); + + fail_unless (underrun_count == 1); fail_unless (overrun_count == 0); - fail_unless (underrun_count == 0); buffer1 = gst_buffer_new_and_alloc (4); /* pushing gives away my reference */ @@ -230,18 +265,16 @@ GST_START_TEST (test_non_leaky_overrun) GST_DEBUG ("added 1st"); fail_unless (overrun_count == 0); - fail_unless (underrun_count == 0); + fail_unless (underrun_count == 1); buffer2 = gst_buffer_new_and_alloc (4); gst_pad_push (mysrcpad, buffer2); GST_DEBUG ("added 2nd"); fail_unless (overrun_count == 0); - fail_unless (underrun_count == 0); + fail_unless (underrun_count == 1); buffer3 = gst_buffer_new_and_alloc (4); - /* lock the check_mutex to block the first buffer pushed to mysinkpad */ - g_mutex_lock (check_mutex); /* the next call to gst_pad_push will emit the overrun signal. The signal * handler queue_overrun_link_and_activate() (above) increases overrun_count, * activates and links mysinkpad. The queue task then dequeues a buffer and @@ -250,22 +283,27 @@ GST_START_TEST (test_non_leaky_overrun) GST_DEBUG ("added 3rd"); fail_unless (overrun_count == 1); - fail_unless (underrun_count == 0); + /* lock the check_mutex to block the first buffer pushed to mysinkpad */ + g_mutex_lock (&check_mutex); /* now let the queue push all buffers */ while (g_list_length (buffers) < 3) { - g_cond_wait (check_cond, check_mutex); + g_cond_wait (&check_cond, &check_mutex); } - g_mutex_unlock (check_mutex); + g_mutex_unlock (&check_mutex); fail_unless (overrun_count == 1); /* make sure we get the underrun signal before we check underrun_count */ UNDERRUN_LOCK (); - while (underrun_count < 1) { + while (underrun_count < 2) { UNDERRUN_WAIT (); } + /* we can't check the underrun_count here safely because when adding the 3rd + * buffer, the queue lock is released to emit the overrun signal and the + * downstream part can then push and empty the queue and signal an additional + * underrun */ + /* fail_unless_equals_int (underrun_count, 2); */ UNDERRUN_UNLOCK (); - fail_unless (underrun_count == 1); buffer = g_list_nth (buffers, 0)->data; fail_unless (buffer == buffer1); @@ -273,9 +311,6 @@ GST_START_TEST (test_non_leaky_overrun) buffer = g_list_nth (buffers, 1)->data; fail_unless (buffer == buffer2); - buffer = g_list_nth (buffers, 2)->data; - fail_unless (buffer == buffer3); - GST_DEBUG ("stopping"); fail_unless (gst_element_set_state (queue, GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null"); @@ -296,17 +331,28 @@ GST_START_TEST (test_leaky_upstream) GstBuffer *buffer2; GstBuffer *buffer3; GstBuffer *buffer; + GstSegment segment; g_signal_connect (queue, "overrun", G_CALLBACK (queue_overrun), NULL); g_object_set (G_OBJECT (queue), "max-size-buffers", 2, "leaky", 1, NULL); GST_DEBUG ("starting"); + block_src (); + + UNDERRUN_LOCK (); fail_unless (gst_element_set_state (queue, GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, "could not set to playing"); + UNDERRUN_WAIT (); + UNDERRUN_UNLOCK (); + + gst_segment_init (&segment, GST_FORMAT_BYTES); + gst_pad_push_event (mysrcpad, gst_event_new_stream_start ("test")); + gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)); + fail_unless (overrun_count == 0); - fail_unless (underrun_count == 0); + fail_unless (underrun_count == 1); buffer1 = gst_buffer_new_and_alloc (4); /* pushing gives away my reference */ @@ -314,33 +360,34 @@ GST_START_TEST (test_leaky_upstream) GST_DEBUG ("added 1st"); fail_unless (overrun_count == 0); - fail_unless (underrun_count == 0); + fail_unless (underrun_count == 1); buffer2 = gst_buffer_new_and_alloc (4); gst_pad_push (mysrcpad, buffer2); GST_DEBUG ("added 2nd"); fail_unless (overrun_count == 0); - fail_unless (underrun_count == 0); + fail_unless (underrun_count == 1); buffer3 = gst_buffer_new_and_alloc (4); - /* buffer3 will be leaked, keep a ref so refcount can be checked below */ + /* buffer4 will be leaked, keep a ref so refcount can be checked below */ gst_buffer_ref (buffer3); gst_pad_push (mysrcpad, buffer3); - GST_DEBUG ("added 3rd"); + GST_DEBUG ("added 3nd"); /* it still triggers overrun when leaking */ fail_unless (overrun_count == 1); - fail_unless (underrun_count == 0); + fail_unless (underrun_count == 1); /* wait for underrun and check that we got buffer1 and buffer2 only */ UNDERRUN_LOCK (); mysinkpad = setup_sink_pad (queue, &sinktemplate); + unblock_src (); UNDERRUN_WAIT (); UNDERRUN_UNLOCK (); fail_unless (overrun_count == 1); - fail_unless (underrun_count == 1); + fail_unless (underrun_count == 2); fail_unless (g_list_length (buffers) == 2); @@ -373,34 +420,45 @@ GST_START_TEST (test_leaky_downstream) GstBuffer *buffer2; GstBuffer *buffer3; GstBuffer *buffer; + GstSegment segment; g_signal_connect (queue, "overrun", G_CALLBACK (queue_overrun), NULL); g_object_set (G_OBJECT (queue), "max-size-buffers", 2, "leaky", 2, NULL); GST_DEBUG ("starting"); + block_src (); + + UNDERRUN_LOCK (); fail_unless (gst_element_set_state (queue, GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, "could not set to playing"); + UNDERRUN_WAIT (); + UNDERRUN_UNLOCK (); + + gst_segment_init (&segment, GST_FORMAT_BYTES); + gst_pad_push_event (mysrcpad, gst_event_new_stream_start ("test")); + gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)); + fail_unless (overrun_count == 0); - fail_unless (underrun_count == 0); + fail_unless (underrun_count == 1); buffer1 = gst_buffer_new_and_alloc (4); + /* pushing gives away one reference */ /* buffer1 will be leaked, keep a ref so refcount can be checked below */ gst_buffer_ref (buffer1); - /* pushing gives away one reference */ gst_pad_push (mysrcpad, buffer1); GST_DEBUG ("added 1st"); fail_unless (overrun_count == 0); - fail_unless (underrun_count == 0); + fail_unless (underrun_count == 1); buffer2 = gst_buffer_new_and_alloc (4); gst_pad_push (mysrcpad, buffer2); GST_DEBUG ("added 2nd"); fail_unless (overrun_count == 0); - fail_unless (underrun_count == 0); + fail_unless (underrun_count == 1); buffer3 = gst_buffer_new_and_alloc (4); gst_pad_push (mysrcpad, buffer3); @@ -408,16 +466,17 @@ GST_START_TEST (test_leaky_downstream) GST_DEBUG ("added 3rd"); /* it still triggers overrun when leaking */ fail_unless (overrun_count == 1); - fail_unless (underrun_count == 0); + fail_unless (underrun_count == 1); /* wait for underrun and check that we got buffer1 and buffer2 only */ UNDERRUN_LOCK (); mysinkpad = setup_sink_pad (queue, &sinktemplate); + unblock_src (); UNDERRUN_WAIT (); UNDERRUN_UNLOCK (); fail_unless (overrun_count == 1); - fail_unless (underrun_count == 1); + fail_unless (underrun_count == 2); fail_unless (g_list_length (buffers) == 2); @@ -445,6 +504,7 @@ GST_START_TEST (test_time_level) { GstBuffer *buffer = NULL; GstClockTime time; + GstSegment segment; g_signal_connect (queue, "overrun", G_CALLBACK (queue_overrun_link_and_activate), NULL); @@ -453,9 +513,18 @@ GST_START_TEST (test_time_level) GST_DEBUG ("starting"); + block_src (); + + UNDERRUN_LOCK (); fail_unless (gst_element_set_state (queue, GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, "could not set to playing"); + UNDERRUN_WAIT (); + UNDERRUN_UNLOCK (); + + gst_segment_init (&segment, GST_FORMAT_BYTES); + gst_pad_push_event (mysrcpad, gst_event_new_stream_start ("test")); + gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)); /* push buffer without duration */ buffer = gst_buffer_new_and_alloc (4); @@ -545,9 +614,16 @@ GST_START_TEST (test_time_level_task_not_started) GST_DEBUG ("starting"); + block_src (); + + UNDERRUN_LOCK (); fail_unless (gst_element_set_state (queue, GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, "could not set to playing"); + UNDERRUN_WAIT (); + UNDERRUN_UNLOCK (); + + gst_pad_push_event (mysrcpad, gst_event_new_stream_start ("test")); gst_segment_init (&segment, GST_FORMAT_TIME); segment.start = 1 * GST_SECOND; @@ -569,6 +645,64 @@ GST_START_TEST (test_time_level_task_not_started) GST_DEBUG ("time now %" GST_TIME_FORMAT, GST_TIME_ARGS (time)); fail_if (time != 4 * GST_SECOND); + unblock_src (); + + GST_DEBUG ("stopping"); + fail_unless (gst_element_set_state (queue, + GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null"); +} + +GST_END_TEST; + +GST_START_TEST (test_sticky_not_linked) +{ + GstEvent *event; + GstSegment segment; + gboolean ret; + GstFlowReturn flow_ret; + + GST_DEBUG ("starting"); + + g_object_set (queue, "max-size-buffers", 1, NULL); + + UNDERRUN_LOCK (); + fail_unless (gst_element_set_state (queue, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + UNDERRUN_WAIT (); + UNDERRUN_UNLOCK (); + + gst_pad_push_event (mysrcpad, gst_event_new_stream_start ("test")); + + gst_segment_init (&segment, GST_FORMAT_TIME); + segment.start = 1 * GST_SECOND; + segment.stop = 5 * GST_SECOND; + segment.time = 0; + segment.position = 1 * GST_SECOND; + + event = gst_event_new_segment (&segment); + ret = gst_pad_push_event (mysrcpad, event); + fail_unless (ret == TRUE); + + /* the first few buffers can return OK as they are queued and gst_queue_loop + * is woken up, tries to push and sets ->srcresult to NOT_LINKED + */ + flow_ret = GST_FLOW_OK; + while (flow_ret != GST_FLOW_NOT_LINKED) + flow_ret = gst_pad_push (mysrcpad, gst_buffer_new ()); + + /* send a new sticky event so that it will be pushed on the next gst_pad_push + */ + event = gst_event_new_segment (&segment); + ret = gst_pad_push_event (mysrcpad, event); + fail_unless (ret == TRUE); + + /* make sure that gst_queue_sink_event doesn't return FALSE if the queue is + * unlinked, as that would make gst_pad_push return ERROR + */ + flow_ret = gst_pad_push (mysrcpad, gst_buffer_new ()); + fail_unless_equals_int (flow_ret, GST_FLOW_NOT_LINKED); + GST_DEBUG ("stopping"); fail_unless (gst_element_set_state (queue, GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null"); @@ -702,6 +836,317 @@ GST_START_TEST (test_newsegment) GST_END_TEST; #endif +static gpointer +thread_func (gpointer data) +{ + int i = 0; + for (i = 0; i < 100; i++) { + GstCaps *caps; + GstQuery *query; + gboolean ok; + caps = gst_caps_new_any (); + query = gst_query_new_allocation (caps, FALSE); + ok = gst_pad_peer_query (mysrcpad, query); + gst_query_unref (query); + gst_caps_unref (caps); + query = NULL; + caps = NULL; + + if (!ok) + break; + } + + return NULL; +} + +static gboolean query_func (GstPad * pad, GstObject * parent, GstQuery * query); + +static gboolean +query_func (GstPad * pad, GstObject * parent, GstQuery * query) +{ + + g_usleep (1000); + return TRUE; +} + +GST_START_TEST (test_queries_while_flushing) +{ + GstEvent *event; + GThread *thread; + int i; + + mysinkpad = gst_check_setup_sink_pad (queue, &sinktemplate); + gst_pad_set_query_function (mysinkpad, query_func); + gst_pad_set_active (mysinkpad, TRUE); + + /* hard to reproduce, so just run it a few times in a row */ + for (i = 0; i < 500; ++i) { + GST_DEBUG ("starting"); + UNDERRUN_LOCK (); + fail_unless (gst_element_set_state (queue, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + UNDERRUN_WAIT (); + UNDERRUN_UNLOCK (); + + thread = g_thread_new ("deactivating thread", thread_func, NULL); + g_usleep (1000); + + event = gst_event_new_flush_start (); + gst_pad_push_event (mysrcpad, event); + + g_thread_join (thread); + + GST_DEBUG ("stopping"); + fail_unless (gst_element_set_state (queue, + GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, + "could not set to null"); + } +} + +GST_END_TEST; + +static gpointer +push_event_thread_func (gpointer data) +{ + GstEvent *event; + + event = GST_EVENT (data); + + GST_DEBUG ("pushing event %p on pad %p", event, mysrcpad); + gst_pad_push_event (mysrcpad, event); + + return NULL; +} + +GST_START_TEST (test_state_change_when_flushing) +{ + GstEvent *event; + GThread *thread; + + mysinkpad = gst_check_setup_sink_pad (queue, &sinktemplate); + gst_pad_set_active (mysinkpad, TRUE); + + fail_unless (gst_element_set_state (queue, GST_STATE_PAUSED) == + GST_STATE_CHANGE_SUCCESS); + + event = gst_event_new_flush_start (); + gst_pad_push_event (mysrcpad, event); + + event = gst_event_new_flush_stop (TRUE); + thread = g_thread_new ("send event", push_event_thread_func, event); + + GST_DEBUG ("changing state to READY"); + fail_unless (gst_element_set_state (queue, GST_STATE_READY) == + GST_STATE_CHANGE_SUCCESS); + GST_DEBUG ("state changed"); + + g_thread_join (thread); + + fail_unless (gst_element_set_state (queue, GST_STATE_NULL) == + GST_STATE_CHANGE_SUCCESS); +} + +GST_END_TEST; + +GST_START_TEST (test_time_level_buffer_list) +{ + GstBuffer *buffer = NULL; + GstBufferList *buffer_list = NULL; + GstClockTime time; + guint buffers; + GstSegment segment; + + g_signal_connect (queue, "overrun", + G_CALLBACK (queue_overrun_link_and_activate), NULL); + g_object_set (G_OBJECT (queue), "max-size-buffers", 11, NULL); + g_object_set (G_OBJECT (queue), "max-size-time", + G_GUINT64_CONSTANT (7000) * GST_MSECOND, NULL); + + GST_DEBUG ("starting"); + + block_src (); + + UNDERRUN_LOCK (); + fail_unless (gst_element_set_state (queue, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + UNDERRUN_WAIT (); + UNDERRUN_UNLOCK (); + + gst_segment_init (&segment, GST_FORMAT_BYTES); + gst_pad_push_event (mysrcpad, gst_event_new_stream_start ("test")); + gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)); + + /* push buffer without duration */ + buffer = gst_buffer_new_and_alloc (4); + GST_BUFFER_TIMESTAMP (buffer) = 1000 * GST_MSECOND; + /* pushing gives away my reference */ + gst_pad_push (mysrcpad, buffer); + + /* level should be 1 seconds because buffer has no duration and starts at 1 + * SECOND (sparse stream). */ + g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL); + fail_unless_equals_uint64 (time, 1000 * GST_MSECOND); + g_object_get (G_OBJECT (queue), "current-level-buffers", &buffers, NULL); + fail_unless_equals_int (buffers, 1); + + /* second push should set the level to 2 second */ + buffer_list = gst_buffer_list_new (); + buffer = gst_buffer_new_and_alloc (4); + GST_BUFFER_TIMESTAMP (buffer) = 1500 * GST_MSECOND; + gst_buffer_list_add (buffer_list, buffer); + buffer = gst_buffer_new_and_alloc (4); + GST_BUFFER_TIMESTAMP (buffer) = 2000 * GST_MSECOND; + gst_buffer_list_add (buffer_list, buffer); + gst_pad_push_list (mysrcpad, buffer_list); + + g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL); + fail_unless_equals_uint64 (time, 2000 * GST_MSECOND); + g_object_get (G_OBJECT (queue), "current-level-buffers", &buffers, NULL); + fail_unless_equals_int (buffers, 3); + + /* third push should set the level to 4 seconds, the 1 second diff with the + * previous buffer (without duration) and the 1 second duration of this + * buffer. */ + buffer_list = gst_buffer_list_new (); + buffer = gst_buffer_new_and_alloc (4); + GST_BUFFER_TIMESTAMP (buffer) = 3000 * GST_MSECOND; + GST_BUFFER_DURATION (buffer) = 500 * GST_MSECOND; + ASSERT_BUFFER_REFCOUNT (buffer, "buffer", 1); + gst_buffer_list_add (buffer_list, buffer); + buffer = gst_buffer_new_and_alloc (4); + GST_BUFFER_TIMESTAMP (buffer) = 3500 * GST_MSECOND; + GST_BUFFER_DURATION (buffer) = 500 * GST_MSECOND; + ASSERT_BUFFER_REFCOUNT (buffer, "buffer", 1); + gst_buffer_list_add (buffer_list, buffer); + gst_pad_push_list (mysrcpad, buffer_list); + + g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL); + fail_unless_equals_uint64 (time, 4000 * GST_MSECOND); + g_object_get (G_OBJECT (queue), "current-level-buffers", &buffers, NULL); + fail_unless_equals_int (buffers, 5); + + /* fourth push should set the level to 6 seconds, the 2 second diff with the + * previous buffer, same duration. */ + buffer_list = gst_buffer_list_new (); + buffer = gst_buffer_new_and_alloc (4); + GST_BUFFER_TIMESTAMP (buffer) = 5000 * GST_MSECOND; + GST_BUFFER_DURATION (buffer) = 1000 * GST_MSECOND; + ASSERT_BUFFER_REFCOUNT (buffer, "buffer", 1); + gst_buffer_list_add (buffer_list, buffer); + gst_pad_push_list (mysrcpad, buffer_list); + + g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL); + fail_unless_equals_uint64 (time, 6000 * GST_MSECOND); + g_object_get (G_OBJECT (queue), "current-level-buffers", &buffers, NULL); + fail_unless_equals_int (buffers, 6); + + /* fifth push should not adjust the level, the timestamp and duration are the + * same, meaning the previous buffer did not really have a duration. */ + buffer_list = gst_buffer_list_new (); + buffer = gst_buffer_new_and_alloc (4); + GST_BUFFER_TIMESTAMP (buffer) = 5000 * GST_MSECOND; + GST_BUFFER_DURATION (buffer) = 250 * GST_MSECOND; + gst_buffer_list_add (buffer_list, buffer); + buffer = gst_buffer_new_and_alloc (4); + GST_BUFFER_TIMESTAMP (buffer) = 5250 * GST_MSECOND; + GST_BUFFER_DURATION (buffer) = 250 * GST_MSECOND; + gst_buffer_list_add (buffer_list, buffer); + buffer = gst_buffer_new_and_alloc (4); + GST_BUFFER_TIMESTAMP (buffer) = 5500 * GST_MSECOND; + GST_BUFFER_DURATION (buffer) = 250 * GST_MSECOND; + gst_buffer_list_add (buffer_list, buffer); + buffer = gst_buffer_new_and_alloc (4); + GST_BUFFER_TIMESTAMP (buffer) = 5750 * GST_MSECOND; + GST_BUFFER_DURATION (buffer) = 250 * GST_MSECOND; + gst_buffer_list_add (buffer_list, buffer); + gst_pad_push_list (mysrcpad, buffer_list); + + g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL); + fail_unless_equals_uint64 (time, 6000 * GST_MSECOND); + g_object_get (G_OBJECT (queue), "current-level-buffers", &buffers, NULL); + fail_unless_equals_int (buffers, 10); + + /* sixth push should adjust the level with 1 second, we now know the + * previous buffer actually had a duration of 2 SECONDS */ + buffer = gst_buffer_new_and_alloc (4); + GST_BUFFER_TIMESTAMP (buffer) = 7000 * GST_MSECOND; + gst_pad_push (mysrcpad, buffer); + + g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL); + fail_unless_equals_uint64 (time, 7000 * GST_MSECOND); + g_object_get (G_OBJECT (queue), "current-level-buffers", &buffers, NULL); + fail_unless_equals_int (buffers, 11); + + /* eighth push should cause overrun */ + fail_unless (overrun_count == 0); + buffer_list = gst_buffer_list_new (); + buffer = gst_buffer_new_and_alloc (4); + GST_BUFFER_TIMESTAMP (buffer) = 8000 * GST_MSECOND; + /* the next call to gst_pad_push will emit the overrun signal. The signal + * handler queue_overrun_link_and_activate() (above) increases overrun_count, + * activates and links mysinkpad. The queue task then dequeues a buffer and + * gst_pad_push() will return. */ + gst_buffer_list_add (buffer_list, buffer); + gst_pad_push_list (mysrcpad, buffer_list); + + fail_unless (overrun_count == 1); + + GST_DEBUG ("stopping"); + fail_unless (gst_element_set_state (queue, + GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null"); +} + +GST_END_TEST; + +GST_START_TEST (test_initial_events_nodelay) +{ + GstSegment segment; + GstEvent *event; + GstCaps *caps; + gboolean ret; + + mysinkpad = gst_check_setup_sink_pad (queue, &sinktemplate); + gst_pad_set_event_function (mysinkpad, event_func); + gst_pad_set_active (mysinkpad, TRUE); + + GST_DEBUG ("starting"); + + fail_unless (gst_element_set_state (queue, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + gst_pad_push_event (mysrcpad, gst_event_new_stream_start ("test")); + + caps = gst_caps_new_empty_simple ("foo/x-bar"); + ret = gst_pad_push_event (mysrcpad, gst_event_new_caps (caps)); + gst_caps_unref (caps); + fail_unless (ret == TRUE); + + gst_segment_init (&segment, GST_FORMAT_TIME); + ret = gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)); + fail_unless (ret == TRUE); + + g_mutex_lock (&events_lock); + while (events_count < 3) { + g_cond_wait (&events_cond, &events_lock); + } + g_mutex_unlock (&events_lock); + + fail_unless_equals_int (g_list_length (events), 3); + event = g_list_nth_data (events, 0); + fail_unless_equals_int (GST_EVENT_TYPE (event), GST_EVENT_STREAM_START); + event = g_list_nth_data (events, 1); + fail_unless_equals_int (GST_EVENT_TYPE (event), GST_EVENT_CAPS); + event = g_list_nth_data (events, 2); + fail_unless_equals_int (GST_EVENT_TYPE (event), GST_EVENT_SEGMENT); + + gst_element_set_state (queue, GST_STATE_NULL); +} + +GST_END_TEST; + static Suite * queue_suite (void) { @@ -716,9 +1161,14 @@ queue_suite (void) tcase_add_test (tc_chain, test_leaky_downstream); tcase_add_test (tc_chain, test_time_level); tcase_add_test (tc_chain, test_time_level_task_not_started); + tcase_add_test (tc_chain, test_queries_while_flushing); + tcase_add_test (tc_chain, test_state_change_when_flushing); #if 0 tcase_add_test (tc_chain, test_newsegment); #endif + tcase_add_test (tc_chain, test_sticky_not_linked); + tcase_add_test (tc_chain, test_time_level_buffer_list); + tcase_add_test (tc_chain, test_initial_events_nodelay); return s; }