basesink: add new enable-last-buffer property.
authorAlessandro Decina <alessandro.d@gmail.com>
Tue, 6 Jul 2010 10:18:45 +0000 (12:18 +0200)
committerAlessandro Decina <alessandro.d@gmail.com>
Tue, 6 Jul 2010 10:38:21 +0000 (12:38 +0200)
Add a new enable-last-buffer property. When false, it disables storing the last
received buffer in basesink::last-buffer. This can be useful in cases where
buffers need to be released asap.

API: GstBaseSink::enable-last-buffer

libs/gst/base/gstbasesink.c
tests/check/Makefile.am
tests/check/libs/basesink.c [new file with mode: 0644]

index acc2db8..5eb1301 100644 (file)
@@ -236,6 +236,7 @@ struct _GstBaseSinkPrivate
   gboolean have_latency;
 
   /* the last buffer we prerolled or rendered. Useful for making snapshots */
+  gboolean enable_last_buffer;
   GstBuffer *last_buffer;
 
   /* caps for pull based scheduling */
@@ -281,6 +282,7 @@ struct _GstBaseSinkPrivate
 #define DEFAULT_TS_OFFSET           0
 #define DEFAULT_BLOCKSIZE           4096
 #define DEFAULT_RENDER_DELAY        0
+#define DEFAULT_ENABLE_LAST_BUFFER  TRUE
 
 enum
 {
@@ -291,6 +293,7 @@ enum
   PROP_QOS,
   PROP_ASYNC,
   PROP_TS_OFFSET,
+  PROP_ENABLE_LAST_BUFFER,
   PROP_LAST_BUFFER,
   PROP_BLOCKSIZE,
   PROP_RENDER_DELAY,
@@ -450,6 +453,22 @@ gst_base_sink_class_init (GstBaseSinkClass * klass)
       g_param_spec_int64 ("ts-offset", "TS Offset",
           "Timestamp offset in nanoseconds", G_MININT64, G_MAXINT64,
           DEFAULT_TS_OFFSET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstBaseSink:enable-last-buffer
+   *
+   * Enable the last-buffer property. If FALSE, basesink doesn't keep a
+   * reference to the last buffer arrived and the last-buffer property is always
+   * set to NULL. This can be useful if you need buffers to be released as soon
+   * as possible, eg. if you're using a buffer pool.
+   *
+   * Since: 0.10.30
+   */
+  g_object_class_install_property (gobject_class, PROP_ENABLE_LAST_BUFFER,
+      g_param_spec_boolean ("enable-last-buffer", "Enable Last Buffer",
+          "Enable the last-buffer property", DEFAULT_ENABLE_LAST_BUFFER,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
   /**
    * GstBaseSink:last-buffer
    *
@@ -648,6 +667,7 @@ gst_base_sink_init (GstBaseSink * basesink, gpointer g_class)
   priv->ts_offset = DEFAULT_TS_OFFSET;
   priv->render_delay = DEFAULT_RENDER_DELAY;
   priv->blocksize = DEFAULT_BLOCKSIZE;
+  priv->enable_last_buffer = DEFAULT_ENABLE_LAST_BUFFER;
 
   GST_OBJECT_FLAG_SET (basesink, GST_ELEMENT_IS_SINK);
 }
@@ -928,12 +948,12 @@ gst_base_sink_get_last_buffer (GstBaseSink * sink)
   return res;
 }
 
+/* with OBJECT_LOCK */
 static void
-gst_base_sink_set_last_buffer (GstBaseSink * sink, GstBuffer * buffer)
+gst_base_sink_set_last_buffer_unlocked (GstBaseSink * sink, GstBuffer * buffer)
 {
   GstBuffer *old;
 
-  GST_OBJECT_LOCK (sink);
   old = sink->priv->last_buffer;
   if (G_LIKELY (old != buffer)) {
     GST_DEBUG_OBJECT (sink, "setting last buffer to %p", buffer);
@@ -943,12 +963,26 @@ gst_base_sink_set_last_buffer (GstBaseSink * sink, GstBuffer * buffer)
   } else {
     old = NULL;
   }
-  GST_OBJECT_UNLOCK (sink);
-
   /* avoid unreffing with the lock because cleanup code might want to take the
    * lock too */
-  if (G_LIKELY (old))
+  if (G_LIKELY (old)) {
+    GST_OBJECT_UNLOCK (sink);
     gst_buffer_unref (old);
+    GST_OBJECT_LOCK (sink);
+  }
+}
+
+static void
+gst_base_sink_set_last_buffer (GstBaseSink * sink, GstBuffer * buffer)
+{
+  GST_OBJECT_LOCK (sink);
+  if (sink->priv->enable_last_buffer == FALSE)
+    goto out;
+
+  gst_base_sink_set_last_buffer_unlocked (sink, buffer);
+
+out:
+  GST_OBJECT_UNLOCK (sink);
 }
 
 /**
@@ -1219,6 +1253,20 @@ gst_base_sink_set_property (GObject * object, guint prop_id,
     case PROP_RENDER_DELAY:
       gst_base_sink_set_render_delay (sink, g_value_get_uint64 (value));
       break;
+    case PROP_ENABLE_LAST_BUFFER:
+    {
+      gboolean enable;
+      enable = g_value_get_boolean (value);
+
+      GST_OBJECT_LOCK (sink);
+      if (enable != sink->priv->enable_last_buffer) {
+        sink->priv->enable_last_buffer = enable;
+        if (!enable)
+          gst_base_sink_set_last_buffer_unlocked (sink, NULL);
+      }
+      GST_OBJECT_UNLOCK (sink);
+      break;
+    }
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1255,6 +1303,9 @@ gst_base_sink_get_property (GObject * object, guint prop_id, GValue * value,
     case PROP_LAST_BUFFER:
       gst_value_take_buffer (value, gst_base_sink_get_last_buffer (sink));
       break;
+    case PROP_ENABLE_LAST_BUFFER:
+      g_value_set_boolean (value, sink->priv->enable_last_buffer);
+      break;
     case PROP_BLOCKSIZE:
       g_value_set_uint (value, gst_base_sink_get_blocksize (sink));
       break;
index 3a0a87c..7fed996 100644 (file)
@@ -64,6 +64,7 @@ REGISTRY_CHECKS =                             \
        elements/multiqueue                     \
        elements/tee                            \
        libs/basesrc                            \
+       libs/basesink                           \
        libs/controller                         \
        libs/typefindhelper                     \
        pipelines/stress                        \
diff --git a/tests/check/libs/basesink.c b/tests/check/libs/basesink.c
new file mode 100644 (file)
index 0000000..9fbd46c
--- /dev/null
@@ -0,0 +1,129 @@
+/* GStreamer
+ *
+ * Copyright (C) 2010 Alessandro Decina <alessandro.decina@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <gst/gst.h>
+#include <gst/check/gstcheck.h>
+#include <gst/base/gstbasesink.h>
+
+GST_START_TEST (basesink_last_buffer_enabled)
+{
+  GstElement *src, *sink, *pipeline;
+  GstBus *bus;
+  GstMessage *msg;
+  GstBuffer *last_buffer;
+
+  pipeline = gst_pipeline_new ("pipeline");
+  sink = gst_element_factory_make ("fakesink", "sink");
+  src = gst_element_factory_make ("fakesrc", "src");
+
+  fail_unless (gst_bin_add (GST_BIN (pipeline), src) == TRUE);
+  fail_unless (gst_bin_add (GST_BIN (pipeline), sink) == TRUE);
+  fail_unless (gst_element_link (src, sink) == TRUE);
+
+  bus = gst_element_get_bus (pipeline);
+
+  /* try with enable-last-buffer set to TRUE */
+  g_object_set (src, "num-buffers", 1, NULL);
+  fail_unless (gst_element_set_state (pipeline, GST_STATE_PLAYING)
+      != GST_STATE_CHANGE_FAILURE);
+  msg = gst_bus_poll (bus, GST_MESSAGE_EOS | GST_MESSAGE_ERROR, -1);
+  fail_unless (msg != NULL);
+  fail_unless (GST_MESSAGE_TYPE (msg) != GST_MESSAGE_ERROR);
+  fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS);
+  gst_message_unref (msg);
+
+  /* last-buffer should be != NULL */
+  g_object_get (sink, "last-buffer", &last_buffer, NULL);
+  fail_unless (last_buffer != NULL);
+  gst_buffer_unref (last_buffer);
+
+  /* set enable-last-buffer to FALSE now, this should set last-buffer to NULL */
+  g_object_set (sink, "enable-last-buffer", FALSE, NULL);
+  g_object_get (sink, "last-buffer", &last_buffer, NULL);
+  fail_unless (last_buffer == NULL);
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+
+  GST_INFO ("stopped");
+
+  gst_object_unref (bus);
+  gst_object_unref (pipeline);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (basesink_last_buffer_disabled)
+{
+  GstElement *src, *sink, *pipeline;
+  GstBus *bus;
+  GstMessage *msg;
+  GstBuffer *last_buffer;
+
+  pipeline = gst_pipeline_new ("pipeline");
+  sink = gst_element_factory_make ("fakesink", "sink");
+  src = gst_element_factory_make ("fakesrc", "src");
+
+  fail_unless (gst_bin_add (GST_BIN (pipeline), src) == TRUE);
+  fail_unless (gst_bin_add (GST_BIN (pipeline), sink) == TRUE);
+  fail_unless (gst_element_link (src, sink) == TRUE);
+
+  bus = gst_element_get_bus (pipeline);
+
+  /* set enable-last-buffer to FALSE */
+  g_object_set (src, "num-buffers", 1, NULL);
+  g_object_set (sink, "enable-last-buffer", FALSE, NULL);
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+  msg = gst_bus_poll (bus, GST_MESSAGE_EOS | GST_MESSAGE_ERROR, -1);
+  fail_unless (msg != NULL);
+  fail_unless (GST_MESSAGE_TYPE (msg) != GST_MESSAGE_ERROR);
+  fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS);
+  gst_message_unref (msg);
+
+  /* last-buffer should be NULL */
+  g_object_get (sink, "last-buffer", &last_buffer, NULL);
+  fail_unless (last_buffer == NULL);
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+
+  GST_INFO ("stopped");
+
+  gst_object_unref (bus);
+  gst_object_unref (pipeline);
+}
+
+GST_END_TEST;
+
+static Suite *
+gst_basesrc_suite (void)
+{
+  Suite *s = suite_create ("GstBaseSink");
+  TCase *tc = tcase_create ("general");
+
+  suite_add_tcase (s, tc);
+  tcase_add_test (tc, basesink_last_buffer_enabled);
+  tcase_add_test (tc, basesink_last_buffer_disabled);
+
+  return s;
+}
+
+GST_CHECK_MAIN (gst_basesrc);