mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-09-08 13:18:52 +00:00
Improve GstSegment, rename some fields. The idea is to have the GstSegment structure represent the timing structure of the buffers as they are generated by the source or demuxer element. gst_segment_set_seek() -> gst_segment_do_seek() Rename the NEWSEGMENT event to SEGMENT. Make parsing of the SEGMENT event into a GstSegment structure. Pass a GstSegment structure when making a new SEGMENT event. This allows us to pass the timing info directly to the next element. No accumulation is needed in the receiving element, all the info is inside the element. Remove gst_segment_set_newsegment(): This function as used to accumulate segments received from upstream, which is now not needed anymore because the segment event contains the complete timing information.
724 lines
21 KiB
C
724 lines
21 KiB
C
/* GStreamer
|
|
*
|
|
* unit test for queue
|
|
*
|
|
* Copyright (C) <2006> Stefan Kost <ensonic@users.sf.net>
|
|
*
|
|
* 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 <unistd.h>
|
|
|
|
#include <gst/check/gstcheck.h>
|
|
|
|
#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;
|
|
|
|
/* For ease of programming we use globals to keep refs for our floating
|
|
* src and sink pads we create; otherwise we always have to do get_pad,
|
|
* get_peer, and then remove references in every test function */
|
|
static GstPad *mysrcpad;
|
|
static GstPad *mysinkpad;
|
|
|
|
static gint overrun_count;
|
|
|
|
static GMutex *underrun_mutex;
|
|
static GCond *underrun_cond;
|
|
static gint underrun_count;
|
|
|
|
static GList *events;
|
|
|
|
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
|
|
GST_PAD_SINK,
|
|
GST_PAD_ALWAYS,
|
|
GST_STATIC_CAPS_ANY);
|
|
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
|
|
GST_PAD_SRC,
|
|
GST_PAD_ALWAYS,
|
|
GST_STATIC_CAPS_ANY);
|
|
|
|
static void
|
|
queue_overrun (GstElement * queue, gpointer user_data)
|
|
{
|
|
GST_DEBUG ("queue overrun");
|
|
overrun_count++;
|
|
}
|
|
|
|
static void
|
|
queue_underrun (GstElement * queue, gpointer user_data)
|
|
{
|
|
GST_DEBUG ("queue underrun");
|
|
UNDERRUN_LOCK ();
|
|
underrun_count++;
|
|
UNDERRUN_SIGNAL ();
|
|
UNDERRUN_UNLOCK ();
|
|
}
|
|
|
|
static gboolean
|
|
event_func (GstPad * pad, GstEvent * event)
|
|
{
|
|
GST_DEBUG ("%s event", gst_event_type_get_name (GST_EVENT_TYPE (event)));
|
|
events = g_list_append (events, event);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
drop_events (void)
|
|
{
|
|
while (events != NULL) {
|
|
gst_event_unref (GST_EVENT (events->data));
|
|
events = g_list_delete_link (events, events);
|
|
}
|
|
}
|
|
|
|
static void
|
|
setup (void)
|
|
{
|
|
GST_DEBUG ("setup_queue");
|
|
|
|
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);
|
|
gst_pad_set_active (mysrcpad, TRUE);
|
|
|
|
mysinkpad = NULL;
|
|
|
|
overrun_count = 0;
|
|
|
|
underrun_mutex = g_mutex_new ();
|
|
underrun_cond = g_cond_new ();
|
|
underrun_count = 0;
|
|
|
|
events = NULL;
|
|
}
|
|
|
|
static void
|
|
cleanup (void)
|
|
{
|
|
GST_DEBUG ("cleanup_queue");
|
|
|
|
gst_check_drop_buffers ();
|
|
|
|
drop_events ();
|
|
|
|
g_cond_free (underrun_cond);
|
|
underrun_cond = NULL;
|
|
g_mutex_free (underrun_mutex);
|
|
underrun_mutex = NULL;
|
|
|
|
if (mysinkpad != NULL) {
|
|
gst_pad_set_active (mysinkpad, FALSE);
|
|
gst_check_teardown_sink_pad (queue);
|
|
}
|
|
|
|
gst_pad_set_active (mysrcpad, FALSE);
|
|
gst_check_teardown_src_pad (queue);
|
|
|
|
gst_check_teardown_element (queue);
|
|
queue = NULL;
|
|
}
|
|
|
|
/* setup the sinkpad on a playing queue element. gst_check_setup_sink_pad()
|
|
* does not work in this case since it does not activate the pad before linking
|
|
* it. */
|
|
static GstPad *
|
|
setup_sink_pad (GstElement * element, GstStaticPadTemplate * tmpl)
|
|
{
|
|
GstPad *srcpad;
|
|
GstPad *sinkpad;
|
|
|
|
sinkpad = gst_pad_new_from_static_template (tmpl, "sink");
|
|
fail_if (sinkpad == NULL);
|
|
srcpad = gst_element_get_static_pad (element, "src");
|
|
fail_if (srcpad == NULL);
|
|
gst_pad_set_chain_function (sinkpad, gst_check_chain_func);
|
|
gst_pad_set_event_function (sinkpad, event_func);
|
|
gst_pad_set_active (sinkpad, TRUE);
|
|
fail_unless (gst_pad_link (srcpad, sinkpad) == GST_PAD_LINK_OK);
|
|
gst_object_unref (srcpad);
|
|
|
|
return sinkpad;
|
|
}
|
|
|
|
/* set queue size to 2 buffers
|
|
* pull 1 buffer
|
|
* check over/underuns
|
|
*/
|
|
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);
|
|
gst_pad_set_active (mysinkpad, TRUE);
|
|
|
|
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 ();
|
|
|
|
fail_unless (overrun_count == 0);
|
|
fail_unless (underrun_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;
|
|
|
|
static void
|
|
queue_overrun_link_and_activate (GstElement * queue, gpointer user_data)
|
|
{
|
|
GST_DEBUG ("queue overrun");
|
|
overrun_count++;
|
|
|
|
/* link the src pad of the queue to make it dequeue buffers */
|
|
mysinkpad = setup_sink_pad (queue, &sinktemplate);
|
|
}
|
|
|
|
/* set queue size to 2 buffers
|
|
* push 2 buffers
|
|
* check over/underuns
|
|
* push 1 more buffer
|
|
* check over/underuns again
|
|
*/
|
|
GST_START_TEST (test_non_leaky_overrun)
|
|
{
|
|
GstBuffer *buffer1;
|
|
GstBuffer *buffer2;
|
|
GstBuffer *buffer3;
|
|
GstBuffer *buffer;
|
|
|
|
g_signal_connect (queue, "overrun",
|
|
G_CALLBACK (queue_overrun_link_and_activate), NULL);
|
|
g_object_set (G_OBJECT (queue), "max-size-buffers", 2, NULL);
|
|
|
|
GST_DEBUG ("starting");
|
|
|
|
fail_unless (gst_element_set_state (queue,
|
|
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
|
|
"could not set to playing");
|
|
fail_unless (overrun_count == 0);
|
|
fail_unless (underrun_count == 0);
|
|
|
|
buffer1 = gst_buffer_new_and_alloc (4);
|
|
/* pushing gives away my reference */
|
|
gst_pad_push (mysrcpad, buffer1);
|
|
|
|
GST_DEBUG ("added 1st");
|
|
fail_unless (overrun_count == 0);
|
|
fail_unless (underrun_count == 0);
|
|
|
|
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);
|
|
|
|
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
|
|
* gst_pad_push() will return. */
|
|
gst_pad_push (mysrcpad, buffer3);
|
|
|
|
GST_DEBUG ("added 3rd");
|
|
fail_unless (overrun_count == 1);
|
|
fail_unless (underrun_count == 0);
|
|
|
|
/* now let the queue push all buffers */
|
|
while (g_list_length (buffers) < 3) {
|
|
g_cond_wait (check_cond, 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) {
|
|
UNDERRUN_WAIT ();
|
|
}
|
|
UNDERRUN_UNLOCK ();
|
|
fail_unless (underrun_count == 1);
|
|
|
|
buffer = g_list_nth (buffers, 0)->data;
|
|
fail_unless (buffer == buffer1);
|
|
|
|
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");
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
/* set queue size to 2 buffers
|
|
* push 2 buffers
|
|
* check over/underuns
|
|
* push 1 more buffer
|
|
* check over/underuns again
|
|
* check which buffer was leaked
|
|
*/
|
|
GST_START_TEST (test_leaky_upstream)
|
|
{
|
|
GstBuffer *buffer1;
|
|
GstBuffer *buffer2;
|
|
GstBuffer *buffer3;
|
|
GstBuffer *buffer;
|
|
|
|
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");
|
|
|
|
fail_unless (gst_element_set_state (queue,
|
|
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
|
|
"could not set to playing");
|
|
fail_unless (overrun_count == 0);
|
|
fail_unless (underrun_count == 0);
|
|
|
|
buffer1 = gst_buffer_new_and_alloc (4);
|
|
/* pushing gives away my reference */
|
|
gst_pad_push (mysrcpad, buffer1);
|
|
|
|
GST_DEBUG ("added 1st");
|
|
fail_unless (overrun_count == 0);
|
|
fail_unless (underrun_count == 0);
|
|
|
|
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);
|
|
|
|
buffer3 = gst_buffer_new_and_alloc (4);
|
|
/* buffer3 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");
|
|
/* it still triggers overrun when leaking */
|
|
fail_unless (overrun_count == 1);
|
|
fail_unless (underrun_count == 0);
|
|
|
|
/* wait for underrun and check that we got buffer1 and buffer2 only */
|
|
UNDERRUN_LOCK ();
|
|
mysinkpad = setup_sink_pad (queue, &sinktemplate);
|
|
UNDERRUN_WAIT ();
|
|
UNDERRUN_UNLOCK ();
|
|
|
|
fail_unless (overrun_count == 1);
|
|
fail_unless (underrun_count == 1);
|
|
|
|
fail_unless (g_list_length (buffers) == 2);
|
|
|
|
buffer = g_list_nth (buffers, 0)->data;
|
|
fail_unless (buffer == buffer1);
|
|
|
|
buffer = g_list_nth (buffers, 1)->data;
|
|
fail_unless (buffer == buffer2);
|
|
|
|
ASSERT_BUFFER_REFCOUNT (buffer3, "buffer", 1);
|
|
gst_buffer_unref (buffer3);
|
|
|
|
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;
|
|
|
|
/* set queue size to 2 buffers
|
|
* push 2 buffers
|
|
* check over/underuns
|
|
* push 1 more buffer
|
|
* check over/underuns again
|
|
* check which buffer was leaked
|
|
*/
|
|
GST_START_TEST (test_leaky_downstream)
|
|
{
|
|
GstBuffer *buffer1;
|
|
GstBuffer *buffer2;
|
|
GstBuffer *buffer3;
|
|
GstBuffer *buffer;
|
|
|
|
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");
|
|
|
|
fail_unless (gst_element_set_state (queue,
|
|
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
|
|
"could not set to playing");
|
|
fail_unless (overrun_count == 0);
|
|
fail_unless (underrun_count == 0);
|
|
|
|
buffer1 = gst_buffer_new_and_alloc (4);
|
|
/* 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);
|
|
|
|
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);
|
|
|
|
buffer3 = gst_buffer_new_and_alloc (4);
|
|
gst_pad_push (mysrcpad, buffer3);
|
|
|
|
GST_DEBUG ("added 3rd");
|
|
/* it still triggers overrun when leaking */
|
|
fail_unless (overrun_count == 1);
|
|
fail_unless (underrun_count == 0);
|
|
|
|
/* wait for underrun and check that we got buffer1 and buffer2 only */
|
|
UNDERRUN_LOCK ();
|
|
mysinkpad = setup_sink_pad (queue, &sinktemplate);
|
|
UNDERRUN_WAIT ();
|
|
UNDERRUN_UNLOCK ();
|
|
|
|
fail_unless (overrun_count == 1);
|
|
fail_unless (underrun_count == 1);
|
|
|
|
fail_unless (g_list_length (buffers) == 2);
|
|
|
|
ASSERT_BUFFER_REFCOUNT (buffer1, "buffer", 1);
|
|
gst_buffer_unref (buffer1);
|
|
|
|
buffer = g_list_nth (buffers, 0)->data;
|
|
fail_unless (buffer == buffer2);
|
|
|
|
buffer = g_list_nth (buffers, 1)->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");
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
/* set queue size to 6 buffers and 7 seconds
|
|
* push 7 buffers with and without duration
|
|
* check current-level-time
|
|
*/
|
|
GST_START_TEST (test_time_level)
|
|
{
|
|
GstBuffer *buffer = NULL;
|
|
GstClockTime time;
|
|
|
|
g_signal_connect (queue, "overrun",
|
|
G_CALLBACK (queue_overrun_link_and_activate), NULL);
|
|
g_object_set (G_OBJECT (queue), "max-size-buffers", 6, NULL);
|
|
g_object_set (G_OBJECT (queue), "max-size-time", 7 * GST_SECOND, NULL);
|
|
|
|
GST_DEBUG ("starting");
|
|
|
|
fail_unless (gst_element_set_state (queue,
|
|
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
|
|
"could not set to playing");
|
|
|
|
/* push buffer without duration */
|
|
buffer = gst_buffer_new_and_alloc (4);
|
|
GST_BUFFER_TIMESTAMP (buffer) = GST_SECOND;
|
|
/* 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_if (time != GST_SECOND);
|
|
|
|
/* second push should set the level to 2 second */
|
|
buffer = gst_buffer_new_and_alloc (4);
|
|
GST_BUFFER_TIMESTAMP (buffer) = 2 * GST_SECOND;
|
|
gst_pad_push (mysrcpad, buffer);
|
|
|
|
g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL);
|
|
fail_if (time != 2 * GST_SECOND);
|
|
|
|
/* 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 = gst_buffer_new_and_alloc (4);
|
|
GST_BUFFER_TIMESTAMP (buffer) = 3 * GST_SECOND;
|
|
GST_BUFFER_DURATION (buffer) = 1 * GST_SECOND;
|
|
ASSERT_BUFFER_REFCOUNT (buffer, "buffer", 1);
|
|
gst_pad_push (mysrcpad, buffer);
|
|
|
|
g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL);
|
|
fail_if (time != 4 * GST_SECOND);
|
|
|
|
/* fourth push should set the level to 6 seconds, the 2 second diff with the
|
|
* previous buffer, same duration. */
|
|
buffer = gst_buffer_new_and_alloc (4);
|
|
GST_BUFFER_TIMESTAMP (buffer) = 5 * GST_SECOND;
|
|
GST_BUFFER_DURATION (buffer) = 1 * GST_SECOND;
|
|
ASSERT_BUFFER_REFCOUNT (buffer, "buffer", 1);
|
|
gst_pad_push (mysrcpad, buffer);
|
|
|
|
g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL);
|
|
fail_if (time != 6 * GST_SECOND);
|
|
|
|
/* 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 = gst_buffer_new_and_alloc (4);
|
|
GST_BUFFER_TIMESTAMP (buffer) = 5 * GST_SECOND;
|
|
GST_BUFFER_DURATION (buffer) = 1 * GST_SECOND;
|
|
gst_pad_push (mysrcpad, buffer);
|
|
|
|
g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL);
|
|
fail_if (time != 6 * GST_SECOND);
|
|
|
|
/* 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) = 7 * GST_SECOND;
|
|
gst_pad_push (mysrcpad, buffer);
|
|
|
|
g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL);
|
|
fail_if (time != 7 * GST_SECOND);
|
|
|
|
/* eighth push should cause overrun */
|
|
fail_unless (overrun_count == 0);
|
|
buffer = gst_buffer_new_and_alloc (4);
|
|
GST_BUFFER_TIMESTAMP (buffer) = 8 * GST_SECOND;
|
|
/* 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_pad_push (mysrcpad, buffer);
|
|
|
|
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_time_level_task_not_started)
|
|
{
|
|
GstEvent *event;
|
|
GstClockTime time;
|
|
GstSegment segment;
|
|
|
|
GST_DEBUG ("starting");
|
|
|
|
fail_unless (gst_element_set_state (queue,
|
|
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
|
|
"could not set to playing");
|
|
|
|
gst_segment_init (&segment, GST_FORMAT_TIME);
|
|
segment.start = 1 * GST_SECOND;
|
|
segment.stop = 5 * GST_SECOND;
|
|
segment.time = 0;
|
|
|
|
event = gst_event_new_segment (&segment);
|
|
gst_pad_push_event (mysrcpad, event);
|
|
|
|
g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL);
|
|
fail_if (time != 0 * GST_SECOND);
|
|
|
|
segment.base = 4 * GST_SECOND;
|
|
event = gst_event_new_segment (&segment);
|
|
gst_pad_push_event (mysrcpad, event);
|
|
|
|
g_object_get (G_OBJECT (queue), "current-level-time", &time, NULL);
|
|
fail_if (time != 4 * GST_SECOND);
|
|
|
|
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;
|
|
|
|
#if 0
|
|
static gboolean
|
|
event_equals_newsegment (GstEvent * event, gboolean update, gdouble rate,
|
|
GstFormat format, gint64 start, gint64 stop, gint64 position)
|
|
{
|
|
gboolean ns_update;
|
|
gdouble ns_rate, ns_arate;
|
|
GstFormat ns_format;
|
|
gint64 ns_start;
|
|
gint64 ns_stop;
|
|
gint64 ns_position;
|
|
|
|
if (GST_EVENT_TYPE (event) != GST_EVENT_SEGMENT) {
|
|
return FALSE;
|
|
}
|
|
|
|
gst_event_parse_new_segment (event, &ns_update, &ns_rate, &ns_arate,
|
|
&ns_format, &ns_start, &ns_stop, &ns_position);
|
|
|
|
GST_DEBUG ("update %d, rate %lf, format %s, start %" GST_TIME_FORMAT
|
|
", stop %" GST_TIME_FORMAT ", position %" GST_TIME_FORMAT, ns_update,
|
|
ns_rate, gst_format_get_name (ns_format), GST_TIME_ARGS (ns_start),
|
|
GST_TIME_ARGS (ns_stop), GST_TIME_ARGS (ns_position));
|
|
|
|
return (ns_update == update && ns_rate == rate && ns_format == format &&
|
|
ns_start == start && ns_stop == stop && ns_position == position);
|
|
}
|
|
|
|
GST_START_TEST (test_newsegment)
|
|
{
|
|
GstEvent *event;
|
|
GstBuffer *buffer1;
|
|
GstBuffer *buffer2;
|
|
GstBuffer *buffer;
|
|
|
|
g_signal_connect (queue, "overrun", G_CALLBACK (queue_overrun), NULL);
|
|
g_object_set (G_OBJECT (queue), "max-size-buffers", 1, "max-size-time",
|
|
(guint64) 0, "leaky", 2, NULL);
|
|
|
|
GST_DEBUG ("starting");
|
|
|
|
fail_unless (gst_element_set_state (queue,
|
|
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
|
|
"could not set to playing");
|
|
fail_unless (overrun_count == 0);
|
|
fail_unless (underrun_count == 0);
|
|
|
|
event = gst_event_new_new_segment (FALSE, 2.0, 1.0, GST_FORMAT_TIME, 0,
|
|
2 * GST_SECOND, 0);
|
|
gst_pad_push_event (mysrcpad, event);
|
|
|
|
GST_DEBUG ("added 1st newsegment");
|
|
fail_unless (overrun_count == 0);
|
|
fail_unless (underrun_count == 0);
|
|
|
|
event = gst_event_new_new_segment (FALSE, 1.0, 1.0, GST_FORMAT_TIME, 0,
|
|
3 * GST_SECOND, 0);
|
|
gst_pad_push_event (mysrcpad, event);
|
|
|
|
GST_DEBUG ("added 2nd newsegment");
|
|
fail_unless (overrun_count == 0);
|
|
fail_unless (underrun_count == 0);
|
|
|
|
event = gst_event_new_new_segment (FALSE, 1.0, 1.0, GST_FORMAT_TIME,
|
|
4 * GST_SECOND, 5 * GST_SECOND, 4 * GST_SECOND);
|
|
gst_pad_push_event (mysrcpad, event);
|
|
|
|
GST_DEBUG ("added 3rd newsegment");
|
|
fail_unless (overrun_count == 0);
|
|
fail_unless (underrun_count == 0);
|
|
|
|
buffer1 = gst_buffer_new_and_alloc (4);
|
|
/* 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 buffer");
|
|
fail_unless (overrun_count == 0);
|
|
fail_unless (underrun_count == 0);
|
|
|
|
buffer2 = gst_buffer_new_and_alloc (4);
|
|
/* next push will cause overrun and leak all newsegment events and buffer1 */
|
|
gst_pad_push (mysrcpad, buffer2);
|
|
|
|
GST_DEBUG ("added 2nd buffer");
|
|
/* it still triggers overrun when leaking */
|
|
fail_unless (overrun_count == 1);
|
|
fail_unless (underrun_count == 0);
|
|
|
|
/* wait for underrun and check that we got one accumulated newsegment event,
|
|
* one real newsegment event and buffer2 only */
|
|
UNDERRUN_LOCK ();
|
|
mysinkpad = setup_sink_pad (queue, &sinktemplate);
|
|
UNDERRUN_WAIT ();
|
|
UNDERRUN_UNLOCK ();
|
|
|
|
fail_unless (overrun_count == 1);
|
|
fail_unless (underrun_count == 1);
|
|
|
|
fail_unless (g_list_length (events) == 2);
|
|
|
|
event = g_list_nth (events, 0)->data;
|
|
fail_unless (event_equals_newsegment (event, FALSE, 1.0, GST_FORMAT_TIME, 0,
|
|
4 * GST_SECOND, 0));
|
|
|
|
event = g_list_nth (events, 1)->data;
|
|
fail_unless (event_equals_newsegment (event, FALSE, 1.0, GST_FORMAT_TIME,
|
|
4 * GST_SECOND, 5 * GST_SECOND, 4 * GST_SECOND));
|
|
|
|
fail_unless (g_list_length (buffers) == 1);
|
|
|
|
ASSERT_BUFFER_REFCOUNT (buffer1, "buffer", 1);
|
|
gst_buffer_unref (buffer1);
|
|
|
|
buffer = g_list_nth (buffers, 0)->data;
|
|
fail_unless (buffer == buffer2);
|
|
|
|
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;
|
|
#endif
|
|
|
|
static Suite *
|
|
queue_suite (void)
|
|
{
|
|
Suite *s = suite_create ("queue");
|
|
TCase *tc_chain = tcase_create ("general");
|
|
|
|
suite_add_tcase (s, tc_chain);
|
|
tcase_add_checked_fixture (tc_chain, setup, cleanup);
|
|
tcase_add_test (tc_chain, test_non_leaky_underrun);
|
|
tcase_add_test (tc_chain, test_non_leaky_overrun);
|
|
tcase_add_test (tc_chain, test_leaky_upstream);
|
|
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);
|
|
#if 0
|
|
tcase_add_test (tc_chain, test_newsegment);
|
|
#endif
|
|
|
|
return s;
|
|
}
|
|
|
|
GST_CHECK_MAIN (queue);
|