libs/gst/base/gstbasesink.c: Fix leak caused when refusing newsegment after EOS.
authorWim Taymans <wim.taymans@gmail.com>
Thu, 5 Apr 2007 11:16:09 +0000 (11:16 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Thu, 5 Apr 2007 11:16:09 +0000 (11:16 +0000)
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.

ChangeLog
libs/gst/base/gstbasesink.c
plugins/elements/gstfakesink.c
plugins/elements/gstfakesink.h
tests/check/elements/fakesink.c

index eefd3ad..dc492f2 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,26 @@
 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>
+
+       * libs/gst/base/gstbasesink.c:
        (gst_base_sink_queue_object_unlocked), (gst_base_sink_event),
        (gst_base_sink_change_state):
        Don't accept anything after an EOS, return UNEXPECTED instead.
index 9703326..34e9357 100644 (file)
@@ -1879,7 +1879,8 @@ gst_base_sink_queue_object_unlocked (GstBaseSink * basesink, GstPad * pad,
   /* special cases */
 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);
     return GST_FLOW_UNEXPECTED;
   }
@@ -1976,10 +1977,11 @@ gst_base_sink_event (GstPad * pad, GstEvent * 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 */
         result = FALSE;
-      else {
+        gst_event_unref (event);
+      } else {
         /* 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 
          * in the queue to serialize it with the buffers for rendering. */
index 280efd0..e38b72a 100644 (file)
@@ -69,6 +69,7 @@ enum
 #define DEFAULT_LAST_MESSAGE NULL
 #define DEFAULT_CAN_ACTIVATE_PUSH TRUE
 #define DEFAULT_CAN_ACTIVATE_PULL FALSE
+#define DEFAULT_NUM_BUFFERS -1
 
 enum
 {
@@ -79,7 +80,8 @@ enum
   PROP_SIGNAL_HANDOFFS,
   PROP_LAST_MESSAGE,
   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())
@@ -186,6 +188,10 @@ gst_fake_sink_class_init (GstFakeSinkClass * klass)
       g_param_spec_boolean ("can-activate-pull", "Can activate pull",
           "Can activate in pull mode", DEFAULT_CAN_ACTIVATE_PULL,
           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:
@@ -234,6 +240,7 @@ gst_fake_sink_init (GstFakeSink * fakesink, GstFakeSinkClass * g_class)
   fakesink->last_message = g_strdup (DEFAULT_LAST_MESSAGE);
   fakesink->state_error = DEFAULT_STATE_ERROR;
   fakesink->signal_handoffs = DEFAULT_SIGNAL_HANDOFFS;
+  fakesink->num_buffers = DEFAULT_NUM_BUFFERS;
 }
 
 static void
@@ -263,6 +270,9 @@ gst_fake_sink_set_property (GObject * object, guint prop_id,
     case PROP_CAN_ACTIVATE_PULL:
       GST_BASE_SINK (sink)->can_activate_pull = g_value_get_boolean (value);
       break;
+    case PROP_NUM_BUFFERS:
+      sink->num_buffers = g_value_get_int (value);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -301,6 +311,9 @@ gst_fake_sink_get_property (GObject * object, guint prop_id, GValue * value,
     case PROP_CAN_ACTIVATE_PULL:
       g_value_set_boolean (value, GST_BASE_SINK (sink)->can_activate_pull);
       break;
+    case PROP_NUM_BUFFERS:
+      g_value_set_int (value, sink->num_buffers);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -341,6 +354,9 @@ gst_fake_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer)
 {
   GstFakeSink *sink = GST_FAKE_SINK (bsink);
 
+  if (sink->num_buffers_left == 0)
+    goto eos;
+
   if (!sink->silent) {
     GST_OBJECT_LOCK (sink);
     g_free (sink->last_message);
@@ -356,6 +372,13 @@ gst_fake_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer)
         bsink->sinkpad);
   }
   return GST_FLOW_OK;
+
+  /* ERRORS */
+eos:
+  {
+    GST_DEBUG_OBJECT (sink, "we are EOS");
+    return GST_FLOW_UNEXPECTED;
+  }
 }
 
 static GstFlowReturn
@@ -363,6 +386,12 @@ gst_fake_sink_render (GstBaseSink * bsink, GstBuffer * buf)
 {
   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) {
     gchar ts_str[64], dur_str[64];
 
@@ -400,8 +429,17 @@ gst_fake_sink_render (GstBaseSink * bsink, GstBuffer * buf)
   if (sink->dump) {
     gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
   }
+  if (sink->num_buffers_left == 0)
+    goto eos;
 
   return GST_FLOW_OK;
+
+  /* ERRORS */
+eos:
+  {
+    GST_DEBUG_OBJECT (sink, "we are EOS");
+    return GST_FLOW_UNEXPECTED;
+  }
 }
 
 static GstStateChangeReturn
@@ -418,6 +456,7 @@ gst_fake_sink_change_state (GstElement * element, GstStateChange transition)
     case GST_STATE_CHANGE_READY_TO_PAUSED:
       if (fakesink->state_error == FAKE_SINK_STATE_ERROR_READY_PAUSED)
         goto error;
+      fakesink->num_buffers_left = fakesink->num_buffers;
       break;
     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
       if (fakesink->state_error == FAKE_SINK_STATE_ERROR_PAUSED_PLAYING)
index 2796492..2db98b9 100644 (file)
@@ -80,6 +80,8 @@ struct _GstFakeSink {
   gboolean             signal_handoffs;
   GstFakeSinkStateError state_error;
   gchar                        *last_message;
+  gint                  num_buffers;
+  gint                  num_buffers_left;
 };
 
 struct _GstFakeSinkClass {
index 3e012ae..0c1b299 100644 (file)
@@ -351,6 +351,7 @@ GST_START_TEST (test_eos)
     if (type == GST_MESSAGE_EOS)
       break;
   }
+  gst_object_unref (bus);
 
   /* send another EOS, this should fail */
   {
@@ -445,6 +446,83 @@ GST_START_TEST (test_eos)
 
 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 *
 fakesink_suite (void)
 {
@@ -455,6 +533,7 @@ fakesink_suite (void)
   tcase_add_test (tc_chain, test_clipping);
   tcase_add_test (tc_chain, test_preroll_sync);
   tcase_add_test (tc_chain, test_eos);
+  tcase_add_test (tc_chain, test_eos2);
 
   return s;
 }