libs/gst/base/gstbasesink.c: Fix leak caused when refusing newsegment after EOS.

Original commit message from CVS:
* libs/gst/base/gstbasesink.c:
(gst_base_sink_queue_object_unlocked), (gst_base_sink_event):
Fix leak caused when refusing newsegment after EOS.
* plugins/elements/gstfakesink.c: (gst_fake_sink_class_init),
(gst_fake_sink_init), (gst_fake_sink_set_property),
(gst_fake_sink_get_property), (gst_fake_sink_preroll),
(gst_fake_sink_render), (gst_fake_sink_change_state):
* plugins/elements/gstfakesink.h:
Add num-buffers property to make the element generate EOS after a
configurable amount of buffers.
API: fakesink::num-buffers property.
* tests/check/elements/fakesink.c: (GST_START_TEST),
(fakesink_suite):
Fix GstBus leak in test.
Test for fakesink num-buffers.
This commit is contained in:
Wim Taymans 2007-04-05 11:16:09 +00:00
parent cc82861367
commit 12c9334667
5 changed files with 146 additions and 4 deletions

View file

@ -1,3 +1,23 @@
2007-04-05 Wim Taymans <wim@fluendo.com>
* libs/gst/base/gstbasesink.c:
(gst_base_sink_queue_object_unlocked), (gst_base_sink_event):
Fix leak caused when refusing newsegment after EOS.
* plugins/elements/gstfakesink.c: (gst_fake_sink_class_init),
(gst_fake_sink_init), (gst_fake_sink_set_property),
(gst_fake_sink_get_property), (gst_fake_sink_preroll),
(gst_fake_sink_render), (gst_fake_sink_change_state):
* plugins/elements/gstfakesink.h:
Add num-buffers property to make the element generate EOS after a
configurable amount of buffers.
API: fakesink::num-buffers property.
* tests/check/elements/fakesink.c: (GST_START_TEST),
(fakesink_suite):
Fix GstBus leak in test.
Test for fakesink num-buffers.
2007-04-05 Wim Taymans <wim@fluendo.com> 2007-04-05 Wim Taymans <wim@fluendo.com>
* libs/gst/base/gstbasesink.c: * libs/gst/base/gstbasesink.c:

View file

@ -1879,7 +1879,8 @@ gst_base_sink_queue_object_unlocked (GstBaseSink * basesink, GstPad * pad,
/* special cases */ /* special cases */
was_eos: was_eos:
{ {
GST_DEBUG_OBJECT (basesink, "we are EOS"); GST_DEBUG_OBJECT (basesink,
"we are EOS, dropping object, return UNEXPECTED");
gst_mini_object_unref (obj); gst_mini_object_unref (obj);
return GST_FLOW_UNEXPECTED; return GST_FLOW_UNEXPECTED;
} }
@ -1976,10 +1977,11 @@ gst_base_sink_event (GstPad * pad, GstEvent * event)
GST_DEBUG_OBJECT (basesink, "newsegment %p", event); GST_DEBUG_OBJECT (basesink, "newsegment %p", event);
if (G_UNLIKELY (basesink->priv->received_eos)) if (G_UNLIKELY (basesink->priv->received_eos)) {
/* we can't accept anything when we are EOS */ /* we can't accept anything when we are EOS */
result = FALSE; result = FALSE;
else { gst_event_unref (event);
} else {
/* the new segment is a non prerollable item and does not block anything, /* the new segment is a non prerollable item and does not block anything,
* we need to configure the current clipping segment and insert the event * we need to configure the current clipping segment and insert the event
* in the queue to serialize it with the buffers for rendering. */ * in the queue to serialize it with the buffers for rendering. */

View file

@ -69,6 +69,7 @@ enum
#define DEFAULT_LAST_MESSAGE NULL #define DEFAULT_LAST_MESSAGE NULL
#define DEFAULT_CAN_ACTIVATE_PUSH TRUE #define DEFAULT_CAN_ACTIVATE_PUSH TRUE
#define DEFAULT_CAN_ACTIVATE_PULL FALSE #define DEFAULT_CAN_ACTIVATE_PULL FALSE
#define DEFAULT_NUM_BUFFERS -1
enum enum
{ {
@ -79,7 +80,8 @@ enum
PROP_SIGNAL_HANDOFFS, PROP_SIGNAL_HANDOFFS,
PROP_LAST_MESSAGE, PROP_LAST_MESSAGE,
PROP_CAN_ACTIVATE_PUSH, PROP_CAN_ACTIVATE_PUSH,
PROP_CAN_ACTIVATE_PULL PROP_CAN_ACTIVATE_PULL,
PROP_NUM_BUFFERS
}; };
#define GST_TYPE_FAKE_SINK_STATE_ERROR (gst_fake_sink_state_error_get_type()) #define GST_TYPE_FAKE_SINK_STATE_ERROR (gst_fake_sink_state_error_get_type())
@ -186,6 +188,10 @@ gst_fake_sink_class_init (GstFakeSinkClass * klass)
g_param_spec_boolean ("can-activate-pull", "Can activate pull", g_param_spec_boolean ("can-activate-pull", "Can activate pull",
"Can activate in pull mode", DEFAULT_CAN_ACTIVATE_PULL, "Can activate in pull mode", DEFAULT_CAN_ACTIVATE_PULL,
G_PARAM_READWRITE)); G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_NUM_BUFFERS,
g_param_spec_int ("num-buffers", "num-buffers",
"Number of buffers to accept going EOS", -1, G_MAXINT,
DEFAULT_NUM_BUFFERS, G_PARAM_READWRITE));
/** /**
* GstFakeSink::handoff: * GstFakeSink::handoff:
@ -234,6 +240,7 @@ gst_fake_sink_init (GstFakeSink * fakesink, GstFakeSinkClass * g_class)
fakesink->last_message = g_strdup (DEFAULT_LAST_MESSAGE); fakesink->last_message = g_strdup (DEFAULT_LAST_MESSAGE);
fakesink->state_error = DEFAULT_STATE_ERROR; fakesink->state_error = DEFAULT_STATE_ERROR;
fakesink->signal_handoffs = DEFAULT_SIGNAL_HANDOFFS; fakesink->signal_handoffs = DEFAULT_SIGNAL_HANDOFFS;
fakesink->num_buffers = DEFAULT_NUM_BUFFERS;
} }
static void static void
@ -263,6 +270,9 @@ gst_fake_sink_set_property (GObject * object, guint prop_id,
case PROP_CAN_ACTIVATE_PULL: case PROP_CAN_ACTIVATE_PULL:
GST_BASE_SINK (sink)->can_activate_pull = g_value_get_boolean (value); GST_BASE_SINK (sink)->can_activate_pull = g_value_get_boolean (value);
break; break;
case PROP_NUM_BUFFERS:
sink->num_buffers = g_value_get_int (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -301,6 +311,9 @@ gst_fake_sink_get_property (GObject * object, guint prop_id, GValue * value,
case PROP_CAN_ACTIVATE_PULL: case PROP_CAN_ACTIVATE_PULL:
g_value_set_boolean (value, GST_BASE_SINK (sink)->can_activate_pull); g_value_set_boolean (value, GST_BASE_SINK (sink)->can_activate_pull);
break; break;
case PROP_NUM_BUFFERS:
g_value_set_int (value, sink->num_buffers);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -341,6 +354,9 @@ gst_fake_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer)
{ {
GstFakeSink *sink = GST_FAKE_SINK (bsink); GstFakeSink *sink = GST_FAKE_SINK (bsink);
if (sink->num_buffers_left == 0)
goto eos;
if (!sink->silent) { if (!sink->silent) {
GST_OBJECT_LOCK (sink); GST_OBJECT_LOCK (sink);
g_free (sink->last_message); g_free (sink->last_message);
@ -356,6 +372,13 @@ gst_fake_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer)
bsink->sinkpad); bsink->sinkpad);
} }
return GST_FLOW_OK; return GST_FLOW_OK;
/* ERRORS */
eos:
{
GST_DEBUG_OBJECT (sink, "we are EOS");
return GST_FLOW_UNEXPECTED;
}
} }
static GstFlowReturn static GstFlowReturn
@ -363,6 +386,12 @@ gst_fake_sink_render (GstBaseSink * bsink, GstBuffer * buf)
{ {
GstFakeSink *sink = GST_FAKE_SINK_CAST (bsink); GstFakeSink *sink = GST_FAKE_SINK_CAST (bsink);
if (sink->num_buffers_left == 0)
goto eos;
if (sink->num_buffers_left != -1)
sink->num_buffers_left--;
if (!sink->silent) { if (!sink->silent) {
gchar ts_str[64], dur_str[64]; gchar ts_str[64], dur_str[64];
@ -400,8 +429,17 @@ gst_fake_sink_render (GstBaseSink * bsink, GstBuffer * buf)
if (sink->dump) { if (sink->dump) {
gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
} }
if (sink->num_buffers_left == 0)
goto eos;
return GST_FLOW_OK; return GST_FLOW_OK;
/* ERRORS */
eos:
{
GST_DEBUG_OBJECT (sink, "we are EOS");
return GST_FLOW_UNEXPECTED;
}
} }
static GstStateChangeReturn static GstStateChangeReturn
@ -418,6 +456,7 @@ gst_fake_sink_change_state (GstElement * element, GstStateChange transition)
case GST_STATE_CHANGE_READY_TO_PAUSED: case GST_STATE_CHANGE_READY_TO_PAUSED:
if (fakesink->state_error == FAKE_SINK_STATE_ERROR_READY_PAUSED) if (fakesink->state_error == FAKE_SINK_STATE_ERROR_READY_PAUSED)
goto error; goto error;
fakesink->num_buffers_left = fakesink->num_buffers;
break; break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING: case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
if (fakesink->state_error == FAKE_SINK_STATE_ERROR_PAUSED_PLAYING) if (fakesink->state_error == FAKE_SINK_STATE_ERROR_PAUSED_PLAYING)

View file

@ -80,6 +80,8 @@ struct _GstFakeSink {
gboolean signal_handoffs; gboolean signal_handoffs;
GstFakeSinkStateError state_error; GstFakeSinkStateError state_error;
gchar *last_message; gchar *last_message;
gint num_buffers;
gint num_buffers_left;
}; };
struct _GstFakeSinkClass { struct _GstFakeSinkClass {

View file

@ -351,6 +351,7 @@ GST_START_TEST (test_eos)
if (type == GST_MESSAGE_EOS) if (type == GST_MESSAGE_EOS)
break; break;
} }
gst_object_unref (bus);
/* send another EOS, this should fail */ /* send another EOS, this should fail */
{ {
@ -445,6 +446,83 @@ GST_START_TEST (test_eos)
GST_END_TEST; GST_END_TEST;
/* test EOS triggered by the element */
GST_START_TEST (test_eos2)
{
GstElement *pipeline, *sink;
GstPad *sinkpad;
GstStateChangeReturn ret;
/* create sink */
pipeline = gst_pipeline_new ("pipeline");
fail_if (pipeline == NULL);
sink = gst_element_factory_make ("fakesink", "sink");
fail_if (sink == NULL);
g_object_set (G_OBJECT (sink), "sync", TRUE, NULL);
g_object_set (G_OBJECT (sink), "num-buffers", 1, NULL);
gst_bin_add (GST_BIN (pipeline), sink);
sinkpad = gst_element_get_pad (sink, "sink");
fail_if (sinkpad == NULL);
/* make pipeline and element ready to accept data */
ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
fail_unless (ret == GST_STATE_CHANGE_ASYNC);
/* send segment, this should work */
{
GstEvent *segment;
gboolean eret;
GST_DEBUG ("sending segment");
segment = gst_event_new_new_segment (FALSE,
1.0, GST_FORMAT_TIME, 0 * GST_SECOND, 2 * GST_SECOND, 0 * GST_SECOND);
eret = gst_pad_send_event (sinkpad, segment);
fail_if (eret == FALSE);
}
/* send buffer that should return UNEXPECTED */
{
GstBuffer *buffer;
GstFlowReturn fret;
buffer = gst_buffer_new ();
GST_BUFFER_TIMESTAMP (buffer) = 1 * GST_SECOND;
GST_BUFFER_DURATION (buffer) = 1 * GST_SECOND;
GST_DEBUG ("sending buffer");
/* this buffer will generate UNEXPECTED */
fret = gst_pad_chain (sinkpad, buffer);
fail_unless (fret == GST_FLOW_UNEXPECTED);
}
/* send buffer that should return UNEXPECTED */
{
GstBuffer *buffer;
GstFlowReturn fret;
buffer = gst_buffer_new ();
GST_BUFFER_TIMESTAMP (buffer) = 1 * GST_SECOND;
GST_BUFFER_DURATION (buffer) = 1 * GST_SECOND;
GST_DEBUG ("sending buffer");
fret = gst_pad_chain (sinkpad, buffer);
fail_unless (fret == GST_FLOW_UNEXPECTED);
}
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_element_get_state (pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
gst_object_unref (sinkpad);
gst_object_unref (pipeline);
}
GST_END_TEST;
Suite * Suite *
fakesink_suite (void) fakesink_suite (void)
{ {
@ -455,6 +533,7 @@ fakesink_suite (void)
tcase_add_test (tc_chain, test_clipping); tcase_add_test (tc_chain, test_clipping);
tcase_add_test (tc_chain, test_preroll_sync); tcase_add_test (tc_chain, test_preroll_sync);
tcase_add_test (tc_chain, test_eos); tcase_add_test (tc_chain, test_eos);
tcase_add_test (tc_chain, test_eos2);
return s; return s;
} }