mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-06 23:45:35 +00:00
2aa9ad9c62
This reverts commit 11e0f451eb
.
When pushing a sticky event out of a pad with a pad probe or pad offset,
those should not be applied to the event that is actually stored in the
event but only in the event sent downstream. The pad probe and pad
offsets are conceptually *after* the pad, added by external code and
should not affect any internal state of pads/elements.
Also storing the modified event has the side-effect that a re-sent event
would arrive with any previous modifications done by the same pad probe
again inside that pad probe, and it would have to check if its
modifications are already applied or not.
For sink pads and generally for events arriving in a pad, some further
changes are still needed and those are tracked in
https://bugzilla.gnome.org/show_bug.cgi?id=765049
In addition, the commit also had a refcounting problem with events,
causing already destroyed events to be stored inside pads.
3349 lines
97 KiB
C
3349 lines
97 KiB
C
/* GStreamer
|
|
* Copyright (C) <2005> Thomas Vander Stichele <thomas at apestaart dot org>
|
|
*
|
|
* gstpad.c: Unit test for GstPad
|
|
*
|
|
* 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., 51 Franklin St, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <gst/check/gstcheck.h>
|
|
|
|
static GstSegment dummy_segment;
|
|
|
|
GST_START_TEST (test_link)
|
|
{
|
|
GstPad *src, *sink;
|
|
GstPadTemplate *srct;
|
|
|
|
GstPadLinkReturn ret;
|
|
gchar *name;
|
|
|
|
src = gst_pad_new ("source", GST_PAD_SRC);
|
|
fail_if (src == NULL);
|
|
ASSERT_OBJECT_REFCOUNT (src, "source pad", 1);
|
|
|
|
name = gst_pad_get_name (src);
|
|
fail_unless (strcmp (name, "source") == 0);
|
|
ASSERT_OBJECT_REFCOUNT (src, "source pad", 1);
|
|
g_free (name);
|
|
|
|
sink = gst_pad_new ("sink", GST_PAD_SINK);
|
|
fail_if (sink == NULL);
|
|
|
|
/* linking without templates or caps should work */
|
|
ret = gst_pad_link (src, sink);
|
|
ASSERT_OBJECT_REFCOUNT (src, "source pad", 1);
|
|
ASSERT_OBJECT_REFCOUNT (sink, "sink pad", 1);
|
|
fail_unless (ret == GST_PAD_LINK_OK);
|
|
|
|
ASSERT_CRITICAL (gst_pad_get_pad_template (NULL));
|
|
|
|
srct = gst_pad_get_pad_template (src);
|
|
fail_unless (srct == NULL);
|
|
ASSERT_OBJECT_REFCOUNT (src, "source pad", 1);
|
|
|
|
/* clean up */
|
|
ASSERT_OBJECT_REFCOUNT (src, "source pad", 1);
|
|
gst_object_unref (src);
|
|
gst_object_unref (sink);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
/* threaded link/unlink */
|
|
/* use globals */
|
|
static GstPad *src, *sink;
|
|
|
|
static void
|
|
thread_link_unlink (gpointer data)
|
|
{
|
|
THREAD_START ();
|
|
|
|
while (THREAD_TEST_RUNNING ()) {
|
|
gst_pad_link (src, sink);
|
|
gst_pad_unlink (src, sink);
|
|
THREAD_SWITCH ();
|
|
}
|
|
}
|
|
|
|
GST_START_TEST (test_link_unlink_threaded)
|
|
{
|
|
GstCaps *caps;
|
|
int i;
|
|
|
|
src = gst_pad_new ("source", GST_PAD_SRC);
|
|
fail_if (src == NULL);
|
|
sink = gst_pad_new ("sink", GST_PAD_SINK);
|
|
fail_if (sink == NULL);
|
|
|
|
caps = gst_caps_from_string ("foo/bar");
|
|
gst_pad_set_active (src, TRUE);
|
|
gst_pad_set_caps (src, caps);
|
|
gst_pad_set_active (sink, TRUE);
|
|
gst_pad_set_caps (sink, caps);
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 3);
|
|
|
|
MAIN_START_THREADS (5, thread_link_unlink, NULL);
|
|
for (i = 0; i < 1000; ++i) {
|
|
gst_pad_is_linked (src);
|
|
gst_pad_is_linked (sink);
|
|
THREAD_SWITCH ();
|
|
}
|
|
MAIN_STOP_THREADS ();
|
|
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 3);
|
|
gst_caps_unref (caps);
|
|
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 2);
|
|
gst_object_unref (src);
|
|
gst_object_unref (sink);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_refcount)
|
|
{
|
|
GstPad *src, *sink;
|
|
GstCaps *caps;
|
|
GstPadLinkReturn plr;
|
|
|
|
sink = gst_pad_new ("sink", GST_PAD_SINK);
|
|
fail_if (sink == NULL);
|
|
|
|
src = gst_pad_new ("src", GST_PAD_SRC);
|
|
fail_if (src == NULL);
|
|
|
|
caps = gst_caps_from_string ("foo/bar");
|
|
/* one for me */
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
|
|
|
|
/* can't set caps on flushing sinkpad */
|
|
fail_if (gst_pad_set_caps (src, caps) == TRUE);
|
|
fail_if (gst_pad_set_caps (sink, caps) == TRUE);
|
|
/* one for me and one for each set_caps */
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
|
|
|
|
gst_pad_set_active (src, TRUE);
|
|
fail_unless (gst_pad_set_caps (src, caps) == TRUE);
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 2);
|
|
|
|
gst_pad_set_active (sink, TRUE);
|
|
fail_unless (gst_pad_set_caps (sink, caps) == TRUE);
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 3);
|
|
|
|
plr = gst_pad_link (src, sink);
|
|
fail_unless (GST_PAD_LINK_SUCCESSFUL (plr));
|
|
/* src caps added to pending caps on sink */
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 3);
|
|
|
|
gst_pad_unlink (src, sink);
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 3);
|
|
|
|
/* cleanup */
|
|
gst_object_unref (src);
|
|
gst_object_unref (sink);
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
|
|
|
|
gst_caps_unref (caps);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_get_allowed_caps)
|
|
{
|
|
GstPad *src, *sink;
|
|
GstCaps *caps, *gotcaps;
|
|
GstBuffer *buffer;
|
|
GstPadLinkReturn plr;
|
|
|
|
ASSERT_CRITICAL (gst_pad_get_allowed_caps (NULL));
|
|
|
|
buffer = gst_buffer_new ();
|
|
ASSERT_CRITICAL (gst_pad_get_allowed_caps ((GstPad *) buffer));
|
|
gst_buffer_unref (buffer);
|
|
|
|
src = gst_pad_new ("src", GST_PAD_SRC);
|
|
fail_if (src == NULL);
|
|
caps = gst_pad_get_allowed_caps (src);
|
|
fail_unless (caps == NULL);
|
|
|
|
caps = gst_caps_from_string ("foo/bar");
|
|
|
|
sink = gst_pad_new ("sink", GST_PAD_SINK);
|
|
gst_pad_set_active (src, TRUE);
|
|
/* source pad is active and will accept the caps event */
|
|
fail_unless (gst_pad_set_caps (src, caps) == TRUE);
|
|
/* sink pad is not active and will refuse the caps event */
|
|
fail_if (gst_pad_set_caps (sink, caps) == TRUE);
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 2);
|
|
|
|
gst_pad_set_active (sink, TRUE);
|
|
/* sink pad is now active and will accept the caps event */
|
|
fail_unless (gst_pad_set_caps (sink, caps) == TRUE);
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 3);
|
|
|
|
plr = gst_pad_link (src, sink);
|
|
fail_unless (GST_PAD_LINK_SUCCESSFUL (plr));
|
|
|
|
gotcaps = gst_pad_get_allowed_caps (src);
|
|
fail_if (gotcaps == NULL);
|
|
fail_unless (gst_caps_is_equal (gotcaps, caps));
|
|
|
|
ASSERT_CAPS_REFCOUNT (gotcaps, "gotcaps", 4);
|
|
gst_caps_unref (gotcaps);
|
|
|
|
gst_pad_unlink (src, sink);
|
|
|
|
/* cleanup */
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 3);
|
|
ASSERT_OBJECT_REFCOUNT (src, "src", 1);
|
|
ASSERT_OBJECT_REFCOUNT (sink, "sink", 1);
|
|
|
|
gst_object_unref (src);
|
|
gst_object_unref (sink);
|
|
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
|
|
gst_caps_unref (caps);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
static GstCaps *event_caps = NULL;
|
|
|
|
static gboolean
|
|
sticky_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
|
{
|
|
GstCaps *caps;
|
|
|
|
fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_CAPS
|
|
|| GST_EVENT_TYPE (event) == GST_EVENT_STREAM_START
|
|
|| GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT);
|
|
|
|
if (GST_EVENT_TYPE (event) != GST_EVENT_CAPS) {
|
|
gst_event_unref (event);
|
|
return TRUE;
|
|
}
|
|
|
|
/* Ensure we get here just once: */
|
|
fail_unless (event_caps == NULL);
|
|
|
|
/* The event must arrive before any buffer: */
|
|
fail_unless_equals_int (g_list_length (buffers), 0);
|
|
|
|
gst_event_parse_caps (event, &caps);
|
|
event_caps = gst_caps_ref (caps);
|
|
|
|
gst_event_unref (event);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* Tests whether caps get properly forwarded when pads
|
|
are initially unlinked */
|
|
GST_START_TEST (test_sticky_caps_unlinked)
|
|
{
|
|
GstCaps *caps;
|
|
GstPadTemplate *src_template, *sink_template;
|
|
GstPad *src, *sink;
|
|
GstEvent *event;
|
|
|
|
caps = gst_caps_from_string ("foo/bar, dummy=(int){1, 2}");
|
|
src_template = gst_pad_template_new ("src", GST_PAD_SRC,
|
|
GST_PAD_ALWAYS, caps);
|
|
sink_template = gst_pad_template_new ("sink", GST_PAD_SINK,
|
|
GST_PAD_ALWAYS, caps);
|
|
gst_caps_unref (caps);
|
|
|
|
src = gst_pad_new_from_template (src_template, "src");
|
|
fail_if (src == NULL);
|
|
sink = gst_pad_new_from_template (sink_template, "sink");
|
|
fail_if (sink == NULL);
|
|
gst_pad_set_event_function (sink, sticky_event);
|
|
gst_pad_set_chain_function (sink, gst_check_chain_func);
|
|
|
|
gst_object_unref (src_template);
|
|
gst_object_unref (sink_template);
|
|
|
|
gst_pad_set_active (src, TRUE);
|
|
|
|
fail_unless (gst_pad_push_event (src,
|
|
gst_event_new_stream_start ("test")) == TRUE);
|
|
|
|
caps = gst_caps_from_string ("foo/bar, dummy=(int)1");
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
|
|
|
|
event = gst_event_new_caps (caps);
|
|
fail_unless (gst_pad_push_event (src, event) == TRUE);
|
|
fail_unless (event_caps == NULL);
|
|
|
|
fail_unless (gst_pad_push_event (src,
|
|
gst_event_new_segment (&dummy_segment)) == TRUE);
|
|
|
|
/* Linking and activating will not forward the sticky event yet... */
|
|
fail_unless (GST_PAD_LINK_SUCCESSFUL (gst_pad_link (src, sink)));
|
|
gst_pad_set_active (sink, TRUE);
|
|
fail_unless (event_caps == NULL);
|
|
|
|
/* ...but the first buffer will: */
|
|
fail_unless (gst_pad_push (src, gst_buffer_new ()) == GST_FLOW_OK);
|
|
fail_unless (event_caps == caps);
|
|
fail_unless_equals_int (g_list_length (buffers), 1);
|
|
|
|
gst_check_drop_buffers ();
|
|
|
|
gst_caps_replace (&caps, NULL);
|
|
gst_caps_replace (&event_caps, NULL);
|
|
ASSERT_OBJECT_REFCOUNT (src, "src", 1);
|
|
ASSERT_OBJECT_REFCOUNT (sink, "sink", 1);
|
|
gst_object_unref (src);
|
|
gst_object_unref (sink);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
static gboolean
|
|
check_if_caps_is_accepted (GstPad * sink, const gchar * str)
|
|
{
|
|
GstCaps *caps;
|
|
gboolean ret;
|
|
|
|
caps = gst_caps_from_string (str);
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
|
|
ret = gst_pad_query_accept_caps (sink, caps);
|
|
gst_caps_unref (caps);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static gboolean
|
|
sink_query_caps (GstPad * pad, GstObject * object, GstQuery * q)
|
|
{
|
|
gboolean ret;
|
|
GstCaps *caps;
|
|
|
|
switch (GST_QUERY_TYPE (q)) {
|
|
case GST_QUERY_CAPS:
|
|
ret = TRUE;
|
|
caps =
|
|
gst_caps_from_string ("foo/bar, dummy=(int)1,"
|
|
" query-only-field=(int)1");
|
|
gst_query_set_caps_result (q, caps);
|
|
gst_caps_unref (caps);
|
|
default:
|
|
ret = gst_pad_query_default (pad, object, q);
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Tests whether acceptcaps default handler works properly
|
|
with all 4 possible flag combinations */
|
|
GST_START_TEST (test_default_accept_caps)
|
|
{
|
|
GstCaps *caps;
|
|
GstPadTemplate *sink_template;
|
|
GstPad *sink;
|
|
|
|
caps = gst_caps_from_string ("foo/bar, dummy=(int){1, 2}");
|
|
sink_template = gst_pad_template_new ("sink", GST_PAD_SINK,
|
|
GST_PAD_ALWAYS, caps);
|
|
gst_caps_unref (caps);
|
|
|
|
sink = gst_pad_new_from_template (sink_template, "sink");
|
|
fail_if (sink == NULL);
|
|
gst_pad_set_query_function (sink, sink_query_caps);
|
|
|
|
gst_object_unref (sink_template);
|
|
|
|
gst_pad_set_active (sink, TRUE);
|
|
|
|
/* 1. Check with caps query, subset check */
|
|
GST_PAD_UNSET_ACCEPT_INTERSECT (sink);
|
|
GST_PAD_UNSET_ACCEPT_TEMPLATE (sink);
|
|
fail_unless (check_if_caps_is_accepted (sink, "foo/bar, dummy=(int)1"));
|
|
fail_if (check_if_caps_is_accepted (sink, "foo/bar, dummy=(int)3"));
|
|
fail_unless (check_if_caps_is_accepted (sink,
|
|
"foo/bar, dummy=(int)1, query-only-field=(int)1"));
|
|
fail_if (check_if_caps_is_accepted (sink, "foo/bar, extra-field=(int)1"));
|
|
|
|
/* 2. Check with caps query, intersect check */
|
|
GST_PAD_SET_ACCEPT_INTERSECT (sink);
|
|
GST_PAD_UNSET_ACCEPT_TEMPLATE (sink);
|
|
fail_unless (check_if_caps_is_accepted (sink, "foo/bar, dummy=(int)1"));
|
|
fail_if (check_if_caps_is_accepted (sink, "foo/bar, dummy=(int)3"));
|
|
fail_unless (check_if_caps_is_accepted (sink,
|
|
"foo/bar, dummy=(int)1, query-only-field=(int)1"));
|
|
fail_unless (check_if_caps_is_accepted (sink, "foo/bar, extra-field=(int)1"));
|
|
|
|
/* 3. Check with template caps, subset check */
|
|
GST_PAD_UNSET_ACCEPT_INTERSECT (sink);
|
|
GST_PAD_SET_ACCEPT_TEMPLATE (sink);
|
|
fail_unless (check_if_caps_is_accepted (sink, "foo/bar, dummy=(int)1"));
|
|
fail_if (check_if_caps_is_accepted (sink, "foo/bar, dummy=(int)3"));
|
|
fail_unless (check_if_caps_is_accepted (sink,
|
|
"foo/bar, dummy=(int)1, query-only-field=(int)1"));
|
|
fail_if (check_if_caps_is_accepted (sink, "foo/bar, extra-field=(int)1"));
|
|
|
|
/* 3. Check with template caps, intersect check */
|
|
GST_PAD_SET_ACCEPT_INTERSECT (sink);
|
|
GST_PAD_SET_ACCEPT_TEMPLATE (sink);
|
|
fail_unless (check_if_caps_is_accepted (sink, "foo/bar, dummy=(int)1"));
|
|
fail_if (check_if_caps_is_accepted (sink, "foo/bar, dummy=(int)3"));
|
|
fail_unless (check_if_caps_is_accepted (sink,
|
|
"foo/bar, dummy=(int)1, query-only-field=(int)1"));
|
|
fail_unless (check_if_caps_is_accepted (sink, "foo/bar, extra-field=(int)1"));
|
|
|
|
ASSERT_OBJECT_REFCOUNT (sink, "sink", 1);
|
|
gst_object_unref (sink);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
/* Same as test_sticky_caps_unlinked except that the source pad
|
|
* has a template of ANY and we will attempt to push
|
|
* incompatible caps */
|
|
GST_START_TEST (test_sticky_caps_unlinked_incompatible)
|
|
{
|
|
GstCaps *caps, *failcaps;
|
|
GstPadTemplate *src_template, *sink_template;
|
|
GstPad *src, *sink;
|
|
GstEvent *event;
|
|
|
|
/* Source pad has ANY caps
|
|
* Sink pad has foobar caps
|
|
* We will push the pony express caps (which should fail)
|
|
*/
|
|
caps = gst_caps_new_any ();
|
|
src_template = gst_pad_template_new ("src", GST_PAD_SRC,
|
|
GST_PAD_ALWAYS, caps);
|
|
gst_caps_unref (caps);
|
|
caps = gst_caps_from_string ("foo/bar, dummy=(int){1, 2}");
|
|
sink_template = gst_pad_template_new ("sink", GST_PAD_SINK,
|
|
GST_PAD_ALWAYS, caps);
|
|
gst_caps_unref (caps);
|
|
|
|
src = gst_pad_new_from_template (src_template, "src");
|
|
fail_if (src == NULL);
|
|
sink = gst_pad_new_from_template (sink_template, "sink");
|
|
fail_if (sink == NULL);
|
|
gst_pad_set_event_function (sink, sticky_event);
|
|
gst_pad_set_chain_function (sink, gst_check_chain_func);
|
|
|
|
gst_object_unref (src_template);
|
|
gst_object_unref (sink_template);
|
|
|
|
gst_pad_set_active (src, TRUE);
|
|
|
|
fail_unless (gst_pad_push_event (src,
|
|
gst_event_new_stream_start ("test")) == TRUE);
|
|
|
|
failcaps = gst_caps_from_string ("pony/express, failure=(boolean)true");
|
|
ASSERT_CAPS_REFCOUNT (failcaps, "caps", 1);
|
|
|
|
event = gst_event_new_caps (failcaps);
|
|
gst_caps_unref (failcaps);
|
|
/* The pad isn't linked yet, and anything matches the source pad template
|
|
* (which is ANY) */
|
|
fail_unless (gst_pad_push_event (src, event) == TRUE);
|
|
fail_unless (event_caps == NULL);
|
|
|
|
fail_unless (gst_pad_push_event (src,
|
|
gst_event_new_segment (&dummy_segment)) == TRUE);
|
|
|
|
/* Linking and activating will not forward the sticky event yet... */
|
|
fail_unless (GST_PAD_LINK_SUCCESSFUL (gst_pad_link (src, sink)));
|
|
gst_pad_set_active (sink, TRUE);
|
|
fail_unless (event_caps == NULL);
|
|
|
|
/* ...but the first buffer will and should FAIL since the caps
|
|
* are not compatible */
|
|
fail_unless (gst_pad_push (src,
|
|
gst_buffer_new ()) == GST_FLOW_NOT_NEGOTIATED);
|
|
/* We shouldn't have received the caps event since it's incompatible */
|
|
fail_unless (event_caps == NULL);
|
|
/* We shouldn't have received any buffers since caps are incompatible */
|
|
fail_unless_equals_int (g_list_length (buffers), 0);
|
|
|
|
gst_check_drop_buffers ();
|
|
|
|
gst_caps_replace (&event_caps, NULL);
|
|
|
|
ASSERT_OBJECT_REFCOUNT (src, "src", 1);
|
|
ASSERT_OBJECT_REFCOUNT (sink, "sink", 1);
|
|
gst_object_unref (src);
|
|
gst_object_unref (sink);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
/* Like test_sticky_caps_unlinked, but link before caps: */
|
|
|
|
GST_START_TEST (test_sticky_caps_flushing)
|
|
{
|
|
GstCaps *caps;
|
|
GstPadTemplate *src_template, *sink_template;
|
|
GstPad *src, *sink;
|
|
GstEvent *event;
|
|
|
|
caps = gst_caps_from_string ("foo/bar, dummy=(int){1, 2}");
|
|
src_template = gst_pad_template_new ("src", GST_PAD_SRC,
|
|
GST_PAD_ALWAYS, caps);
|
|
sink_template = gst_pad_template_new ("sink", GST_PAD_SINK,
|
|
GST_PAD_ALWAYS, caps);
|
|
gst_caps_unref (caps);
|
|
|
|
src = gst_pad_new_from_template (src_template, "src");
|
|
fail_if (src == NULL);
|
|
sink = gst_pad_new_from_template (sink_template, "sink");
|
|
fail_if (sink == NULL);
|
|
gst_pad_set_event_function (sink, sticky_event);
|
|
gst_pad_set_chain_function (sink, gst_check_chain_func);
|
|
|
|
gst_object_unref (src_template);
|
|
gst_object_unref (sink_template);
|
|
|
|
fail_unless (GST_PAD_LINK_SUCCESSFUL (gst_pad_link (src, sink)));
|
|
|
|
caps = gst_caps_from_string ("foo/bar, dummy=(int)1");
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
|
|
|
|
event = gst_event_new_caps (caps);
|
|
|
|
gst_pad_set_active (src, TRUE);
|
|
fail_unless (gst_pad_push_event (src,
|
|
gst_event_new_stream_start ("test")) == TRUE);
|
|
/* The caps event gets accepted by the source pad (and stored) */
|
|
fail_unless (gst_pad_push_event (src, event) == TRUE);
|
|
/* But wasn't forwarded since the sink pad is flushing (not activated) */
|
|
fail_unless (event_caps == NULL);
|
|
|
|
fail_unless (gst_pad_push_event (src,
|
|
gst_event_new_segment (&dummy_segment)) == TRUE);
|
|
|
|
/* Activating will not forward the sticky event yet... */
|
|
gst_pad_set_active (sink, TRUE);
|
|
fail_unless (event_caps == NULL);
|
|
|
|
/* ...but the first buffer will: */
|
|
fail_unless (gst_pad_push (src, gst_buffer_new ()) == GST_FLOW_OK);
|
|
fail_unless (event_caps == caps);
|
|
fail_unless_equals_int (g_list_length (buffers), 1);
|
|
|
|
gst_check_drop_buffers ();
|
|
|
|
gst_caps_replace (&caps, NULL);
|
|
gst_caps_replace (&event_caps, NULL);
|
|
|
|
ASSERT_OBJECT_REFCOUNT (src, "src", 1);
|
|
ASSERT_OBJECT_REFCOUNT (sink, "sink", 1);
|
|
gst_object_unref (src);
|
|
gst_object_unref (sink);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
static gboolean
|
|
name_is_valid (const gchar * name, GstPadPresence presence)
|
|
{
|
|
GstPadTemplate *new;
|
|
GstCaps *any = gst_caps_new_any ();
|
|
|
|
new = gst_pad_template_new (name, GST_PAD_SRC, presence, any);
|
|
gst_caps_unref (any);
|
|
if (new) {
|
|
gst_object_unref (GST_OBJECT (new));
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
GST_START_TEST (test_name_is_valid)
|
|
{
|
|
gboolean result = FALSE;
|
|
|
|
fail_unless (name_is_valid ("src", GST_PAD_ALWAYS));
|
|
ASSERT_WARNING (name_is_valid ("src%", GST_PAD_ALWAYS));
|
|
ASSERT_WARNING (result = name_is_valid ("src%d", GST_PAD_ALWAYS));
|
|
fail_if (result);
|
|
|
|
fail_unless (name_is_valid ("src", GST_PAD_REQUEST));
|
|
ASSERT_WARNING (name_is_valid ("src%s%s", GST_PAD_REQUEST));
|
|
ASSERT_WARNING (name_is_valid ("src%c", GST_PAD_REQUEST));
|
|
ASSERT_WARNING (name_is_valid ("src%", GST_PAD_REQUEST));
|
|
fail_unless (name_is_valid ("src%dsrc", GST_PAD_REQUEST));
|
|
|
|
fail_unless (name_is_valid ("src", GST_PAD_SOMETIMES));
|
|
fail_unless (name_is_valid ("src%c", GST_PAD_SOMETIMES));
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
static GstPadProbeReturn
|
|
_probe_handler (GstPad * pad, GstPadProbeInfo * info, gpointer userdata)
|
|
{
|
|
GstPadProbeReturn ret = (GstPadProbeReturn) GPOINTER_TO_INT (userdata);
|
|
|
|
/* If we are handling the data, we unref it */
|
|
if (ret == GST_PAD_PROBE_HANDLED
|
|
&& !(GST_PAD_PROBE_INFO_TYPE (info) & GST_PAD_PROBE_TYPE_QUERY_BOTH)) {
|
|
GST_DEBUG_OBJECT (pad, "Unreffing data");
|
|
gst_mini_object_unref (info->data);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static GstPadProbeReturn
|
|
_handled_probe_handler (GstPad * pad, GstPadProbeInfo * info, gpointer userdata)
|
|
{
|
|
GstFlowReturn customflow = (GstFlowReturn) GPOINTER_TO_INT (userdata);
|
|
|
|
/* We are handling the data, we unref it */
|
|
if (!(GST_PAD_PROBE_INFO_TYPE (info) & GST_PAD_PROBE_TYPE_QUERY_BOTH))
|
|
gst_mini_object_unref (info->data);
|
|
GST_PAD_PROBE_INFO_FLOW_RETURN (info) = customflow;
|
|
|
|
return GST_PAD_PROBE_HANDLED;
|
|
}
|
|
|
|
|
|
|
|
GST_START_TEST (test_events_query_unlinked)
|
|
{
|
|
GstPad *src;
|
|
GstCaps *caps;
|
|
gulong id;
|
|
GstQuery *query;
|
|
|
|
src = gst_pad_new ("src", GST_PAD_SRC);
|
|
fail_if (src == NULL);
|
|
caps = gst_pad_get_allowed_caps (src);
|
|
fail_unless (caps == NULL);
|
|
|
|
caps = gst_caps_from_string ("foo/bar");
|
|
|
|
gst_pad_set_active (src, TRUE);
|
|
fail_unless (gst_pad_push_event (src,
|
|
gst_event_new_stream_start ("test")) == TRUE);
|
|
gst_pad_set_caps (src, caps);
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 2);
|
|
fail_unless (gst_pad_push_event (src,
|
|
gst_event_new_segment (&dummy_segment)) == TRUE);
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 2);
|
|
|
|
/* Doing a query on an unlinked pad will return FALSE */
|
|
query = gst_query_new_duration (GST_FORMAT_TIME);
|
|
fail_unless (gst_pad_peer_query (src, query) == FALSE);
|
|
ASSERT_MINI_OBJECT_REFCOUNT (query, "query", 1);
|
|
gst_query_unref (query);
|
|
|
|
/* Add a probe that returns _DROP will make the event push return TRUE
|
|
* even if not linked */
|
|
GST_DEBUG ("event/query DROP");
|
|
id = gst_pad_add_probe (src,
|
|
GST_PAD_PROBE_TYPE_EVENT_BOTH | GST_PAD_PROBE_TYPE_QUERY_BOTH,
|
|
_probe_handler, GINT_TO_POINTER (GST_PAD_PROBE_DROP), NULL);
|
|
fail_unless (gst_pad_push_event (src,
|
|
gst_event_new_segment (&dummy_segment)) == TRUE);
|
|
/* Queries should still fail */
|
|
query = gst_query_new_duration (GST_FORMAT_TIME);
|
|
fail_unless (gst_pad_peer_query (src, query) == FALSE);
|
|
ASSERT_MINI_OBJECT_REFCOUNT (query, "query", 1);
|
|
gst_query_unref (query);
|
|
gst_pad_remove_probe (src, id);
|
|
|
|
/* Add a probe that returns _HANDLED will make the event push return TRUE
|
|
* even if not linked */
|
|
GST_DEBUG ("event/query HANDLED");
|
|
id = gst_pad_add_probe (src,
|
|
GST_PAD_PROBE_TYPE_EVENT_BOTH | GST_PAD_PROBE_TYPE_QUERY_BOTH,
|
|
_probe_handler, GINT_TO_POINTER (GST_PAD_PROBE_HANDLED), NULL);
|
|
fail_unless (gst_pad_push_event (src,
|
|
gst_event_new_segment (&dummy_segment)) == TRUE);
|
|
|
|
/* Queries will succeed */
|
|
query = gst_query_new_duration (GST_FORMAT_TIME);
|
|
fail_unless (gst_pad_peer_query (src, query) == TRUE);
|
|
ASSERT_MINI_OBJECT_REFCOUNT (query, "query", 1);
|
|
gst_query_unref (query);
|
|
gst_pad_remove_probe (src, id);
|
|
|
|
/* cleanup */
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 2);
|
|
ASSERT_OBJECT_REFCOUNT (src, "src", 1);
|
|
|
|
gst_object_unref (src);
|
|
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
|
|
gst_caps_unref (caps);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_push_unlinked)
|
|
{
|
|
GstPad *src;
|
|
GstCaps *caps;
|
|
GstBuffer *buffer;
|
|
gulong id;
|
|
GstFlowReturn fl;
|
|
|
|
src = gst_pad_new ("src", GST_PAD_SRC);
|
|
fail_if (src == NULL);
|
|
caps = gst_pad_get_allowed_caps (src);
|
|
fail_unless (caps == NULL);
|
|
|
|
caps = gst_caps_from_string ("foo/bar");
|
|
|
|
/* pushing on an inactive pad will return wrong state */
|
|
GST_DEBUG ("push buffer inactive");
|
|
buffer = gst_buffer_new ();
|
|
gst_buffer_ref (buffer);
|
|
fail_unless (gst_pad_push (src, buffer) == GST_FLOW_FLUSHING);
|
|
ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
|
|
gst_buffer_unref (buffer);
|
|
|
|
gst_pad_set_active (src, TRUE);
|
|
fail_unless (gst_pad_push_event (src,
|
|
gst_event_new_stream_start ("test")) == TRUE);
|
|
GST_DEBUG ("push caps event inactive");
|
|
gst_pad_set_caps (src, caps);
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 2);
|
|
fail_unless (gst_pad_push_event (src,
|
|
gst_event_new_segment (&dummy_segment)) == TRUE);
|
|
|
|
/* pushing on an unlinked pad will drop the buffer */
|
|
GST_DEBUG ("push buffer unlinked");
|
|
buffer = gst_buffer_new ();
|
|
gst_buffer_ref (buffer);
|
|
fail_unless (gst_pad_push (src, buffer) == GST_FLOW_NOT_LINKED);
|
|
ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
|
|
gst_buffer_unref (buffer);
|
|
|
|
/* adding a probe that returns _DROP will drop the buffer without trying
|
|
* to chain */
|
|
GST_DEBUG ("push buffer drop");
|
|
id = gst_pad_add_probe (src, GST_PAD_PROBE_TYPE_BUFFER,
|
|
_probe_handler, GINT_TO_POINTER (GST_PAD_PROBE_DROP), NULL);
|
|
buffer = gst_buffer_new ();
|
|
gst_buffer_ref (buffer);
|
|
fail_unless (gst_pad_push (src, buffer) == GST_FLOW_OK);
|
|
ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
|
|
gst_buffer_unref (buffer);
|
|
gst_pad_remove_probe (src, id);
|
|
|
|
/* adding a probe that returns _HANDLED will drop the buffer without trying
|
|
* to chain */
|
|
GST_DEBUG ("push buffer handled");
|
|
id = gst_pad_add_probe (src, GST_PAD_PROBE_TYPE_BUFFER,
|
|
_probe_handler, GINT_TO_POINTER (GST_PAD_PROBE_HANDLED), NULL);
|
|
buffer = gst_buffer_new ();
|
|
gst_buffer_ref (buffer);
|
|
fail_unless (gst_pad_push (src, buffer) == GST_FLOW_OK);
|
|
ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
|
|
gst_buffer_unref (buffer);
|
|
gst_pad_remove_probe (src, id);
|
|
|
|
/* adding a probe that returns _OK will still chain the buffer,
|
|
* and hence drop because pad is unlinked */
|
|
GST_DEBUG ("push buffer ok");
|
|
id = gst_pad_add_probe (src, GST_PAD_PROBE_TYPE_BUFFER,
|
|
_probe_handler, GINT_TO_POINTER (GST_PAD_PROBE_OK), NULL);
|
|
buffer = gst_buffer_new ();
|
|
gst_buffer_ref (buffer);
|
|
fail_unless (gst_pad_push (src, buffer) == GST_FLOW_NOT_LINKED);
|
|
ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
|
|
gst_buffer_unref (buffer);
|
|
gst_pad_remove_probe (src, id);
|
|
|
|
GST_DEBUG ("push buffer handled and custom return");
|
|
for (fl = GST_FLOW_NOT_SUPPORTED; fl <= GST_FLOW_OK; fl += 1) {
|
|
GST_DEBUG ("Testing with %s", gst_flow_get_name (fl));
|
|
id = gst_pad_add_probe (src, GST_PAD_PROBE_TYPE_BUFFER,
|
|
_handled_probe_handler, GINT_TO_POINTER (fl), NULL);
|
|
buffer = gst_buffer_new ();
|
|
gst_buffer_ref (buffer);
|
|
fail_unless (gst_pad_push (src, buffer) == fl);
|
|
ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
|
|
gst_buffer_unref (buffer);
|
|
gst_pad_remove_probe (src, id);
|
|
|
|
}
|
|
|
|
|
|
/* cleanup */
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 2);
|
|
ASSERT_OBJECT_REFCOUNT (src, "src", 1);
|
|
|
|
gst_object_unref (src);
|
|
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
|
|
gst_caps_unref (caps);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_push_linked)
|
|
{
|
|
GstPad *src, *sink;
|
|
GstPadLinkReturn plr;
|
|
GstCaps *caps;
|
|
GstBuffer *buffer;
|
|
gulong id;
|
|
|
|
/* setup */
|
|
sink = gst_pad_new ("sink", GST_PAD_SINK);
|
|
fail_if (sink == NULL);
|
|
gst_pad_set_chain_function (sink, gst_check_chain_func);
|
|
|
|
src = gst_pad_new ("src", GST_PAD_SRC);
|
|
fail_if (src == NULL);
|
|
|
|
caps = gst_caps_from_string ("foo/bar");
|
|
/* one for me */
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
|
|
|
|
gst_pad_set_active (src, TRUE);
|
|
|
|
fail_unless (gst_pad_push_event (src,
|
|
gst_event_new_stream_start ("test")) == TRUE);
|
|
|
|
gst_pad_set_caps (src, caps);
|
|
|
|
fail_unless (gst_pad_push_event (src,
|
|
gst_event_new_segment (&dummy_segment)) == TRUE);
|
|
|
|
gst_pad_set_active (sink, TRUE);
|
|
/* one for me and one for each set_caps */
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 2);
|
|
|
|
plr = gst_pad_link (src, sink);
|
|
fail_unless (GST_PAD_LINK_SUCCESSFUL (plr));
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 2);
|
|
|
|
buffer = gst_buffer_new ();
|
|
|
|
/* test */
|
|
/* pushing on a linked pad will drop the ref to the buffer */
|
|
gst_buffer_ref (buffer);
|
|
fail_unless (gst_pad_push (src, buffer) == GST_FLOW_OK);
|
|
ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 2);
|
|
gst_buffer_unref (buffer);
|
|
fail_unless_equals_int (g_list_length (buffers), 1);
|
|
buffer = GST_BUFFER (buffers->data);
|
|
ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
|
|
gst_buffer_unref (buffer);
|
|
g_list_free (buffers);
|
|
buffers = NULL;
|
|
|
|
/* adding a probe that returns _DROP will drop the buffer without trying
|
|
* to chain */
|
|
id = gst_pad_add_probe (src, GST_PAD_PROBE_TYPE_BUFFER,
|
|
_probe_handler, GINT_TO_POINTER (GST_PAD_PROBE_DROP), NULL);
|
|
buffer = gst_buffer_new ();
|
|
gst_buffer_ref (buffer);
|
|
fail_unless (gst_pad_push (src, buffer) == GST_FLOW_OK);
|
|
ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
|
|
gst_buffer_unref (buffer);
|
|
gst_pad_remove_probe (src, id);
|
|
fail_unless_equals_int (g_list_length (buffers), 0);
|
|
|
|
/* adding a probe that returns _OK will still chain the buffer */
|
|
id = gst_pad_add_probe (src, GST_PAD_PROBE_TYPE_BUFFER,
|
|
_probe_handler, GINT_TO_POINTER (GST_PAD_PROBE_OK), NULL);
|
|
buffer = gst_buffer_new ();
|
|
gst_buffer_ref (buffer);
|
|
fail_unless (gst_pad_push (src, buffer) == GST_FLOW_OK);
|
|
gst_pad_remove_probe (src, id);
|
|
|
|
ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 2);
|
|
gst_buffer_unref (buffer);
|
|
fail_unless_equals_int (g_list_length (buffers), 1);
|
|
buffer = GST_BUFFER (buffers->data);
|
|
ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
|
|
gst_buffer_unref (buffer);
|
|
g_list_free (buffers);
|
|
buffers = NULL;
|
|
|
|
/* adding a probe that returns _HANDLED will not chain the buffer */
|
|
id = gst_pad_add_probe (src, GST_PAD_PROBE_TYPE_BUFFER,
|
|
_probe_handler, GINT_TO_POINTER (GST_PAD_PROBE_HANDLED), NULL);
|
|
buffer = gst_buffer_new ();
|
|
gst_buffer_ref (buffer);
|
|
fail_unless (gst_pad_push (src, buffer) == GST_FLOW_OK);
|
|
gst_pad_remove_probe (src, id);
|
|
|
|
ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
|
|
gst_buffer_unref (buffer);
|
|
fail_unless_equals_int (g_list_length (buffers), 0);
|
|
g_list_free (buffers);
|
|
buffers = NULL;
|
|
|
|
/* teardown */
|
|
gst_check_drop_buffers ();
|
|
gst_pad_unlink (src, sink);
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 2);
|
|
gst_object_unref (src);
|
|
gst_object_unref (sink);
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
|
|
|
|
gst_caps_unref (caps);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_push_linked_flushing)
|
|
{
|
|
GstPad *src, *sink;
|
|
GstCaps *caps;
|
|
GstPadLinkReturn plr;
|
|
GstBuffer *buffer;
|
|
gulong id;
|
|
|
|
/* setup */
|
|
src = gst_pad_new ("src", GST_PAD_SRC);
|
|
fail_if (src == NULL);
|
|
sink = gst_pad_new ("sink", GST_PAD_SINK);
|
|
fail_if (sink == NULL);
|
|
gst_pad_set_chain_function (sink, gst_check_chain_func);
|
|
|
|
caps = gst_pad_get_allowed_caps (src);
|
|
fail_unless (caps == NULL);
|
|
caps = gst_pad_get_allowed_caps (sink);
|
|
fail_unless (caps == NULL);
|
|
|
|
caps = gst_caps_from_string ("foo/bar");
|
|
/* one for me */
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
|
|
|
|
gst_pad_set_active (src, TRUE);
|
|
fail_unless (gst_pad_push_event (src,
|
|
gst_event_new_stream_start ("test")) == TRUE);
|
|
gst_pad_set_caps (src, caps);
|
|
fail_unless (gst_pad_push_event (src,
|
|
gst_event_new_segment (&dummy_segment)) == TRUE);
|
|
/* need to activate to make it accept the caps */
|
|
gst_pad_set_active (sink, TRUE);
|
|
/* one for me and one for each set_caps */
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 2);
|
|
|
|
plr = gst_pad_link (src, sink);
|
|
fail_unless (GST_PAD_LINK_SUCCESSFUL (plr));
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 2);
|
|
|
|
/* not activating the pads here, which keeps them flushing */
|
|
gst_pad_set_active (src, FALSE);
|
|
gst_pad_set_active (sink, FALSE);
|
|
|
|
/* pushing on a flushing pad will drop the buffer */
|
|
buffer = gst_buffer_new ();
|
|
gst_buffer_ref (buffer);
|
|
fail_unless (gst_pad_push (src, buffer) == GST_FLOW_FLUSHING);
|
|
ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
|
|
fail_unless_equals_int (g_list_length (buffers), 0);
|
|
gst_buffer_unref (buffer);
|
|
|
|
gst_pad_set_active (src, TRUE);
|
|
gst_pad_set_active (sink, FALSE);
|
|
|
|
fail_unless (gst_pad_push_event (src,
|
|
gst_event_new_stream_start ("test")) == TRUE);
|
|
gst_pad_set_caps (src, caps);
|
|
fail_unless (gst_pad_push_event (src,
|
|
gst_event_new_segment (&dummy_segment)) == TRUE);
|
|
/* adding a probe that returns _DROP will drop the buffer without trying
|
|
* to chain */
|
|
id = gst_pad_add_probe (src, GST_PAD_PROBE_TYPE_BUFFER, _probe_handler,
|
|
GINT_TO_POINTER (GST_PAD_PROBE_DROP), NULL);
|
|
buffer = gst_buffer_new ();
|
|
gst_buffer_ref (buffer);
|
|
fail_unless (gst_pad_push (src, buffer) == GST_FLOW_FLUSHING);
|
|
ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
|
|
fail_unless_equals_int (g_list_length (buffers), 0);
|
|
gst_buffer_unref (buffer);
|
|
gst_pad_remove_probe (src, id);
|
|
|
|
/* adding a probe that returns _OK will still chain the buffer,
|
|
* and hence drop because pad is flushing */
|
|
id = gst_pad_add_probe (src, GST_PAD_PROBE_TYPE_BUFFER, _probe_handler,
|
|
GINT_TO_POINTER (GST_PAD_PROBE_OK), NULL);
|
|
buffer = gst_buffer_new ();
|
|
gst_buffer_ref (buffer);
|
|
fail_unless (gst_pad_push (src, buffer) == GST_FLOW_FLUSHING);
|
|
ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
|
|
fail_unless_equals_int (g_list_length (buffers), 0);
|
|
gst_buffer_unref (buffer);
|
|
gst_pad_remove_probe (src, id);
|
|
|
|
/* cleanup */
|
|
gst_check_drop_buffers ();
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 2);
|
|
ASSERT_OBJECT_REFCOUNT (src, "src", 1);
|
|
gst_pad_link (src, sink);
|
|
gst_object_unref (src);
|
|
gst_object_unref (sink);
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
|
|
gst_caps_unref (caps);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
static GstBuffer *
|
|
buffer_from_string (const gchar * str)
|
|
{
|
|
guint size;
|
|
GstBuffer *buf;
|
|
|
|
size = strlen (str);
|
|
buf = gst_buffer_new_and_alloc (size);
|
|
|
|
gst_buffer_fill (buf, 0, str, size);
|
|
|
|
return buf;
|
|
}
|
|
|
|
static gboolean
|
|
buffer_compare (GstBuffer * buf, const gchar * str, gsize size)
|
|
{
|
|
gboolean res;
|
|
GstMapInfo info;
|
|
|
|
fail_unless (gst_buffer_map (buf, &info, GST_MAP_READ));
|
|
res = memcmp (info.data, str, size) == 0;
|
|
GST_MEMDUMP ("buffer data", info.data, size);
|
|
GST_MEMDUMP ("compare data", (guint8 *) str, size);
|
|
GST_DEBUG ("buffers match: %s", res ? "yes" : "no");
|
|
gst_buffer_unmap (buf, &info);
|
|
|
|
return res;
|
|
}
|
|
|
|
GST_START_TEST (test_push_buffer_list_compat)
|
|
{
|
|
GstPad *src, *sink;
|
|
GstPadLinkReturn plr;
|
|
GstCaps *caps;
|
|
GstBufferList *list;
|
|
GstBuffer *buffer;
|
|
|
|
/* setup */
|
|
sink = gst_pad_new ("sink", GST_PAD_SINK);
|
|
fail_if (sink == NULL);
|
|
gst_pad_set_chain_function (sink, gst_check_chain_func);
|
|
/* leave chainlistfunc unset */
|
|
|
|
src = gst_pad_new ("src", GST_PAD_SRC);
|
|
fail_if (src == NULL);
|
|
|
|
caps = gst_caps_from_string ("foo/bar");
|
|
|
|
gst_pad_set_active (src, TRUE);
|
|
|
|
fail_unless (gst_pad_push_event (src,
|
|
gst_event_new_stream_start ("test")) == TRUE);
|
|
|
|
gst_pad_set_caps (src, caps);
|
|
|
|
fail_unless (gst_pad_push_event (src,
|
|
gst_event_new_segment (&dummy_segment)) == TRUE);
|
|
|
|
gst_pad_set_active (sink, TRUE);
|
|
|
|
plr = gst_pad_link (src, sink);
|
|
fail_unless (GST_PAD_LINK_SUCCESSFUL (plr));
|
|
|
|
list = gst_buffer_list_new ();
|
|
|
|
/* test */
|
|
/* adding to a buffer list will drop the ref to the buffer */
|
|
gst_buffer_list_add (list, buffer_from_string ("ListGroup"));
|
|
gst_buffer_list_add (list, buffer_from_string ("AnotherListGroup"));
|
|
|
|
fail_unless (gst_pad_push_list (src, list) == GST_FLOW_OK);
|
|
fail_unless_equals_int (g_list_length (buffers), 2);
|
|
buffer = GST_BUFFER (buffers->data);
|
|
ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
|
|
fail_unless (buffer_compare (buffer, "ListGroup", 9));
|
|
gst_buffer_unref (buffer);
|
|
buffers = g_list_delete_link (buffers, buffers);
|
|
buffer = GST_BUFFER (buffers->data);
|
|
ASSERT_MINI_OBJECT_REFCOUNT (buffer, "buffer", 1);
|
|
fail_unless (buffer_compare (buffer, "AnotherListGroup", 16));
|
|
gst_buffer_unref (buffer);
|
|
buffers = g_list_delete_link (buffers, buffers);
|
|
fail_unless (buffers == NULL);
|
|
|
|
/* teardown */
|
|
gst_check_drop_buffers ();
|
|
gst_pad_unlink (src, sink);
|
|
gst_object_unref (src);
|
|
gst_object_unref (sink);
|
|
ASSERT_CAPS_REFCOUNT (caps, "caps", 1);
|
|
gst_caps_unref (caps);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_flowreturn)
|
|
{
|
|
GstFlowReturn ret;
|
|
GQuark quark;
|
|
|
|
/* test some of the macros */
|
|
ret = GST_FLOW_EOS;
|
|
fail_if (strcmp (gst_flow_get_name (ret), "eos"));
|
|
quark = gst_flow_to_quark (ret);
|
|
fail_if (strcmp (g_quark_to_string (quark), "eos"));
|
|
|
|
/* custom returns */
|
|
ret = GST_FLOW_CUSTOM_SUCCESS;
|
|
fail_if (strcmp (gst_flow_get_name (ret), "custom-success"));
|
|
quark = gst_flow_to_quark (ret);
|
|
fail_if (strcmp (g_quark_to_string (quark), "custom-success"));
|
|
|
|
ret = GST_FLOW_CUSTOM_ERROR;
|
|
fail_if (strcmp (gst_flow_get_name (ret), "custom-error"));
|
|
quark = gst_flow_to_quark (ret);
|
|
fail_if (strcmp (g_quark_to_string (quark), "custom-error"));
|
|
|
|
/* custom returns clamping */
|
|
ret = GST_FLOW_CUSTOM_SUCCESS + 2;
|
|
fail_if (strcmp (gst_flow_get_name (ret), "custom-success"));
|
|
quark = gst_flow_to_quark (ret);
|
|
fail_if (strcmp (g_quark_to_string (quark), "custom-success"));
|
|
|
|
ret = GST_FLOW_CUSTOM_ERROR - 2;
|
|
fail_if (strcmp (gst_flow_get_name (ret), "custom-error"));
|
|
quark = gst_flow_to_quark (ret);
|
|
fail_if (strcmp (g_quark_to_string (quark), "custom-error"));
|
|
|
|
/* unknown values */
|
|
ret = GST_FLOW_CUSTOM_ERROR + 2;
|
|
fail_if (strcmp (gst_flow_get_name (ret), "unknown"));
|
|
quark = gst_flow_to_quark (ret);
|
|
fail_unless (quark == 0);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_push_negotiation)
|
|
{
|
|
GstPad *src, *sink;
|
|
GstPadLinkReturn plr;
|
|
GstCaps *srccaps =
|
|
gst_caps_from_string ("audio/x-raw,width={16,32},depth={16,32}");
|
|
GstCaps *sinkcaps =
|
|
gst_caps_from_string ("audio/x-raw,width=32,depth={16,32}");
|
|
GstPadTemplate *src_template;
|
|
GstPadTemplate *sink_template;
|
|
GstCaps *caps;
|
|
|
|
/* setup */
|
|
src_template = gst_pad_template_new ("src", GST_PAD_SRC,
|
|
GST_PAD_ALWAYS, srccaps);
|
|
sink_template = gst_pad_template_new ("sink", GST_PAD_SINK,
|
|
GST_PAD_ALWAYS, sinkcaps);
|
|
gst_caps_unref (srccaps);
|
|
gst_caps_unref (sinkcaps);
|
|
|
|
sink = gst_pad_new_from_template (sink_template, "sink");
|
|
fail_if (sink == NULL);
|
|
gst_pad_set_chain_function (sink, gst_check_chain_func);
|
|
|
|
src = gst_pad_new_from_template (src_template, "src");
|
|
fail_if (src == NULL);
|
|
|
|
plr = gst_pad_link (src, sink);
|
|
fail_unless (GST_PAD_LINK_SUCCESSFUL (plr));
|
|
|
|
/* activate pads */
|
|
gst_pad_set_active (src, TRUE);
|
|
gst_pad_set_active (sink, TRUE);
|
|
|
|
caps = gst_caps_from_string ("audio/x-raw,width=16,depth=16");
|
|
|
|
/* Should fail if src pad caps are incompatible with sink pad caps */
|
|
gst_pad_set_caps (src, caps);
|
|
fail_unless (gst_pad_set_caps (sink, caps) == FALSE);
|
|
|
|
/* teardown */
|
|
gst_check_drop_buffers ();
|
|
gst_pad_unlink (src, sink);
|
|
gst_object_unref (src);
|
|
gst_object_unref (sink);
|
|
gst_caps_unref (caps);
|
|
gst_object_unref (sink_template);
|
|
gst_object_unref (src_template);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
/* see that an unref also unlinks the pads */
|
|
GST_START_TEST (test_src_unref_unlink)
|
|
{
|
|
GstPad *src, *sink;
|
|
GstCaps *caps;
|
|
GstPadLinkReturn plr;
|
|
|
|
sink = gst_pad_new ("sink", GST_PAD_SINK);
|
|
fail_if (sink == NULL);
|
|
|
|
src = gst_pad_new ("src", GST_PAD_SRC);
|
|
fail_if (src == NULL);
|
|
|
|
caps = gst_caps_from_string ("foo/bar");
|
|
|
|
gst_pad_set_active (src, TRUE);
|
|
gst_pad_set_caps (src, caps);
|
|
gst_pad_set_active (sink, TRUE);
|
|
gst_pad_set_caps (sink, caps);
|
|
|
|
plr = gst_pad_link (src, sink);
|
|
fail_unless (GST_PAD_LINK_SUCCESSFUL (plr));
|
|
|
|
/* unref the srcpad */
|
|
gst_object_unref (src);
|
|
|
|
/* sink should be unlinked now */
|
|
fail_if (gst_pad_is_linked (sink));
|
|
|
|
/* cleanup */
|
|
gst_object_unref (sink);
|
|
gst_caps_unref (caps);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
/* see that an unref also unlinks the pads */
|
|
GST_START_TEST (test_sink_unref_unlink)
|
|
{
|
|
GstPad *src, *sink;
|
|
GstCaps *caps;
|
|
GstPadLinkReturn plr;
|
|
|
|
sink = gst_pad_new ("sink", GST_PAD_SINK);
|
|
fail_if (sink == NULL);
|
|
|
|
src = gst_pad_new ("src", GST_PAD_SRC);
|
|
fail_if (src == NULL);
|
|
|
|
caps = gst_caps_from_string ("foo/bar");
|
|
|
|
gst_pad_set_active (src, TRUE);
|
|
gst_pad_set_caps (src, caps);
|
|
gst_pad_set_active (sink, TRUE);
|
|
gst_pad_set_caps (sink, caps);
|
|
|
|
plr = gst_pad_link (src, sink);
|
|
fail_unless (GST_PAD_LINK_SUCCESSFUL (plr));
|
|
|
|
/* unref the sinkpad */
|
|
gst_object_unref (sink);
|
|
|
|
/* src should be unlinked now */
|
|
fail_if (gst_pad_is_linked (src));
|
|
|
|
/* cleanup */
|
|
gst_object_unref (src);
|
|
gst_caps_unref (caps);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
static gulong id;
|
|
|
|
static GstPadProbeReturn
|
|
block_async_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
|
|
{
|
|
gboolean *bool_user_data = (gboolean *) user_data;
|
|
|
|
fail_unless ((info->type & GST_PAD_PROBE_TYPE_BLOCK) != 0);
|
|
|
|
/* here we should have blocked == 0 unblocked == 0 */
|
|
fail_unless (bool_user_data[0] == FALSE);
|
|
fail_unless (bool_user_data[1] == FALSE);
|
|
|
|
bool_user_data[0] = TRUE;
|
|
|
|
gst_pad_remove_probe (pad, id);
|
|
bool_user_data[1] = TRUE;
|
|
|
|
return GST_PAD_PROBE_OK;
|
|
}
|
|
|
|
GST_START_TEST (test_block_async)
|
|
{
|
|
GstPad *pad;
|
|
/* we set data[0] = TRUE when the pad is blocked, data[1] = TRUE when it's
|
|
* unblocked */
|
|
gboolean data[2] = { FALSE, FALSE };
|
|
|
|
pad = gst_pad_new ("src", GST_PAD_SRC);
|
|
fail_unless (pad != NULL);
|
|
|
|
gst_pad_set_active (pad, TRUE);
|
|
|
|
fail_unless (gst_pad_push_event (pad,
|
|
gst_event_new_stream_start ("test")) == TRUE);
|
|
fail_unless (gst_pad_push_event (pad,
|
|
gst_event_new_segment (&dummy_segment)) == TRUE);
|
|
|
|
id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BLOCK, block_async_cb, &data,
|
|
NULL);
|
|
|
|
fail_unless (data[0] == FALSE);
|
|
fail_unless (data[1] == FALSE);
|
|
gst_pad_push (pad, gst_buffer_new ());
|
|
|
|
gst_object_unref (pad);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
static GstPadProbeReturn
|
|
block_async_cb_return_ok (GstPad * pad, GstPadProbeInfo * info,
|
|
gpointer user_data)
|
|
{
|
|
return GST_PAD_PROBE_OK;
|
|
}
|
|
|
|
static gpointer
|
|
push_buffer_async (GstPad * pad)
|
|
{
|
|
return GINT_TO_POINTER (gst_pad_push (pad, gst_buffer_new ()));
|
|
}
|
|
|
|
static void
|
|
test_pad_blocking_with_type (GstPadProbeType type)
|
|
{
|
|
GstPad *pad;
|
|
GThread *thread;
|
|
GstFlowReturn ret;
|
|
|
|
pad = gst_pad_new ("src", GST_PAD_SRC);
|
|
fail_unless (pad != NULL);
|
|
|
|
gst_pad_set_active (pad, TRUE);
|
|
|
|
fail_unless (gst_pad_push_event (pad,
|
|
gst_event_new_stream_start ("test")) == TRUE);
|
|
fail_unless (gst_pad_push_event (pad,
|
|
gst_event_new_segment (&dummy_segment)) == TRUE);
|
|
|
|
id = gst_pad_add_probe (pad, type, block_async_cb_return_ok, NULL, NULL);
|
|
|
|
thread = g_thread_try_new ("gst-check", (GThreadFunc) push_buffer_async,
|
|
pad, NULL);
|
|
|
|
/* wait for the block */
|
|
while (!gst_pad_is_blocking (pad)) {
|
|
g_usleep (10000);
|
|
}
|
|
|
|
/* stop with flushing */
|
|
gst_pad_push_event (pad, gst_event_new_flush_start ());
|
|
|
|
/* get return value from push */
|
|
ret = GPOINTER_TO_INT (g_thread_join (thread));
|
|
/* unflush now */
|
|
gst_pad_push_event (pad, gst_event_new_flush_stop (FALSE));
|
|
/* must be wrong state */
|
|
fail_unless (ret == GST_FLOW_FLUSHING);
|
|
|
|
gst_object_unref (pad);
|
|
}
|
|
|
|
GST_START_TEST (test_pad_blocking_with_probe_type_block)
|
|
{
|
|
test_pad_blocking_with_type (GST_PAD_PROBE_TYPE_BLOCK);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_pad_blocking_with_probe_type_blocking)
|
|
{
|
|
test_pad_blocking_with_type (GST_PAD_PROBE_TYPE_BLOCKING);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
static gboolean idle_probe_running;
|
|
|
|
static GstFlowReturn
|
|
idletest_sink_pad_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
|
|
{
|
|
if (idle_probe_running)
|
|
fail ("Should not be reached");
|
|
gst_buffer_unref (buf);
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static GstPadProbeReturn
|
|
idle_probe_wait (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
|
|
{
|
|
/* it is ok to have a probe called multiple times but it is not
|
|
* acceptable in our scenario */
|
|
fail_if (idle_probe_running);
|
|
|
|
idle_probe_running = TRUE;
|
|
while (idle_probe_running) {
|
|
g_usleep (10000);
|
|
}
|
|
|
|
return GST_PAD_PROBE_REMOVE;
|
|
}
|
|
|
|
static gpointer
|
|
add_idle_probe_async (GstPad * pad)
|
|
{
|
|
gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_IDLE, idle_probe_wait, NULL, NULL);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
GST_START_TEST (test_pad_blocking_with_probe_type_idle)
|
|
{
|
|
GstPad *srcpad, *sinkpad;
|
|
GThread *idle_thread, *thread;
|
|
|
|
srcpad = gst_pad_new ("src", GST_PAD_SRC);
|
|
fail_unless (srcpad != NULL);
|
|
sinkpad = gst_pad_new ("sink", GST_PAD_SINK);
|
|
fail_unless (sinkpad != NULL);
|
|
|
|
gst_pad_set_chain_function (sinkpad, idletest_sink_pad_chain);
|
|
|
|
fail_unless (gst_pad_link (srcpad, sinkpad) == GST_PAD_LINK_OK);
|
|
|
|
gst_pad_set_active (sinkpad, TRUE);
|
|
gst_pad_set_active (srcpad, TRUE);
|
|
|
|
fail_unless (gst_pad_push_event (srcpad,
|
|
gst_event_new_stream_start ("test")) == TRUE);
|
|
fail_unless (gst_pad_push_event (srcpad,
|
|
gst_event_new_segment (&dummy_segment)) == TRUE);
|
|
|
|
idle_probe_running = FALSE;
|
|
idle_thread =
|
|
g_thread_try_new ("gst-check", (GThreadFunc) add_idle_probe_async, srcpad,
|
|
NULL);
|
|
|
|
/* wait for the idle function to signal it is being called */
|
|
while (!idle_probe_running) {
|
|
g_usleep (10000);
|
|
}
|
|
|
|
thread = g_thread_try_new ("gst-check", (GThreadFunc) push_buffer_async,
|
|
srcpad, NULL);
|
|
|
|
while (!gst_pad_is_blocking (srcpad)) {
|
|
g_usleep (10000);
|
|
}
|
|
|
|
idle_probe_running = FALSE;
|
|
|
|
g_thread_join (idle_thread);
|
|
g_thread_join (thread);
|
|
gst_object_unref (srcpad);
|
|
gst_object_unref (sinkpad);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
static gboolean pull_probe_called;
|
|
static gboolean pull_probe_called_with_bad_type;
|
|
static gboolean pull_probe_called_with_bad_data;
|
|
|
|
static GstPadProbeReturn
|
|
probe_pull_buffer_cb_check_buffer_return_ok (GstPad * pad,
|
|
GstPadProbeInfo * info, gpointer user_data)
|
|
{
|
|
if (info->type & GST_PAD_PROBE_TYPE_BUFFER) {
|
|
if (GST_IS_BUFFER (info->data))
|
|
pull_probe_called = TRUE;
|
|
else
|
|
pull_probe_called_with_bad_data = TRUE;
|
|
} else {
|
|
/* shouldn't be called */
|
|
pull_probe_called_with_bad_type = TRUE;
|
|
}
|
|
return GST_PAD_PROBE_OK;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
test_probe_pull_getrange (GstPad * pad, GstObject * parent, guint64 offset,
|
|
guint length, GstBuffer ** buf)
|
|
{
|
|
*buf = gst_buffer_new ();
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static gboolean
|
|
test_probe_pull_activate_pull (GstPad * pad, GstObject * object)
|
|
{
|
|
return gst_pad_activate_mode (pad, GST_PAD_MODE_PULL, TRUE);
|
|
}
|
|
|
|
static gpointer
|
|
pull_range_async (GstPad * pad)
|
|
{
|
|
GstBuffer *buf = NULL;
|
|
GstFlowReturn res = gst_pad_pull_range (pad, 0, 100, &buf);
|
|
if (buf)
|
|
gst_buffer_unref (buf);
|
|
return GINT_TO_POINTER (res);
|
|
}
|
|
|
|
GST_START_TEST (test_pad_probe_pull)
|
|
{
|
|
GstPad *srcpad, *sinkpad;
|
|
GThread *thread;
|
|
GstFlowReturn ret;
|
|
|
|
srcpad = gst_pad_new ("src", GST_PAD_SRC);
|
|
fail_unless (srcpad != NULL);
|
|
sinkpad = gst_pad_new ("sink", GST_PAD_SINK);
|
|
fail_unless (sinkpad != NULL);
|
|
|
|
gst_pad_set_getrange_function (srcpad, test_probe_pull_getrange);
|
|
gst_pad_set_activate_function (sinkpad, test_probe_pull_activate_pull);
|
|
gst_pad_link (srcpad, sinkpad);
|
|
|
|
gst_pad_set_active (sinkpad, TRUE);
|
|
gst_pad_set_active (srcpad, TRUE);
|
|
|
|
id = gst_pad_add_probe (sinkpad,
|
|
GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_PULL,
|
|
block_async_cb_return_ok, NULL, NULL);
|
|
|
|
thread = g_thread_try_new ("gst-check", (GThreadFunc) pull_range_async,
|
|
sinkpad, NULL);
|
|
|
|
/* wait for the block */
|
|
while (!gst_pad_is_blocking (sinkpad)) {
|
|
g_usleep (10000);
|
|
}
|
|
|
|
/* stop with flushing */
|
|
gst_pad_push_event (srcpad, gst_event_new_flush_start ());
|
|
|
|
/* get return value from push */
|
|
ret = GPOINTER_TO_INT (g_thread_join (thread));
|
|
/* unflush now */
|
|
gst_pad_push_event (srcpad, gst_event_new_flush_stop (FALSE));
|
|
/* must be wrong state */
|
|
fail_unless (ret == GST_FLOW_FLUSHING);
|
|
|
|
gst_object_unref (srcpad);
|
|
gst_object_unref (sinkpad);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
static gboolean idle_probe_called;
|
|
static gboolean get_range_wait;
|
|
static gboolean getrange_waiting;
|
|
|
|
static GstPadProbeReturn
|
|
idle_cb_return_ok (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
|
|
{
|
|
idle_probe_called = TRUE;
|
|
return GST_PAD_PROBE_OK;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
test_probe_pull_getrange_wait (GstPad * pad, GstObject * parent, guint64 offset,
|
|
guint length, GstBuffer ** buf)
|
|
{
|
|
getrange_waiting = TRUE;
|
|
|
|
*buf = gst_buffer_new ();
|
|
while (get_range_wait) {
|
|
g_usleep (10000);
|
|
}
|
|
|
|
getrange_waiting = FALSE;
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
GST_START_TEST (test_pad_probe_pull_idle)
|
|
{
|
|
GstPad *srcpad, *sinkpad;
|
|
GThread *thread;
|
|
GstFlowReturn ret;
|
|
|
|
srcpad = gst_pad_new ("src", GST_PAD_SRC);
|
|
fail_unless (srcpad != NULL);
|
|
sinkpad = gst_pad_new ("sink", GST_PAD_SINK);
|
|
fail_unless (sinkpad != NULL);
|
|
|
|
gst_pad_set_getrange_function (srcpad, test_probe_pull_getrange_wait);
|
|
gst_pad_set_activate_function (sinkpad, test_probe_pull_activate_pull);
|
|
gst_pad_link (srcpad, sinkpad);
|
|
|
|
gst_pad_set_active (sinkpad, TRUE);
|
|
gst_pad_set_active (srcpad, TRUE);
|
|
|
|
idle_probe_called = FALSE;
|
|
get_range_wait = TRUE;
|
|
thread = g_thread_try_new ("gst-check", (GThreadFunc) pull_range_async,
|
|
sinkpad, NULL);
|
|
|
|
/* wait for the block */
|
|
while (!getrange_waiting) {
|
|
g_usleep (10000);
|
|
}
|
|
|
|
id = gst_pad_add_probe (sinkpad,
|
|
GST_PAD_PROBE_TYPE_IDLE | GST_PAD_PROBE_TYPE_PULL,
|
|
idle_cb_return_ok, NULL, NULL);
|
|
|
|
fail_if (idle_probe_called);
|
|
|
|
get_range_wait = FALSE;
|
|
while (getrange_waiting) {
|
|
g_usleep (10000);
|
|
}
|
|
while (!idle_probe_called) {
|
|
g_usleep (10000);
|
|
}
|
|
|
|
ret = GPOINTER_TO_INT (g_thread_join (thread));
|
|
fail_unless (ret == GST_FLOW_OK);
|
|
gst_pad_set_active (srcpad, FALSE);
|
|
gst_pad_set_active (sinkpad, FALSE);
|
|
gst_object_unref (srcpad);
|
|
gst_object_unref (sinkpad);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
|
|
GST_START_TEST (test_pad_probe_pull_buffer)
|
|
{
|
|
GstPad *srcpad, *sinkpad;
|
|
GThread *thread;
|
|
GstFlowReturn ret;
|
|
|
|
srcpad = gst_pad_new ("src", GST_PAD_SRC);
|
|
fail_unless (srcpad != NULL);
|
|
sinkpad = gst_pad_new ("sink", GST_PAD_SINK);
|
|
fail_unless (sinkpad != NULL);
|
|
|
|
gst_pad_set_getrange_function (srcpad, test_probe_pull_getrange);
|
|
gst_pad_set_activate_function (sinkpad, test_probe_pull_activate_pull);
|
|
gst_pad_link (srcpad, sinkpad);
|
|
|
|
gst_pad_set_active (sinkpad, TRUE);
|
|
gst_pad_set_active (srcpad, TRUE);
|
|
|
|
id = gst_pad_add_probe (sinkpad,
|
|
GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_PULL,
|
|
probe_pull_buffer_cb_check_buffer_return_ok, NULL, NULL);
|
|
|
|
pull_probe_called = FALSE;
|
|
pull_probe_called_with_bad_type = FALSE;
|
|
pull_probe_called_with_bad_data = FALSE;
|
|
|
|
thread = g_thread_try_new ("gst-check", (GThreadFunc) pull_range_async,
|
|
sinkpad, NULL);
|
|
|
|
/* wait for the block */
|
|
while (!pull_probe_called && !pull_probe_called_with_bad_data
|
|
&& !pull_probe_called_with_bad_type) {
|
|
g_usleep (10000);
|
|
}
|
|
|
|
fail_unless (pull_probe_called);
|
|
fail_if (pull_probe_called_with_bad_data);
|
|
fail_if (pull_probe_called_with_bad_type);
|
|
|
|
/* get return value from push */
|
|
ret = GPOINTER_TO_INT (g_thread_join (thread));
|
|
fail_unless (ret == GST_FLOW_OK);
|
|
|
|
gst_pad_set_active (sinkpad, FALSE);
|
|
gst_pad_set_active (srcpad, FALSE);
|
|
gst_object_unref (srcpad);
|
|
gst_object_unref (sinkpad);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
static gboolean pad_probe_remove_notifiy_called = FALSE;
|
|
|
|
static GstPadProbeReturn
|
|
probe_remove_self_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
|
|
{
|
|
gst_pad_remove_probe (pad, info->id);
|
|
|
|
fail_unless (pad->num_probes == 0);
|
|
fail_unless (pad->num_blocked == 0);
|
|
|
|
return GST_PAD_PROBE_REMOVE;
|
|
}
|
|
|
|
static void
|
|
probe_remove_notify_cb (gpointer data)
|
|
{
|
|
fail_unless (pad_probe_remove_notifiy_called == FALSE);
|
|
pad_probe_remove_notifiy_called = TRUE;
|
|
}
|
|
|
|
GST_START_TEST (test_pad_probe_remove)
|
|
{
|
|
GstPad *pad;
|
|
|
|
pad = gst_pad_new ("src", GST_PAD_SRC);
|
|
fail_unless (pad != NULL);
|
|
|
|
gst_pad_set_active (pad, TRUE);
|
|
fail_unless (pad->num_probes == 0);
|
|
fail_unless (pad->num_blocked == 0);
|
|
gst_pad_add_probe (pad,
|
|
GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
|
|
probe_remove_self_cb, NULL, probe_remove_notify_cb);
|
|
fail_unless (pad->num_probes == 1);
|
|
fail_unless (pad->num_blocked == 1);
|
|
|
|
pad_probe_remove_notifiy_called = FALSE;
|
|
gst_pad_push_event (pad, gst_event_new_stream_start ("asda"));
|
|
|
|
fail_unless (pad->num_probes == 0);
|
|
fail_unless (pad->num_blocked == 0);
|
|
|
|
gst_object_unref (pad);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
typedef struct
|
|
{
|
|
gulong probe_id;
|
|
GstPad *probe_pad;
|
|
GThread *thread;
|
|
} BlockReplaceProbeHelper;
|
|
|
|
static gpointer
|
|
unblock_probe_thread (gpointer user_data)
|
|
{
|
|
BlockReplaceProbeHelper *helper = user_data;
|
|
|
|
GST_INFO_OBJECT (helper->probe_pad, "removing probe to unblock pad");
|
|
gst_pad_remove_probe (helper->probe_pad, helper->probe_id);
|
|
return NULL;
|
|
}
|
|
|
|
static GstPadProbeReturn
|
|
block_and_replace_buffer_probe_cb (GstPad * pad, GstPadProbeInfo * info,
|
|
gpointer user_data)
|
|
{
|
|
BlockReplaceProbeHelper *helper = user_data;
|
|
|
|
GST_INFO_OBJECT (pad, "about to block pad, replacing buffer");
|
|
|
|
/* we want to block, but also drop this buffer */
|
|
gst_buffer_unref (GST_BUFFER (info->data));
|
|
info->data = NULL;
|
|
|
|
helper->thread =
|
|
g_thread_new ("gst-pad-test-thread", unblock_probe_thread, helper);
|
|
|
|
return GST_PAD_PROBE_OK;
|
|
}
|
|
|
|
GST_START_TEST (test_pad_probe_block_and_drop_buffer)
|
|
{
|
|
BlockReplaceProbeHelper helper;
|
|
GstFlowReturn flow;
|
|
GstPad *src, *sink;
|
|
|
|
src = gst_pad_new ("src", GST_PAD_SRC);
|
|
gst_pad_set_active (src, TRUE);
|
|
sink = gst_pad_new ("sink", GST_PAD_SINK);
|
|
gst_pad_set_chain_function (sink, gst_check_chain_func);
|
|
gst_pad_set_active (sink, TRUE);
|
|
|
|
fail_unless (gst_pad_push_event (src,
|
|
gst_event_new_stream_start ("test")) == TRUE);
|
|
fail_unless (gst_pad_push_event (src,
|
|
gst_event_new_segment (&dummy_segment)) == TRUE);
|
|
|
|
fail_unless_equals_int (gst_pad_link (src, sink), GST_PAD_LINK_OK);
|
|
|
|
helper.probe_id = gst_pad_add_probe (src,
|
|
GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_BUFFER,
|
|
block_and_replace_buffer_probe_cb, &helper, NULL);
|
|
helper.probe_pad = src;
|
|
|
|
/* push a buffer so the events are propagated downstream */
|
|
flow = gst_pad_push (src, gst_buffer_new ());
|
|
|
|
g_thread_join (helper.thread);
|
|
|
|
fail_unless_equals_int (flow, GST_FLOW_OK);
|
|
|
|
/* no buffer should have made it through to the sink pad, and especially
|
|
* not a NULL pointer buffer */
|
|
fail_if (buffers && buffers->data == NULL);
|
|
fail_unless (buffers == NULL);
|
|
|
|
gst_check_drop_buffers ();
|
|
gst_object_unref (src);
|
|
gst_object_unref (sink);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
static GstPadProbeReturn
|
|
probe_block_a (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
|
|
{
|
|
return GST_PAD_PROBE_OK;
|
|
}
|
|
|
|
static GstPadProbeReturn
|
|
probe_block_b (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
|
|
{
|
|
gboolean *probe_b_called = user_data;
|
|
|
|
*probe_b_called = TRUE;
|
|
|
|
return GST_PAD_PROBE_OK;
|
|
}
|
|
|
|
static GstPadProbeReturn
|
|
probe_block_c (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
|
|
{
|
|
gboolean *probe_c_called = user_data;
|
|
|
|
*probe_c_called = TRUE;
|
|
|
|
return GST_PAD_PROBE_REMOVE;
|
|
}
|
|
|
|
GST_START_TEST (test_pad_probe_block_add_remove)
|
|
{
|
|
GstPad *pad;
|
|
GThread *thread;
|
|
gulong probe_a, probe_b;
|
|
gboolean probe_b_called = FALSE;
|
|
gboolean probe_c_called = FALSE;
|
|
|
|
pad = gst_pad_new ("src", GST_PAD_SRC);
|
|
fail_unless (pad != NULL);
|
|
|
|
gst_pad_set_active (pad, TRUE);
|
|
fail_unless (pad->num_probes == 0);
|
|
fail_unless (pad->num_blocked == 0);
|
|
|
|
fail_unless (gst_pad_push_event (pad,
|
|
gst_event_new_stream_start ("test")) == TRUE);
|
|
fail_unless (gst_pad_push_event (pad,
|
|
gst_event_new_segment (&dummy_segment)) == TRUE);
|
|
|
|
probe_a = gst_pad_add_probe (pad,
|
|
GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_BUFFER,
|
|
probe_block_a, NULL, NULL);
|
|
|
|
fail_unless (pad->num_probes == 1);
|
|
fail_unless (pad->num_blocked == 1);
|
|
|
|
thread = g_thread_try_new ("gst-check", (GThreadFunc) push_buffer_async,
|
|
pad, NULL);
|
|
|
|
/* wait for the block */
|
|
while (!gst_pad_is_blocking (pad)) {
|
|
g_usleep (10000);
|
|
}
|
|
|
|
probe_b = gst_pad_add_probe (pad,
|
|
GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_BUFFER,
|
|
probe_block_b, &probe_b_called, NULL);
|
|
|
|
gst_pad_remove_probe (pad, probe_a);
|
|
|
|
/* wait for the callback */
|
|
while (!probe_b_called) {
|
|
g_usleep (10000);
|
|
}
|
|
|
|
/* wait for the block */
|
|
while (!gst_pad_is_blocking (pad)) {
|
|
g_usleep (10000);
|
|
}
|
|
|
|
gst_pad_add_probe (pad,
|
|
GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_BUFFER,
|
|
probe_block_c, &probe_c_called, NULL);
|
|
|
|
gst_pad_remove_probe (pad, probe_b);
|
|
|
|
/* wait for the callback */
|
|
while (!probe_c_called) {
|
|
g_usleep (10000);
|
|
}
|
|
|
|
/* wait for the unblock */
|
|
while (gst_pad_is_blocking (pad)) {
|
|
g_usleep (10000);
|
|
}
|
|
|
|
gst_object_unref (pad);
|
|
|
|
g_thread_join (thread);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
static gboolean src_flush_start_probe_called = FALSE;
|
|
static gboolean src_flush_stop_probe_called = FALSE;
|
|
static gboolean sink_flush_start_probe_called = FALSE;
|
|
static gboolean sink_flush_stop_probe_called = FALSE;
|
|
|
|
static GstPadProbeReturn
|
|
flush_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
|
|
{
|
|
GstEvent *event;
|
|
|
|
if (!(GST_PAD_PROBE_INFO_TYPE (info) & GST_PAD_PROBE_TYPE_EVENT_FLUSH))
|
|
goto out;
|
|
|
|
event = gst_pad_probe_info_get_event (info);
|
|
switch (GST_EVENT_TYPE (event)) {
|
|
case GST_EVENT_FLUSH_START:
|
|
if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC)
|
|
src_flush_start_probe_called = TRUE;
|
|
else
|
|
sink_flush_start_probe_called = TRUE;
|
|
break;
|
|
case GST_EVENT_FLUSH_STOP:
|
|
if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC)
|
|
src_flush_stop_probe_called = TRUE;
|
|
else
|
|
sink_flush_stop_probe_called = TRUE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
out:
|
|
return GST_PAD_PROBE_OK;
|
|
}
|
|
|
|
GST_START_TEST (test_pad_probe_flush_events)
|
|
{
|
|
GstPad *src, *sink;
|
|
|
|
src = gst_pad_new ("src", GST_PAD_SRC);
|
|
sink = gst_pad_new ("sink", GST_PAD_SINK);
|
|
gst_pad_set_chain_function (sink, gst_check_chain_func);
|
|
gst_pad_set_active (src, TRUE);
|
|
gst_pad_set_active (sink, TRUE);
|
|
|
|
fail_unless (gst_pad_push_event (src,
|
|
gst_event_new_stream_start ("test")) == TRUE);
|
|
fail_unless (gst_pad_push_event (src,
|
|
gst_event_new_segment (&dummy_segment)) == TRUE);
|
|
|
|
fail_unless (gst_pad_link (src, sink) == GST_PAD_LINK_OK);
|
|
|
|
gst_pad_add_probe (src,
|
|
GST_PAD_PROBE_TYPE_PUSH | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM |
|
|
GST_PAD_PROBE_TYPE_EVENT_FLUSH, flush_probe_cb, NULL, NULL);
|
|
gst_pad_add_probe (sink,
|
|
GST_PAD_PROBE_TYPE_PUSH | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM |
|
|
GST_PAD_PROBE_TYPE_EVENT_FLUSH, flush_probe_cb, NULL, NULL);
|
|
|
|
gst_pad_push_event (src, gst_event_new_flush_start ());
|
|
gst_pad_push_event (src, gst_event_new_flush_stop (TRUE));
|
|
|
|
fail_unless (gst_pad_push_event (src,
|
|
gst_event_new_segment (&dummy_segment)) == TRUE);
|
|
|
|
/* push a buffer so the events are propagated downstream */
|
|
gst_pad_push (src, gst_buffer_new ());
|
|
|
|
fail_unless (src_flush_start_probe_called);
|
|
fail_unless (src_flush_stop_probe_called);
|
|
fail_unless (sink_flush_start_probe_called);
|
|
fail_unless (sink_flush_stop_probe_called);
|
|
|
|
gst_check_drop_buffers ();
|
|
gst_object_unref (src);
|
|
gst_object_unref (sink);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
static gboolean probe_was_called;
|
|
|
|
static GstPadProbeReturn
|
|
flush_events_only_probe (GstPad * pad, GstPadProbeInfo * info, gpointer data)
|
|
{
|
|
GST_LOG_OBJECT (pad, "%" GST_PTR_FORMAT, GST_PAD_PROBE_INFO_DATA (info));
|
|
|
|
probe_was_called = TRUE;
|
|
|
|
return GST_PAD_PROBE_OK;
|
|
}
|
|
|
|
GST_START_TEST (test_pad_probe_flush_events_only)
|
|
{
|
|
GstPad *src, *sink;
|
|
|
|
src = gst_pad_new ("src", GST_PAD_SRC);
|
|
sink = gst_pad_new ("sink", GST_PAD_SINK);
|
|
gst_pad_set_chain_function (sink, gst_check_chain_func);
|
|
gst_pad_set_active (src, TRUE);
|
|
gst_pad_set_active (sink, TRUE);
|
|
|
|
fail_unless (gst_pad_link (src, sink) == GST_PAD_LINK_OK);
|
|
|
|
fail_unless (gst_pad_push_event (src,
|
|
gst_event_new_stream_start ("test")) == TRUE);
|
|
|
|
gst_pad_add_probe (src, GST_PAD_PROBE_TYPE_EVENT_FLUSH,
|
|
flush_events_only_probe, NULL, NULL);
|
|
|
|
probe_was_called = FALSE;
|
|
fail_unless (gst_pad_push_event (src,
|
|
gst_event_new_segment (&dummy_segment)) == TRUE);
|
|
fail_if (probe_was_called);
|
|
|
|
fail_unless_equals_int (gst_pad_push (src, gst_buffer_new ()), GST_FLOW_OK);
|
|
fail_if (probe_was_called);
|
|
|
|
gst_pad_push_event (src, gst_event_new_flush_start ());
|
|
fail_unless (probe_was_called);
|
|
|
|
probe_was_called = FALSE;
|
|
gst_pad_push_event (src, gst_event_new_flush_stop (TRUE));
|
|
fail_unless (probe_was_called);
|
|
|
|
gst_check_drop_buffers ();
|
|
gst_object_unref (src);
|
|
gst_object_unref (sink);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
#define NUM_PROBES 4
|
|
static guint count;
|
|
|
|
static GstPadProbeReturn
|
|
order_others_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
|
|
{
|
|
*(guint *) (user_data) = ++count;
|
|
|
|
return GST_PAD_PROBE_REMOVE;
|
|
}
|
|
|
|
GST_START_TEST (test_pad_probe_call_order)
|
|
{
|
|
GstFlowReturn flow;
|
|
GstPad *src, *sink;
|
|
guint counters[NUM_PROBES];
|
|
guint i;
|
|
|
|
src = gst_pad_new ("src", GST_PAD_SRC);
|
|
gst_pad_set_active (src, TRUE);
|
|
sink = gst_pad_new ("sink", GST_PAD_SINK);
|
|
gst_pad_set_chain_function (sink, gst_check_chain_func);
|
|
gst_pad_set_active (sink, TRUE);
|
|
|
|
fail_unless (gst_pad_push_event (src,
|
|
gst_event_new_stream_start ("test")) == TRUE);
|
|
fail_unless (gst_pad_push_event (src,
|
|
gst_event_new_segment (&dummy_segment)) == TRUE);
|
|
|
|
fail_unless_equals_int (gst_pad_link (src, sink), GST_PAD_LINK_OK);
|
|
|
|
for (i = 0; i < NUM_PROBES; i++) {
|
|
gst_pad_add_probe (src,
|
|
GST_PAD_PROBE_TYPE_BUFFER, order_others_probe_cb, &(counters[i]), NULL);
|
|
}
|
|
|
|
/* push a buffer so the events are propagated downstream */
|
|
flow = gst_pad_push (src, gst_buffer_new ());
|
|
fail_unless_equals_int (flow, GST_FLOW_OK);
|
|
|
|
for (i = 0; i < NUM_PROBES; i++) {
|
|
fail_unless (counters[i] == i + 1);
|
|
}
|
|
|
|
gst_check_drop_buffers ();
|
|
gst_object_unref (src);
|
|
gst_object_unref (sink);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
static GstPadProbeReturn
|
|
buffers_probe_handled (GstPad * pad, GstPadProbeInfo * info, gpointer gp)
|
|
{
|
|
if (GST_PAD_PROBE_INFO_TYPE (info) & GST_PAD_PROBE_TYPE_BUFFER) {
|
|
GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER (info);
|
|
|
|
GST_DEBUG_OBJECT (pad, "buffer: %" GST_PTR_FORMAT ", refcount: %d",
|
|
buffer, (GST_MINI_OBJECT (buffer))->refcount);
|
|
gst_buffer_unref (buffer);
|
|
}
|
|
|
|
return GST_PAD_PROBE_HANDLED;
|
|
}
|
|
|
|
static GstPadProbeReturn
|
|
buffers_probe_drop (GstPad * pad, GstPadProbeInfo * info, gboolean * called)
|
|
{
|
|
if (GST_PAD_PROBE_INFO_TYPE (info) & GST_PAD_PROBE_TYPE_BUFFER) {
|
|
GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER (info);
|
|
|
|
GST_DEBUG_OBJECT (pad, "buffer: %" GST_PTR_FORMAT ", refcount: %d",
|
|
buffer, (GST_MINI_OBJECT (buffer))->refcount);
|
|
*called = TRUE;
|
|
}
|
|
|
|
return GST_PAD_PROBE_DROP;
|
|
}
|
|
|
|
GST_START_TEST (test_pad_probe_handled_and_drop)
|
|
{
|
|
GstFlowReturn flow;
|
|
GstPad *src, *sink;
|
|
gboolean called;
|
|
|
|
src = gst_pad_new ("src", GST_PAD_SRC);
|
|
gst_pad_set_active (src, TRUE);
|
|
sink = gst_pad_new ("sink", GST_PAD_SINK);
|
|
gst_pad_set_chain_function (sink, gst_check_chain_func);
|
|
gst_pad_set_active (sink, TRUE);
|
|
|
|
fail_unless (gst_pad_push_event (src,
|
|
gst_event_new_stream_start ("test")) == TRUE);
|
|
fail_unless (gst_pad_push_event (src,
|
|
gst_event_new_segment (&dummy_segment)) == TRUE);
|
|
|
|
fail_unless_equals_int (gst_pad_link (src, sink), GST_PAD_LINK_OK);
|
|
|
|
gst_pad_add_probe (src, GST_PAD_PROBE_TYPE_BUFFER,
|
|
(GstPadProbeCallback) buffers_probe_handled, NULL, NULL);
|
|
gst_pad_add_probe (src, GST_PAD_PROBE_TYPE_BUFFER,
|
|
(GstPadProbeCallback) buffers_probe_drop, &called, NULL);
|
|
|
|
called = FALSE;
|
|
flow = gst_pad_push (src, gst_buffer_new ());
|
|
fail_unless_equals_int (flow, GST_FLOW_OK);
|
|
fail_if (called);
|
|
|
|
/* no buffer should have made it through to the sink pad, and especially
|
|
* not a NULL pointer buffer */
|
|
fail_if (buffers && buffers->data == NULL);
|
|
fail_unless (buffers == NULL);
|
|
|
|
gst_object_unref (src);
|
|
gst_object_unref (sink);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
static gboolean got_notify;
|
|
|
|
static void
|
|
caps_notify (GstPad * pad, GParamSpec * spec, gpointer data)
|
|
{
|
|
got_notify = TRUE;
|
|
}
|
|
|
|
static void
|
|
test_queue_src_caps_notify (gboolean link_queue)
|
|
{
|
|
GstElement *queue;
|
|
GstPad *src, *sink, *another_pad;
|
|
GstCaps *caps;
|
|
|
|
queue = gst_element_factory_make ("queue", NULL);
|
|
fail_unless (queue != NULL);
|
|
|
|
src = gst_element_get_static_pad (queue, "src");
|
|
fail_unless (src != NULL);
|
|
|
|
sink = gst_element_get_static_pad (queue, "sink");
|
|
fail_unless (sink != NULL);
|
|
|
|
if (link_queue) {
|
|
another_pad = gst_pad_new ("sink", GST_PAD_SINK);
|
|
fail_unless (another_pad != NULL);
|
|
gst_pad_set_active (another_pad, TRUE);
|
|
|
|
gst_pad_link_full (src, another_pad, GST_PAD_LINK_CHECK_NOTHING);
|
|
} else {
|
|
another_pad = NULL;
|
|
}
|
|
|
|
gst_element_set_state (queue, GST_STATE_PLAYING);
|
|
|
|
got_notify = FALSE;
|
|
|
|
g_signal_connect (src, "notify::caps", G_CALLBACK (caps_notify), NULL);
|
|
|
|
caps = gst_caps_from_string ("caps");
|
|
gst_pad_send_event (sink, gst_event_new_caps (caps));
|
|
gst_caps_unref (caps);
|
|
|
|
while (got_notify == FALSE)
|
|
g_usleep (10000);
|
|
|
|
gst_element_set_state (queue, GST_STATE_NULL);
|
|
|
|
gst_object_unref (src);
|
|
gst_object_unref (sink);
|
|
gst_object_unref (queue);
|
|
if (another_pad) {
|
|
gst_object_unref (another_pad);
|
|
}
|
|
}
|
|
|
|
GST_START_TEST (test_queue_src_caps_notify_linked)
|
|
{
|
|
test_queue_src_caps_notify (TRUE);
|
|
}
|
|
|
|
GST_END_TEST
|
|
GST_START_TEST (test_queue_src_caps_notify_not_linked)
|
|
{
|
|
/* This test will fail because queue doesn't set the caps
|
|
on src pad unless it is linked */
|
|
test_queue_src_caps_notify (FALSE);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
#if 0
|
|
static void
|
|
block_async_second (GstPad * pad, gboolean blocked, gpointer user_data)
|
|
{
|
|
gst_pad_set_blocked (pad, FALSE, unblock_async_cb, NULL, NULL);
|
|
}
|
|
|
|
static void
|
|
block_async_first (GstPad * pad, gboolean blocked, gpointer user_data)
|
|
{
|
|
static int n_calls = 0;
|
|
gboolean *bool_user_data = (gboolean *) user_data;
|
|
|
|
if (++n_calls > 1)
|
|
/* we expect this callback to be called only once */
|
|
g_warn_if_reached ();
|
|
|
|
*bool_user_data = blocked;
|
|
|
|
/* replace block_async_first with block_async_second so next time the pad is
|
|
* blocked the latter should be called */
|
|
gst_pad_set_blocked (pad, TRUE, block_async_second, NULL, NULL);
|
|
|
|
/* unblock temporarily, in the next push block_async_second should be called
|
|
*/
|
|
gst_pad_push_event (pad, gst_event_new_flush_start ());
|
|
}
|
|
|
|
GST_START_TEST (test_block_async_replace_callback)
|
|
{
|
|
GstPad *pad;
|
|
gboolean blocked;
|
|
|
|
pad = gst_pad_new ("src", GST_PAD_SRC);
|
|
fail_unless (pad != NULL);
|
|
gst_pad_set_active (pad, TRUE);
|
|
|
|
gst_pad_set_blocked (pad, TRUE, block_async_first, &blocked, NULL);
|
|
blocked = FALSE;
|
|
|
|
gst_pad_push (pad, gst_buffer_new ());
|
|
fail_unless (blocked == TRUE);
|
|
/* block_async_first flushes to unblock */
|
|
gst_pad_push_event (pad, gst_event_new_flush_stop ());
|
|
|
|
/* push again, this time block_async_second should be called */
|
|
gst_pad_push (pad, gst_buffer_new ());
|
|
fail_unless (blocked == TRUE);
|
|
|
|
gst_object_unref (pad);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
#endif
|
|
|
|
static void
|
|
block_async_full_destroy (gpointer user_data)
|
|
{
|
|
gint *state = (gint *) user_data;
|
|
|
|
fail_unless (*state < 2);
|
|
|
|
GST_DEBUG ("setting state to 2");
|
|
*state = 2;
|
|
}
|
|
|
|
static GstPadProbeReturn
|
|
block_async_full_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
|
|
{
|
|
*(gint *) user_data = (gint) TRUE;
|
|
|
|
gst_pad_push_event (pad, gst_event_new_flush_start ());
|
|
GST_DEBUG ("setting state to 1");
|
|
|
|
return GST_PAD_PROBE_OK;
|
|
}
|
|
|
|
GST_START_TEST (test_block_async_full_destroy)
|
|
{
|
|
GstPad *pad;
|
|
/* 0 = unblocked, 1 = blocked, 2 = destroyed */
|
|
gint state = 0;
|
|
gulong id;
|
|
|
|
pad = gst_pad_new ("src", GST_PAD_SRC);
|
|
fail_unless (pad != NULL);
|
|
gst_pad_set_active (pad, TRUE);
|
|
|
|
fail_unless (gst_pad_push_event (pad,
|
|
gst_event_new_stream_start ("test")) == TRUE);
|
|
fail_unless (gst_pad_push_event (pad,
|
|
gst_event_new_segment (&dummy_segment)) == TRUE);
|
|
|
|
id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BLOCK, block_async_full_cb,
|
|
&state, block_async_full_destroy);
|
|
fail_unless (state == 0);
|
|
|
|
gst_pad_push (pad, gst_buffer_new ());
|
|
/* block_async_full_cb sets state to 1 and then flushes to unblock temporarily
|
|
*/
|
|
fail_unless (state == 1);
|
|
gst_pad_push_event (pad, gst_event_new_flush_stop (TRUE));
|
|
|
|
/* unblock callback is called */
|
|
gst_pad_remove_probe (pad, id);
|
|
fail_unless (state == 2);
|
|
|
|
gst_object_unref (pad);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_block_async_full_destroy_dispose)
|
|
{
|
|
GstPad *pad;
|
|
/* 0 = unblocked, 1 = blocked, 2 = destroyed */
|
|
gint state = 0;
|
|
|
|
pad = gst_pad_new ("src", GST_PAD_SRC);
|
|
fail_unless (pad != NULL);
|
|
gst_pad_set_active (pad, TRUE);
|
|
|
|
fail_unless (gst_pad_push_event (pad,
|
|
gst_event_new_stream_start ("test")) == TRUE);
|
|
fail_unless (gst_pad_push_event (pad,
|
|
gst_event_new_segment (&dummy_segment)) == TRUE);
|
|
|
|
(void) gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BLOCK, block_async_full_cb,
|
|
&state, block_async_full_destroy);
|
|
|
|
gst_pad_push (pad, gst_buffer_new ());
|
|
/* block_async_full_cb sets state to 1 and then flushes to unblock temporarily
|
|
*/
|
|
fail_unless_equals_int (state, 1);
|
|
gst_pad_push_event (pad, gst_event_new_flush_stop (TRUE));
|
|
|
|
/* gst_BLOCK calls the destroy_notify function if necessary */
|
|
gst_object_unref (pad);
|
|
|
|
fail_unless_equals_int (state, 2);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
|
|
#if 0
|
|
static void
|
|
unblock_async_no_flush_cb (GstPad * pad, gboolean blocked, gpointer user_data)
|
|
{
|
|
gboolean *bool_user_data = (gboolean *) user_data;
|
|
|
|
/* here we should have blocked == 1 unblocked == 0 */
|
|
|
|
fail_unless (blocked == FALSE);
|
|
|
|
fail_unless (bool_user_data[0] == TRUE);
|
|
fail_unless (bool_user_data[1] == TRUE);
|
|
fail_unless (bool_user_data[2] == FALSE);
|
|
|
|
bool_user_data[2] = TRUE;
|
|
}
|
|
#endif
|
|
|
|
|
|
#if 0
|
|
static void
|
|
unblock_async_not_called (GstPad * pad, gboolean blocked, gpointer user_data)
|
|
{
|
|
g_warn_if_reached ();
|
|
}
|
|
#endif
|
|
|
|
static GstPadProbeReturn
|
|
block_async_second_no_flush (GstPad * pad, GstPadProbeInfo * info,
|
|
gpointer user_data)
|
|
{
|
|
gboolean *bool_user_data = (gboolean *) user_data;
|
|
|
|
GST_DEBUG ("second probe called");
|
|
|
|
fail_unless (info->type & GST_PAD_PROBE_TYPE_BLOCK);
|
|
|
|
fail_unless (bool_user_data[0] == TRUE);
|
|
fail_unless (bool_user_data[1] == FALSE);
|
|
fail_unless (bool_user_data[2] == FALSE);
|
|
|
|
bool_user_data[1] = TRUE;
|
|
|
|
GST_DEBUG ("removing second probe with id %lu", id);
|
|
gst_pad_remove_probe (pad, id);
|
|
|
|
return GST_PAD_PROBE_OK;
|
|
}
|
|
|
|
static GstPadProbeReturn
|
|
block_async_first_no_flush (GstPad * pad, GstPadProbeInfo * info,
|
|
gpointer user_data)
|
|
{
|
|
static int n_calls = 0;
|
|
gboolean *bool_user_data = (gboolean *) user_data;
|
|
|
|
fail_unless (info->type & GST_PAD_PROBE_TYPE_BLOCK);
|
|
|
|
GST_DEBUG ("first probe called");
|
|
|
|
if (++n_calls > 1)
|
|
/* we expect this callback to be called only once */
|
|
g_warn_if_reached ();
|
|
|
|
*bool_user_data = TRUE;
|
|
|
|
fail_unless (bool_user_data[0] == TRUE);
|
|
fail_unless (bool_user_data[1] == FALSE);
|
|
fail_unless (bool_user_data[2] == FALSE);
|
|
|
|
GST_DEBUG ("removing first probe with id %lu", id);
|
|
gst_pad_remove_probe (pad, id);
|
|
|
|
GST_DEBUG ("adding second probe");
|
|
/* replace block_async_first with block_async_second so next time the pad is
|
|
* blocked the latter should be called */
|
|
id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BLOCK,
|
|
block_async_second_no_flush, user_data, NULL);
|
|
GST_DEBUG ("added probe with id %lu", id);
|
|
|
|
return GST_PAD_PROBE_OK;
|
|
}
|
|
|
|
GST_START_TEST (test_block_async_replace_callback_no_flush)
|
|
{
|
|
GstPad *pad;
|
|
gboolean bool_user_data[3] = { FALSE, FALSE, FALSE };
|
|
|
|
pad = gst_pad_new ("src", GST_PAD_SRC);
|
|
fail_unless (pad != NULL);
|
|
gst_pad_set_active (pad, TRUE);
|
|
|
|
fail_unless (gst_pad_push_event (pad,
|
|
gst_event_new_stream_start ("test")) == TRUE);
|
|
fail_unless (gst_pad_push_event (pad,
|
|
gst_event_new_segment (&dummy_segment)) == TRUE);
|
|
|
|
GST_DEBUG ("adding probe");
|
|
id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BLOCK,
|
|
block_async_first_no_flush, bool_user_data, NULL);
|
|
GST_DEBUG ("added probe with id %lu", id);
|
|
fail_if (id == 0);
|
|
|
|
GST_DEBUG ("pushing buffer");
|
|
gst_pad_push (pad, gst_buffer_new ());
|
|
fail_unless (bool_user_data[0] == TRUE);
|
|
fail_unless (bool_user_data[1] == TRUE);
|
|
fail_unless (bool_user_data[2] == FALSE);
|
|
|
|
gst_object_unref (pad);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
static gint sticky_count;
|
|
|
|
static gboolean
|
|
test_sticky_events_handler (GstPad * pad, GstObject * parent, GstEvent * event)
|
|
{
|
|
GST_DEBUG_OBJECT (pad, "received event %" GST_PTR_FORMAT, event);
|
|
|
|
switch (sticky_count) {
|
|
case 0:
|
|
fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_START);
|
|
break;
|
|
case 1:
|
|
{
|
|
GstCaps *caps;
|
|
GstStructure *s;
|
|
|
|
fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_CAPS);
|
|
|
|
gst_event_parse_caps (event, &caps);
|
|
fail_unless (gst_caps_get_size (caps) == 1);
|
|
s = gst_caps_get_structure (caps, 0);
|
|
fail_unless (gst_structure_has_name (s, "foo/baz"));
|
|
break;
|
|
}
|
|
case 2:
|
|
fail_unless (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT);
|
|
break;
|
|
default:
|
|
fail_unless (FALSE);
|
|
break;
|
|
}
|
|
|
|
gst_event_unref (event);
|
|
sticky_count++;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
test_sticky_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
|
|
{
|
|
gst_buffer_unref (buffer);
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
GST_START_TEST (test_sticky_events)
|
|
{
|
|
GstPad *srcpad, *sinkpad;
|
|
GstCaps *caps;
|
|
GstSegment seg;
|
|
gchar *id;
|
|
|
|
/* make unlinked srcpad */
|
|
srcpad = gst_pad_new ("src", GST_PAD_SRC);
|
|
fail_unless (srcpad != NULL);
|
|
gst_pad_set_active (srcpad, TRUE);
|
|
|
|
/* test stream-start */
|
|
fail_unless (gst_pad_get_stream_id (srcpad) == NULL);
|
|
|
|
/* push an event, it should be sticky on the srcpad */
|
|
fail_unless (gst_pad_push_event (srcpad,
|
|
gst_event_new_stream_start ("test")) == TRUE);
|
|
|
|
/* let's see if it stuck */
|
|
id = gst_pad_get_stream_id (srcpad);
|
|
fail_unless_equals_string (id, "test");
|
|
g_free (id);
|
|
|
|
/* make a caps event */
|
|
caps = gst_caps_new_empty_simple ("foo/bar");
|
|
gst_pad_push_event (srcpad, gst_event_new_caps (caps));
|
|
gst_caps_unref (caps);
|
|
|
|
/* make segment event */
|
|
gst_segment_init (&seg, GST_FORMAT_TIME);
|
|
gst_pad_push_event (srcpad, gst_event_new_segment (&seg));
|
|
|
|
/* now make a sinkpad */
|
|
sinkpad = gst_pad_new ("sink", GST_PAD_SINK);
|
|
fail_unless (sinkpad != NULL);
|
|
sticky_count = 0;
|
|
gst_pad_set_event_function (sinkpad, test_sticky_events_handler);
|
|
gst_pad_set_chain_function (sinkpad, test_sticky_chain);
|
|
fail_unless (sticky_count == 0);
|
|
gst_pad_set_active (sinkpad, TRUE);
|
|
|
|
/* link the pads */
|
|
gst_pad_link (srcpad, sinkpad);
|
|
/* should not trigger events */
|
|
fail_unless (sticky_count == 0);
|
|
|
|
/* caps replaces old caps event at position 2, the pushes all
|
|
* pending events */
|
|
caps = gst_caps_new_empty_simple ("foo/baz");
|
|
gst_pad_push_event (srcpad, gst_event_new_caps (caps));
|
|
gst_caps_unref (caps);
|
|
|
|
/* should have triggered 2 events, the segment event is still pending */
|
|
fail_unless_equals_int (sticky_count, 2);
|
|
|
|
fail_unless (gst_pad_push (srcpad, gst_buffer_new ()) == GST_FLOW_OK);
|
|
|
|
/* should have triggered 3 events */
|
|
fail_unless_equals_int (sticky_count, 3);
|
|
|
|
gst_object_unref (srcpad);
|
|
gst_object_unref (sinkpad);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
static GstFlowReturn next_return;
|
|
|
|
static GstFlowReturn
|
|
test_lastflow_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
|
|
{
|
|
gst_buffer_unref (buffer);
|
|
return next_return;
|
|
}
|
|
|
|
GST_START_TEST (test_last_flow_return_push)
|
|
{
|
|
GstPad *srcpad, *sinkpad;
|
|
GstSegment seg;
|
|
|
|
srcpad = gst_pad_new ("src", GST_PAD_SRC);
|
|
fail_unless (srcpad != NULL);
|
|
sinkpad = gst_pad_new ("sink", GST_PAD_SINK);
|
|
fail_unless (sinkpad != NULL);
|
|
gst_pad_set_chain_function (sinkpad, test_lastflow_chain);
|
|
gst_pad_link (srcpad, sinkpad);
|
|
|
|
/* initial value is flushing */
|
|
fail_unless (gst_pad_get_last_flow_return (srcpad) == GST_FLOW_FLUSHING);
|
|
|
|
/* when active it goes to ok */
|
|
gst_pad_set_active (srcpad, TRUE);
|
|
fail_unless (gst_pad_get_last_flow_return (srcpad) == GST_FLOW_OK);
|
|
gst_pad_set_active (sinkpad, TRUE);
|
|
|
|
/* startup events */
|
|
gst_pad_push_event (srcpad, gst_event_new_stream_start ("test"));
|
|
gst_segment_init (&seg, GST_FORMAT_TIME);
|
|
gst_pad_push_event (srcpad, gst_event_new_segment (&seg));
|
|
|
|
|
|
/* push Ok */
|
|
next_return = GST_FLOW_OK;
|
|
fail_unless (gst_pad_push (srcpad, gst_buffer_new ()) == GST_FLOW_OK);
|
|
fail_unless (gst_pad_get_last_flow_return (srcpad) == GST_FLOW_OK);
|
|
|
|
/* push not-linked */
|
|
next_return = GST_FLOW_NOT_LINKED;
|
|
fail_unless (gst_pad_push (srcpad, gst_buffer_new ()) == GST_FLOW_NOT_LINKED);
|
|
fail_unless (gst_pad_get_last_flow_return (srcpad) == GST_FLOW_NOT_LINKED);
|
|
|
|
/* push not-linked */
|
|
next_return = GST_FLOW_NOT_NEGOTIATED;
|
|
fail_unless (gst_pad_push (srcpad,
|
|
gst_buffer_new ()) == GST_FLOW_NOT_NEGOTIATED);
|
|
fail_unless (gst_pad_get_last_flow_return (srcpad) ==
|
|
GST_FLOW_NOT_NEGOTIATED);
|
|
|
|
/* push error */
|
|
next_return = GST_FLOW_ERROR;
|
|
fail_unless (gst_pad_push (srcpad, gst_buffer_new ()) == GST_FLOW_ERROR);
|
|
fail_unless (gst_pad_get_last_flow_return (srcpad) == GST_FLOW_ERROR);
|
|
|
|
/* back to ok */
|
|
next_return = GST_FLOW_OK;
|
|
fail_unless (gst_pad_push (srcpad, gst_buffer_new ()) == GST_FLOW_OK);
|
|
fail_unless (gst_pad_get_last_flow_return (srcpad) == GST_FLOW_OK);
|
|
|
|
/* unlinked push */
|
|
gst_pad_unlink (srcpad, sinkpad);
|
|
fail_unless (gst_pad_push (srcpad, gst_buffer_new ()) == GST_FLOW_NOT_LINKED);
|
|
fail_unless (gst_pad_get_last_flow_return (srcpad) == GST_FLOW_NOT_LINKED);
|
|
|
|
gst_pad_link (srcpad, sinkpad);
|
|
fail_unless (gst_pad_push_event (srcpad, gst_event_new_eos ()));
|
|
fail_unless (gst_pad_get_last_flow_return (srcpad) == GST_FLOW_EOS);
|
|
|
|
gst_object_unref (srcpad);
|
|
gst_object_unref (sinkpad);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
static GstFlowReturn
|
|
test_lastflow_getrange (GstPad * pad, GstObject * parent, guint64 offset,
|
|
guint length, GstBuffer ** buf)
|
|
{
|
|
if (next_return == GST_FLOW_OK)
|
|
*buf = gst_buffer_new ();
|
|
else
|
|
*buf = NULL;
|
|
return next_return;
|
|
}
|
|
|
|
static gboolean
|
|
test_lastflow_activate_pull_func (GstPad * pad, GstObject * object)
|
|
{
|
|
return gst_pad_activate_mode (pad, GST_PAD_MODE_PULL, TRUE);
|
|
}
|
|
|
|
GST_START_TEST (test_last_flow_return_pull)
|
|
{
|
|
GstPad *srcpad, *sinkpad;
|
|
GstBuffer *buf = NULL;
|
|
|
|
srcpad = gst_pad_new ("src", GST_PAD_SRC);
|
|
fail_unless (srcpad != NULL);
|
|
sinkpad = gst_pad_new ("sink", GST_PAD_SINK);
|
|
fail_unless (sinkpad != NULL);
|
|
gst_pad_set_getrange_function (srcpad, test_lastflow_getrange);
|
|
gst_pad_set_activate_function (sinkpad, test_lastflow_activate_pull_func);
|
|
gst_pad_link (srcpad, sinkpad);
|
|
|
|
/* initial value is flushing */
|
|
fail_unless (gst_pad_get_last_flow_return (sinkpad) == GST_FLOW_FLUSHING);
|
|
|
|
/* when active it goes to ok */
|
|
gst_pad_set_active (sinkpad, TRUE);
|
|
fail_unless (gst_pad_get_last_flow_return (sinkpad) == GST_FLOW_OK);
|
|
gst_pad_set_active (srcpad, TRUE);
|
|
|
|
/* pull Ok */
|
|
next_return = GST_FLOW_OK;
|
|
fail_unless (gst_pad_pull_range (sinkpad, 0, 1, &buf) == GST_FLOW_OK);
|
|
fail_unless (gst_pad_get_last_flow_return (sinkpad) == GST_FLOW_OK);
|
|
gst_buffer_unref (buf);
|
|
buf = NULL;
|
|
|
|
/* pull not-linked */
|
|
next_return = GST_FLOW_NOT_LINKED;
|
|
fail_unless (gst_pad_pull_range (sinkpad, 0, 1, &buf) == GST_FLOW_NOT_LINKED);
|
|
fail_unless (gst_pad_get_last_flow_return (sinkpad) == GST_FLOW_NOT_LINKED);
|
|
|
|
/* pull error */
|
|
next_return = GST_FLOW_ERROR;
|
|
fail_unless (gst_pad_pull_range (sinkpad, 0, 1, &buf) == GST_FLOW_ERROR);
|
|
fail_unless (gst_pad_get_last_flow_return (sinkpad) == GST_FLOW_ERROR);
|
|
|
|
/* pull not-nego */
|
|
next_return = GST_FLOW_NOT_NEGOTIATED;
|
|
fail_unless (gst_pad_pull_range (sinkpad, 0, 1,
|
|
&buf) == GST_FLOW_NOT_NEGOTIATED);
|
|
fail_unless (gst_pad_get_last_flow_return (sinkpad) ==
|
|
GST_FLOW_NOT_NEGOTIATED);
|
|
|
|
/* pull ok again */
|
|
next_return = GST_FLOW_OK;
|
|
fail_unless (gst_pad_pull_range (sinkpad, 0, 1, &buf) == GST_FLOW_OK);
|
|
fail_unless (gst_pad_get_last_flow_return (sinkpad) == GST_FLOW_OK);
|
|
gst_buffer_unref (buf);
|
|
buf = NULL;
|
|
|
|
/* unlinked pads */
|
|
gst_pad_unlink (srcpad, sinkpad);
|
|
fail_unless (gst_pad_pull_range (sinkpad, 0, 1, &buf) == GST_FLOW_NOT_LINKED);
|
|
fail_unless (gst_pad_get_last_flow_return (sinkpad) == GST_FLOW_NOT_LINKED);
|
|
|
|
/* eos */
|
|
gst_pad_link (srcpad, sinkpad);
|
|
next_return = GST_FLOW_EOS;
|
|
fail_unless (gst_pad_pull_range (sinkpad, 0, 1, &buf) == GST_FLOW_EOS);
|
|
fail_unless (gst_pad_get_last_flow_return (sinkpad) == GST_FLOW_EOS);
|
|
|
|
gst_object_unref (srcpad);
|
|
gst_object_unref (sinkpad);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_flush_stop_inactive)
|
|
{
|
|
GstPad *sinkpad, *srcpad;
|
|
|
|
sinkpad = gst_pad_new ("sink", GST_PAD_SINK);
|
|
fail_unless (sinkpad != NULL);
|
|
|
|
/* new pads are inactive and flushing */
|
|
fail_if (GST_PAD_IS_ACTIVE (sinkpad));
|
|
fail_unless (GST_PAD_IS_FLUSHING (sinkpad));
|
|
|
|
/* this should fail, pad is inactive */
|
|
fail_if (gst_pad_send_event (sinkpad, gst_event_new_flush_stop (FALSE)));
|
|
|
|
/* nothing should have changed */
|
|
fail_if (GST_PAD_IS_ACTIVE (sinkpad));
|
|
fail_unless (GST_PAD_IS_FLUSHING (sinkpad));
|
|
|
|
gst_pad_set_active (sinkpad, TRUE);
|
|
|
|
/* pad is now active an not flushing anymore */
|
|
fail_unless (GST_PAD_IS_ACTIVE (sinkpad));
|
|
fail_if (GST_PAD_IS_FLUSHING (sinkpad));
|
|
|
|
/* do flush, does not deactivate the pad */
|
|
fail_unless (gst_pad_send_event (sinkpad, gst_event_new_flush_start ()));
|
|
fail_unless (GST_PAD_IS_ACTIVE (sinkpad));
|
|
fail_unless (GST_PAD_IS_FLUSHING (sinkpad));
|
|
|
|
fail_unless (gst_pad_send_event (sinkpad, gst_event_new_flush_stop (FALSE)));
|
|
fail_unless (GST_PAD_IS_ACTIVE (sinkpad));
|
|
fail_if (GST_PAD_IS_FLUSHING (sinkpad));
|
|
|
|
gst_pad_set_active (sinkpad, FALSE);
|
|
fail_if (GST_PAD_IS_ACTIVE (sinkpad));
|
|
fail_unless (GST_PAD_IS_FLUSHING (sinkpad));
|
|
|
|
gst_object_unref (sinkpad);
|
|
|
|
/* we should not be able to push on an inactive srcpad */
|
|
srcpad = gst_pad_new ("src", GST_PAD_SRC);
|
|
fail_unless (srcpad != NULL);
|
|
|
|
fail_if (GST_PAD_IS_ACTIVE (srcpad));
|
|
fail_unless (GST_PAD_IS_FLUSHING (srcpad));
|
|
|
|
fail_if (gst_pad_push_event (srcpad, gst_event_new_flush_stop (FALSE)));
|
|
|
|
/* should still be inactive and flushing */
|
|
fail_if (GST_PAD_IS_ACTIVE (srcpad));
|
|
fail_unless (GST_PAD_IS_FLUSHING (srcpad));
|
|
|
|
gst_pad_set_active (srcpad, TRUE);
|
|
|
|
/* pad is now active an not flushing anymore */
|
|
fail_unless (GST_PAD_IS_ACTIVE (srcpad));
|
|
fail_if (GST_PAD_IS_FLUSHING (srcpad));
|
|
|
|
/* do flush, does not deactivate the pad */
|
|
fail_if (gst_pad_push_event (srcpad, gst_event_new_flush_start ()));
|
|
fail_unless (GST_PAD_IS_ACTIVE (srcpad));
|
|
fail_unless (GST_PAD_IS_FLUSHING (srcpad));
|
|
|
|
fail_if (gst_pad_push_event (srcpad, gst_event_new_flush_stop (FALSE)));
|
|
fail_unless (GST_PAD_IS_ACTIVE (srcpad));
|
|
fail_if (GST_PAD_IS_FLUSHING (srcpad));
|
|
|
|
gst_pad_set_active (srcpad, FALSE);
|
|
fail_if (GST_PAD_IS_ACTIVE (srcpad));
|
|
fail_unless (GST_PAD_IS_FLUSHING (srcpad));
|
|
|
|
gst_object_unref (srcpad);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
/* For proxy caps flag tests */
|
|
|
|
typedef struct _GstProxyTestElement GstProxyTestElement;
|
|
typedef struct _GstProxyTestElementClass GstProxyTestElementClass;
|
|
|
|
struct _GstProxyTestElement
|
|
{
|
|
GstElement element;
|
|
};
|
|
|
|
struct _GstProxyTestElementClass
|
|
{
|
|
GstElementClass parent_class;
|
|
};
|
|
|
|
G_GNUC_INTERNAL GType gst_proxytestelement_get_type (void);
|
|
|
|
static GstStaticPadTemplate proxytestelement_peer_template =
|
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
|
GST_PAD_SINK,
|
|
GST_PAD_ALWAYS,
|
|
GST_STATIC_CAPS ("test/proxy, option=(int)1"));
|
|
|
|
static GstStaticPadTemplate proxytestelement_peer_incompatible_template =
|
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
|
GST_PAD_SINK,
|
|
GST_PAD_ALWAYS,
|
|
GST_STATIC_CAPS ("test/proxy-incompatible"));
|
|
|
|
static GstStaticPadTemplate proxytestelement_sink_template =
|
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
|
GST_PAD_SINK,
|
|
GST_PAD_ALWAYS,
|
|
GST_STATIC_CAPS ("test/proxy"));
|
|
|
|
static GstStaticPadTemplate proxytestelement_src_template =
|
|
GST_STATIC_PAD_TEMPLATE ("src",
|
|
GST_PAD_SRC,
|
|
GST_PAD_ALWAYS,
|
|
GST_STATIC_CAPS_ANY);
|
|
|
|
G_DEFINE_TYPE (GstProxyTestElement, gst_proxytestelement, GST_TYPE_ELEMENT);
|
|
|
|
static void
|
|
gst_proxytestelement_class_init (GstProxyTestElementClass * klass)
|
|
{
|
|
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
|
|
|
|
gst_element_class_set_static_metadata (gstelement_class,
|
|
"Proxy Test Element", "Test", "Proxy test element",
|
|
"Thiago Santos <thiagoss@osg.samsung.com>");
|
|
|
|
gst_element_class_add_static_pad_template (gstelement_class,
|
|
&proxytestelement_sink_template);
|
|
}
|
|
|
|
static void
|
|
gst_proxytestelement_init (GstProxyTestElement * element)
|
|
{
|
|
GstPad *sinkpad;
|
|
sinkpad =
|
|
gst_pad_new_from_static_template (&proxytestelement_sink_template,
|
|
"sink");
|
|
GST_PAD_SET_PROXY_CAPS (sinkpad);
|
|
gst_element_add_pad (GST_ELEMENT_CAST (element), sinkpad);
|
|
}
|
|
|
|
GST_START_TEST (test_proxy_accept_caps_no_proxy)
|
|
{
|
|
GstElement *element;
|
|
GstPad *sinkpad;
|
|
GstCaps *caps;
|
|
|
|
gst_element_register (NULL, "proxytestelement", GST_RANK_NONE,
|
|
gst_proxytestelement_get_type ());
|
|
element = gst_element_factory_make ("proxytestelement", NULL);
|
|
sinkpad = gst_element_get_static_pad (element, "sink");
|
|
|
|
gst_element_set_state (element, GST_STATE_PLAYING);
|
|
|
|
caps = gst_caps_from_string ("test/proxy");
|
|
fail_unless (gst_pad_query_accept_caps (sinkpad, caps));
|
|
gst_caps_unref (caps);
|
|
|
|
caps = gst_caps_from_string ("test/bad");
|
|
fail_if (gst_pad_query_accept_caps (sinkpad, caps));
|
|
gst_caps_unref (caps);
|
|
|
|
gst_object_unref (sinkpad);
|
|
gst_element_set_state (element, GST_STATE_NULL);
|
|
gst_object_unref (element);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
|
|
GST_START_TEST (test_proxy_accept_caps_with_proxy)
|
|
{
|
|
GstElement *element;
|
|
GstPad *sinkpad, *srcpad;
|
|
GstPad *peerpad;
|
|
GstCaps *caps;
|
|
|
|
gst_element_register (NULL, "proxytestelement", GST_RANK_NONE,
|
|
gst_proxytestelement_get_type ());
|
|
element = gst_element_factory_make ("proxytestelement", NULL);
|
|
|
|
srcpad =
|
|
gst_pad_new_from_static_template (&proxytestelement_src_template, "src");
|
|
gst_element_add_pad (GST_ELEMENT_CAST (element), srcpad);
|
|
|
|
sinkpad = gst_element_get_static_pad (element, "sink");
|
|
srcpad = gst_element_get_static_pad (element, "src");
|
|
|
|
peerpad =
|
|
gst_pad_new_from_static_template (&proxytestelement_peer_template,
|
|
"sink");
|
|
fail_unless (gst_pad_link (srcpad, peerpad) == GST_PAD_LINK_OK);
|
|
gst_pad_set_active (peerpad, TRUE);
|
|
|
|
gst_element_set_state (element, GST_STATE_PLAYING);
|
|
|
|
caps = gst_caps_from_string ("test/bad");
|
|
fail_if (gst_pad_query_accept_caps (sinkpad, caps));
|
|
gst_caps_unref (caps);
|
|
|
|
caps = gst_caps_from_string ("test/proxy, option=(int)1");
|
|
fail_unless (gst_pad_query_accept_caps (sinkpad, caps));
|
|
gst_caps_unref (caps);
|
|
|
|
caps = gst_caps_from_string ("test/proxy, option=(int)2");
|
|
fail_if (gst_pad_query_accept_caps (sinkpad, caps));
|
|
gst_caps_unref (caps);
|
|
|
|
gst_object_unref (sinkpad);
|
|
gst_object_unref (srcpad);
|
|
gst_pad_set_active (peerpad, FALSE);
|
|
gst_object_unref (peerpad);
|
|
gst_element_set_state (element, GST_STATE_NULL);
|
|
gst_object_unref (element);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (test_proxy_accept_caps_with_incompatible_proxy)
|
|
{
|
|
GstElement *element;
|
|
GstPad *sinkpad, *srcpad;
|
|
GstPad *peerpad;
|
|
GstCaps *caps;
|
|
|
|
gst_element_register (NULL, "proxytestelement", GST_RANK_NONE,
|
|
gst_proxytestelement_get_type ());
|
|
element = gst_element_factory_make ("proxytestelement", NULL);
|
|
|
|
srcpad =
|
|
gst_pad_new_from_static_template (&proxytestelement_src_template, "src");
|
|
gst_element_add_pad (GST_ELEMENT_CAST (element), srcpad);
|
|
|
|
sinkpad = gst_element_get_static_pad (element, "sink");
|
|
srcpad = gst_element_get_static_pad (element, "src");
|
|
|
|
peerpad =
|
|
gst_pad_new_from_static_template
|
|
(&proxytestelement_peer_incompatible_template, "sink");
|
|
fail_unless (gst_pad_link (srcpad, peerpad) == GST_PAD_LINK_OK);
|
|
|
|
gst_element_set_state (element, GST_STATE_PLAYING);
|
|
|
|
caps = gst_caps_from_string ("test/bad");
|
|
fail_if (gst_pad_query_accept_caps (sinkpad, caps));
|
|
gst_caps_unref (caps);
|
|
|
|
caps = gst_caps_from_string ("test/proxy");
|
|
fail_if (gst_pad_query_accept_caps (sinkpad, caps));
|
|
gst_caps_unref (caps);
|
|
|
|
caps = gst_caps_from_string ("test/proxy-incompatible");
|
|
fail_if (gst_pad_query_accept_caps (sinkpad, caps));
|
|
gst_caps_unref (caps);
|
|
|
|
gst_object_unref (sinkpad);
|
|
gst_object_unref (srcpad);
|
|
gst_pad_set_active (peerpad, FALSE);
|
|
gst_object_unref (peerpad);
|
|
gst_element_set_state (element, GST_STATE_NULL);
|
|
gst_object_unref (element);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
static GstSegment sink_segment;
|
|
static gint sink_segment_counter;
|
|
|
|
static gboolean
|
|
segment_event_func (GstPad * pad, GstObject * parent, GstEvent * event)
|
|
{
|
|
switch (GST_EVENT_TYPE (event)) {
|
|
case GST_EVENT_SEGMENT:
|
|
gst_event_copy_segment (event, &sink_segment);
|
|
sink_segment_counter++;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
gst_event_unref (event);
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
test_pad_offset (gboolean on_srcpad)
|
|
{
|
|
GstPad *srcpad, *sinkpad, *offset_pad;
|
|
GstSegment segment;
|
|
GstBuffer *buffer;
|
|
GstQuery *query;
|
|
|
|
srcpad = gst_pad_new ("src", GST_PAD_SRC);
|
|
fail_unless (srcpad != NULL);
|
|
sinkpad = gst_pad_new ("sink", GST_PAD_SINK);
|
|
|
|
offset_pad = on_srcpad ? srcpad : sinkpad;
|
|
|
|
gst_segment_init (&sink_segment, GST_FORMAT_UNDEFINED);
|
|
sink_segment_counter = 0;
|
|
gst_pad_set_chain_function (sinkpad, gst_check_chain_func);
|
|
gst_pad_set_event_function (sinkpad, segment_event_func);
|
|
|
|
fail_unless (sinkpad != NULL);
|
|
fail_unless_equals_int (gst_pad_link (srcpad, sinkpad), GST_PAD_LINK_OK);
|
|
fail_unless (gst_pad_set_active (sinkpad, TRUE));
|
|
fail_unless (gst_pad_set_active (srcpad, TRUE));
|
|
|
|
/* Set an offset of 5s, meaning:
|
|
* segment position 0 gives running time 5s, stream time 0s
|
|
* segment start of 0 should stay 0
|
|
*/
|
|
gst_pad_set_offset (offset_pad, 5 * GST_SECOND);
|
|
|
|
fail_unless (gst_pad_push_event (srcpad,
|
|
gst_event_new_stream_start ("test")) == TRUE);
|
|
/* We should have no segment event yet */
|
|
fail_if (sink_segment.format != GST_FORMAT_UNDEFINED);
|
|
fail_unless_equals_int (sink_segment_counter, 0);
|
|
|
|
/* Send segment event, expect it to arrive with a modified start running time */
|
|
gst_segment_init (&segment, GST_FORMAT_TIME);
|
|
fail_unless (gst_pad_push_event (srcpad,
|
|
gst_event_new_segment (&segment)) == TRUE);
|
|
fail_if (sink_segment.format == GST_FORMAT_UNDEFINED);
|
|
fail_unless_equals_uint64 (gst_segment_to_running_time (&sink_segment,
|
|
GST_FORMAT_TIME, sink_segment.start), 5 * GST_SECOND);
|
|
fail_unless_equals_uint64 (gst_segment_to_stream_time (&sink_segment,
|
|
GST_FORMAT_TIME, sink_segment.start), 0 * GST_SECOND);
|
|
fail_unless_equals_uint64 (sink_segment.start, 0 * GST_SECOND);
|
|
|
|
fail_unless_equals_int (sink_segment_counter, 1);
|
|
|
|
/* Send a buffer and check if all timestamps are as expected, and especially
|
|
* if the buffer timestamp was not changed */
|
|
buffer = gst_buffer_new ();
|
|
GST_BUFFER_PTS (buffer) = 0 * GST_SECOND;
|
|
fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
|
|
|
|
fail_unless_equals_int (g_list_length (buffers), 1);
|
|
buffer = buffers->data;
|
|
buffers = g_list_delete_link (buffers, buffers);
|
|
fail_unless_equals_uint64 (gst_segment_to_running_time (&sink_segment,
|
|
GST_FORMAT_TIME, GST_BUFFER_PTS (buffer)), 5 * GST_SECOND);
|
|
fail_unless_equals_uint64 (gst_segment_to_stream_time (&sink_segment,
|
|
GST_FORMAT_TIME, GST_BUFFER_PTS (buffer)), 0 * GST_SECOND);
|
|
fail_unless_equals_uint64 (GST_BUFFER_PTS (buffer), 0 * GST_SECOND);
|
|
gst_buffer_unref (buffer);
|
|
|
|
fail_unless_equals_int (sink_segment_counter, 1);
|
|
|
|
/* Set a negative offset of -5s, meaning:
|
|
* segment position 5s gives running time 0s, stream time 5s
|
|
* segment start would have a negative running time!
|
|
*/
|
|
gst_pad_set_offset (offset_pad, -5 * GST_SECOND);
|
|
|
|
/* Segment should still be the same as before */
|
|
fail_if (sink_segment.format == GST_FORMAT_UNDEFINED);
|
|
fail_unless_equals_uint64 (gst_segment_to_running_time (&sink_segment,
|
|
GST_FORMAT_TIME, sink_segment.start), 5 * GST_SECOND);
|
|
fail_unless_equals_uint64 (gst_segment_to_stream_time (&sink_segment,
|
|
GST_FORMAT_TIME, sink_segment.start), 0 * GST_SECOND);
|
|
fail_unless_equals_uint64 (sink_segment.start, 0 * GST_SECOND);
|
|
|
|
fail_unless_equals_int (sink_segment_counter, 1);
|
|
|
|
/* Send segment event, expect it to arrive with a modified start running time */
|
|
gst_segment_init (&segment, GST_FORMAT_TIME);
|
|
fail_unless (gst_pad_push_event (srcpad,
|
|
gst_event_new_segment (&segment)) == TRUE);
|
|
fail_if (sink_segment.format == GST_FORMAT_UNDEFINED);
|
|
fail_unless_equals_uint64 (gst_segment_to_running_time (&sink_segment,
|
|
GST_FORMAT_TIME, sink_segment.start + 5 * GST_SECOND),
|
|
0 * GST_SECOND);
|
|
fail_unless_equals_uint64 (gst_segment_to_stream_time (&sink_segment,
|
|
GST_FORMAT_TIME, sink_segment.start + 5 * GST_SECOND),
|
|
5 * GST_SECOND);
|
|
fail_unless_equals_uint64 (sink_segment.start, 0 * GST_SECOND);
|
|
|
|
fail_unless_equals_int (sink_segment_counter, 2);
|
|
|
|
/* Send a buffer and check if all timestamps are as expected, and especially
|
|
* if the buffer timestamp was not changed */
|
|
buffer = gst_buffer_new ();
|
|
GST_BUFFER_PTS (buffer) = 5 * GST_SECOND;
|
|
fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
|
|
|
|
fail_unless_equals_int (g_list_length (buffers), 1);
|
|
buffer = buffers->data;
|
|
buffers = g_list_delete_link (buffers, buffers);
|
|
fail_unless_equals_uint64 (gst_segment_to_running_time (&sink_segment,
|
|
GST_FORMAT_TIME, GST_BUFFER_PTS (buffer)), 0 * GST_SECOND);
|
|
fail_unless_equals_uint64 (gst_segment_to_stream_time (&sink_segment,
|
|
GST_FORMAT_TIME, GST_BUFFER_PTS (buffer)), 5 * GST_SECOND);
|
|
fail_unless_equals_uint64 (GST_BUFFER_PTS (buffer), 5 * GST_SECOND);
|
|
gst_buffer_unref (buffer);
|
|
|
|
fail_unless_equals_int (sink_segment_counter, 2);
|
|
|
|
/* Set offset to 5s again, same situation as above but don't send a new
|
|
* segment event. The segment should be adjusted *before* the buffer comes
|
|
* out of the srcpad */
|
|
gst_pad_set_offset (offset_pad, 5 * GST_SECOND);
|
|
|
|
/* Segment should still be the same as before */
|
|
fail_if (sink_segment.format == GST_FORMAT_UNDEFINED);
|
|
fail_unless_equals_uint64 (gst_segment_to_running_time (&sink_segment,
|
|
GST_FORMAT_TIME, sink_segment.start + 5 * GST_SECOND),
|
|
0 * GST_SECOND);
|
|
fail_unless_equals_uint64 (gst_segment_to_stream_time (&sink_segment,
|
|
GST_FORMAT_TIME, sink_segment.start + 5 * GST_SECOND),
|
|
5 * GST_SECOND);
|
|
fail_unless_equals_uint64 (sink_segment.start, 0 * GST_SECOND);
|
|
|
|
fail_unless_equals_int (sink_segment_counter, 2);
|
|
|
|
/* Send a buffer and check if a new segment event was sent and all buffer
|
|
* timestamps are as expected */
|
|
buffer = gst_buffer_new ();
|
|
GST_BUFFER_PTS (buffer) = 0 * GST_SECOND;
|
|
fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
|
|
|
|
fail_if (sink_segment.format == GST_FORMAT_UNDEFINED);
|
|
fail_unless_equals_uint64 (gst_segment_to_running_time (&sink_segment,
|
|
GST_FORMAT_TIME, sink_segment.start), 5 * GST_SECOND);
|
|
fail_unless_equals_uint64 (gst_segment_to_stream_time (&sink_segment,
|
|
GST_FORMAT_TIME, sink_segment.start), 0 * GST_SECOND);
|
|
fail_unless_equals_uint64 (sink_segment.start, 0 * GST_SECOND);
|
|
|
|
fail_unless_equals_int (sink_segment_counter, 3);
|
|
|
|
fail_unless_equals_int (g_list_length (buffers), 1);
|
|
buffer = buffers->data;
|
|
buffers = g_list_delete_link (buffers, buffers);
|
|
fail_unless_equals_uint64 (gst_segment_to_running_time (&sink_segment,
|
|
GST_FORMAT_TIME, GST_BUFFER_PTS (buffer)), 5 * GST_SECOND);
|
|
fail_unless_equals_uint64 (gst_segment_to_stream_time (&sink_segment,
|
|
GST_FORMAT_TIME, GST_BUFFER_PTS (buffer)), 0 * GST_SECOND);
|
|
fail_unless_equals_uint64 (GST_BUFFER_PTS (buffer), 0 * GST_SECOND);
|
|
gst_buffer_unref (buffer);
|
|
|
|
fail_unless_equals_int (sink_segment_counter, 3);
|
|
|
|
/* Set offset to 10s and send another sticky event. In between a new
|
|
* segment event should've been sent */
|
|
gst_pad_set_offset (offset_pad, 10 * GST_SECOND);
|
|
|
|
/* Segment should still be the same as before */
|
|
fail_if (sink_segment.format == GST_FORMAT_UNDEFINED);
|
|
fail_unless_equals_uint64 (gst_segment_to_running_time (&sink_segment,
|
|
GST_FORMAT_TIME, sink_segment.start), 5 * GST_SECOND);
|
|
fail_unless_equals_uint64 (gst_segment_to_stream_time (&sink_segment,
|
|
GST_FORMAT_TIME, sink_segment.start), 0 * GST_SECOND);
|
|
fail_unless_equals_uint64 (sink_segment.start, 0 * GST_SECOND);
|
|
fail_unless_equals_int (sink_segment_counter, 3);
|
|
|
|
fail_unless (gst_pad_push_event (srcpad,
|
|
gst_event_new_tag (gst_tag_list_new_empty ())) == TRUE);
|
|
|
|
/* Segment should be updated */
|
|
fail_if (sink_segment.format == GST_FORMAT_UNDEFINED);
|
|
fail_unless_equals_uint64 (gst_segment_to_running_time (&sink_segment,
|
|
GST_FORMAT_TIME, sink_segment.start), 10 * GST_SECOND);
|
|
fail_unless_equals_uint64 (gst_segment_to_stream_time (&sink_segment,
|
|
GST_FORMAT_TIME, sink_segment.start), 0 * GST_SECOND);
|
|
fail_unless_equals_uint64 (sink_segment.start, 0 * GST_SECOND);
|
|
|
|
fail_unless_equals_int (sink_segment_counter, 4);
|
|
|
|
/* Set offset to 15s and do a serialized query. In between a new
|
|
* segment event should've been sent */
|
|
gst_pad_set_offset (offset_pad, 15 * GST_SECOND);
|
|
|
|
/* Segment should still be the same as before */
|
|
fail_if (sink_segment.format == GST_FORMAT_UNDEFINED);
|
|
fail_unless_equals_uint64 (gst_segment_to_running_time (&sink_segment,
|
|
GST_FORMAT_TIME, sink_segment.start), 10 * GST_SECOND);
|
|
fail_unless_equals_uint64 (gst_segment_to_stream_time (&sink_segment,
|
|
GST_FORMAT_TIME, sink_segment.start), 0 * GST_SECOND);
|
|
fail_unless_equals_uint64 (sink_segment.start, 0 * GST_SECOND);
|
|
fail_unless_equals_int (sink_segment_counter, 4);
|
|
|
|
query = gst_query_new_drain ();
|
|
gst_pad_peer_query (srcpad, query);
|
|
gst_query_unref (query);
|
|
|
|
/* Segment should be updated */
|
|
fail_if (sink_segment.format == GST_FORMAT_UNDEFINED);
|
|
fail_unless_equals_uint64 (gst_segment_to_running_time (&sink_segment,
|
|
GST_FORMAT_TIME, sink_segment.start), 15 * GST_SECOND);
|
|
fail_unless_equals_uint64 (gst_segment_to_stream_time (&sink_segment,
|
|
GST_FORMAT_TIME, sink_segment.start), 0 * GST_SECOND);
|
|
fail_unless_equals_uint64 (sink_segment.start, 0 * GST_SECOND);
|
|
|
|
fail_unless_equals_int (sink_segment_counter, 5);
|
|
|
|
gst_check_drop_buffers ();
|
|
|
|
fail_unless (gst_pad_set_active (sinkpad, FALSE));
|
|
fail_unless (gst_pad_set_active (srcpad, FALSE));
|
|
gst_object_unref (sinkpad);
|
|
gst_object_unref (srcpad);
|
|
}
|
|
|
|
GST_START_TEST (test_pad_offset_src)
|
|
{
|
|
test_pad_offset (TRUE);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
static Suite *
|
|
gst_pad_suite (void)
|
|
{
|
|
Suite *s = suite_create ("GstPad");
|
|
TCase *tc_chain = tcase_create ("general");
|
|
|
|
/* turn off timeout */
|
|
tcase_set_timeout (tc_chain, 60);
|
|
|
|
gst_segment_init (&dummy_segment, GST_FORMAT_BYTES);
|
|
|
|
suite_add_tcase (s, tc_chain);
|
|
tcase_add_test (tc_chain, test_link);
|
|
tcase_add_test (tc_chain, test_refcount);
|
|
tcase_add_test (tc_chain, test_get_allowed_caps);
|
|
tcase_add_test (tc_chain, test_sticky_caps_unlinked);
|
|
tcase_add_test (tc_chain, test_sticky_caps_unlinked_incompatible);
|
|
tcase_add_test (tc_chain, test_sticky_caps_flushing);
|
|
tcase_add_test (tc_chain, test_default_accept_caps);
|
|
tcase_add_test (tc_chain, test_link_unlink_threaded);
|
|
tcase_add_test (tc_chain, test_name_is_valid);
|
|
tcase_add_test (tc_chain, test_push_unlinked);
|
|
tcase_add_test (tc_chain, test_push_linked);
|
|
tcase_add_test (tc_chain, test_push_linked_flushing);
|
|
tcase_add_test (tc_chain, test_push_buffer_list_compat);
|
|
tcase_add_test (tc_chain, test_flowreturn);
|
|
tcase_add_test (tc_chain, test_push_negotiation);
|
|
tcase_add_test (tc_chain, test_src_unref_unlink);
|
|
tcase_add_test (tc_chain, test_sink_unref_unlink);
|
|
tcase_add_test (tc_chain, test_block_async);
|
|
tcase_add_test (tc_chain, test_pad_blocking_with_probe_type_block);
|
|
tcase_add_test (tc_chain, test_pad_blocking_with_probe_type_blocking);
|
|
tcase_add_test (tc_chain, test_pad_blocking_with_probe_type_idle);
|
|
tcase_add_test (tc_chain, test_pad_probe_pull);
|
|
tcase_add_test (tc_chain, test_pad_probe_pull_idle);
|
|
tcase_add_test (tc_chain, test_pad_probe_pull_buffer);
|
|
tcase_add_test (tc_chain, test_pad_probe_remove);
|
|
tcase_add_test (tc_chain, test_pad_probe_block_add_remove);
|
|
tcase_add_test (tc_chain, test_pad_probe_block_and_drop_buffer);
|
|
tcase_add_test (tc_chain, test_pad_probe_flush_events);
|
|
tcase_add_test (tc_chain, test_pad_probe_flush_events_only);
|
|
tcase_add_test (tc_chain, test_pad_probe_call_order);
|
|
tcase_add_test (tc_chain, test_pad_probe_handled_and_drop);
|
|
tcase_add_test (tc_chain, test_events_query_unlinked);
|
|
tcase_add_test (tc_chain, test_queue_src_caps_notify_linked);
|
|
tcase_add_test (tc_chain, test_queue_src_caps_notify_not_linked);
|
|
#if 0
|
|
tcase_add_test (tc_chain, test_block_async_replace_callback);
|
|
#endif
|
|
tcase_add_test (tc_chain, test_block_async_full_destroy);
|
|
tcase_add_test (tc_chain, test_block_async_full_destroy_dispose);
|
|
tcase_add_test (tc_chain, test_block_async_replace_callback_no_flush);
|
|
tcase_add_test (tc_chain, test_sticky_events);
|
|
tcase_add_test (tc_chain, test_last_flow_return_push);
|
|
tcase_add_test (tc_chain, test_last_flow_return_pull);
|
|
tcase_add_test (tc_chain, test_flush_stop_inactive);
|
|
tcase_add_test (tc_chain, test_proxy_accept_caps_no_proxy);
|
|
tcase_add_test (tc_chain, test_proxy_accept_caps_with_proxy);
|
|
tcase_add_test (tc_chain, test_proxy_accept_caps_with_incompatible_proxy);
|
|
tcase_add_test (tc_chain, test_pad_offset_src);
|
|
|
|
return s;
|
|
}
|
|
|
|
GST_CHECK_MAIN (gst_pad);
|