Merge branch 'master' into 0.11
[platform/upstream/gst-plugins-base.git] / gst-libs / gst / app / gstappsink.c
index 871d6f0..25c95eb 100644 (file)
@@ -19,9 +19,9 @@
  */
 /**
  * SECTION:gstappsink
- * @short_description: Easy way for applications to extract buffers from a
+ * @short_description: Easy way for applications to extract samples from a
  *     pipeline
- * @see_also: #GstBaseSink, appsrc
+ * @see_also: #GstSample, #GstBaseSink, appsrc
  *
  * Appsink is a sink plugin that supports many different methods for making
  * the application get a handle on the GStreamer data in a pipeline. Unlike
  * appsink can be used by linking to the gstappsink.h header file to access the
  * methods or by using the appsink action signals and properties.
  *
- * The normal way of retrieving buffers from appsink is by using the
- * gst_app_sink_pull_buffer() and gst_app_sink_pull_preroll() methods.
- * These methods block until a buffer becomes available in the sink or when the
+ * The normal way of retrieving samples from appsink is by using the
+ * gst_app_sink_pull_sample() and gst_app_sink_pull_preroll() methods.
+ * These methods block until a sample becomes available in the sink or when the
  * sink is shut down or reaches EOS.
  *
  * Appsink will internally use a queue to collect buffers from the streaming
- * thread. If the application is not pulling buffers fast enough, this queue
+ * thread. If the application is not pulling samples fast enough, this queue
  * will consume a lot of memory over time. The "max-buffers" property can be
  * used to limit the queue size. The "drop" property controls whether the
  * streaming thread blocks or if older buffers are dropped when the maximum
  * affect real-time performance and should be avoided.
  *
  * If a blocking behaviour is not desirable, setting the "emit-signals" property
- * to %TRUE will make appsink emit the "new-buffer" and "new-preroll" signals
- * when a buffer can be pulled without blocking.
+ * to %TRUE will make appsink emit the "new-sample" and "new-preroll" signals
+ * when a sample can be pulled without blocking.
  *
  * The "caps" property on appsink can be used to control the formats that
  * appsink can receive. This property can contain non-fixed caps, the format of
- * the pulled buffers can be obtained by getting the buffer caps.
+ * the pulled samples can be obtained by getting the sample caps.
  *
- * If one of the pull-preroll or pull-buffer methods return %NULL, the appsink
+ * If one of the pull-preroll or pull-sample methods return %NULL, the appsink
  * is stopped or in the EOS state. You can check for the EOS state with the
  * "eos" property or with the gst_app_sink_is_eos() method.
  *
 #include <gst/gst.h>
 #include <gst/base/gstbasesink.h>
 #include <gst/gstbuffer.h>
-#include <gst/gstbufferlist.h>
 
 #include <string.h>
 
+#include "gstapp-marshal.h"
 #include "gstappsink.h"
 
 #include "gst/glib-compat-private.h"
@@ -82,6 +82,7 @@ struct _GstAppSinkPrivate
 {
   GstCaps *caps;
   gboolean emit_signals;
+  guint num_buffers;
   guint max_buffers;
   gboolean drop;
 
@@ -89,6 +90,9 @@ struct _GstAppSinkPrivate
   GMutex *mutex;
   GQueue *queue;
   GstBuffer *preroll;
+  GstCaps *preroll_caps;
+  GstCaps *last_caps;
+  GstSegment last_segment;
   gboolean flushing;
   gboolean unlock;
   gboolean started;
@@ -97,8 +101,6 @@ struct _GstAppSinkPrivate
   GstAppSinkCallbacks callbacks;
   gpointer user_data;
   GDestroyNotify notify;
-
-  gboolean buffer_lists_supported;
 };
 
 GST_DEBUG_CATEGORY_STATIC (app_sink_debug);
@@ -109,13 +111,11 @@ enum
   /* signals */
   SIGNAL_EOS,
   SIGNAL_NEW_PREROLL,
-  SIGNAL_NEW_BUFFER,
-  SIGNAL_NEW_BUFFER_LIST,
+  SIGNAL_NEW_SAMPLE,
 
   /* actions */
   SIGNAL_PULL_PREROLL,
-  SIGNAL_PULL_BUFFER,
-  SIGNAL_PULL_BUFFER_LIST,
+  SIGNAL_PULL_SAMPLE,
 
   LAST_SIGNAL
 };
@@ -161,87 +161,27 @@ static gboolean gst_app_sink_event (GstBaseSink * sink, GstEvent * event);
 static gboolean gst_app_sink_query (GstBaseSink * bsink, GstQuery * query);
 static GstFlowReturn gst_app_sink_preroll (GstBaseSink * psink,
     GstBuffer * buffer);
-static GstFlowReturn gst_app_sink_render_common (GstBaseSink * psink,
-    GstMiniObject * data, gboolean is_list);
 static GstFlowReturn gst_app_sink_render (GstBaseSink * psink,
     GstBuffer * buffer);
-static GstFlowReturn gst_app_sink_render_list (GstBaseSink * psink,
-    GstBufferList * list);
-static GstCaps *gst_app_sink_getcaps (GstBaseSink * psink);
-static GstMiniObject *gst_app_sink_pull_object (GstAppSink * appsink);
+static gboolean gst_app_sink_setcaps (GstBaseSink * sink, GstCaps * caps);
+static GstCaps *gst_app_sink_getcaps (GstBaseSink * psink, GstCaps * filter);
 
 static guint gst_app_sink_signals[LAST_SIGNAL] = { 0 };
 
-static void
-_do_init (GType filesrc_type)
-{
-  static const GInterfaceInfo urihandler_info = {
-    gst_app_sink_uri_handler_init,
-    NULL,
-    NULL
-  };
-  g_type_add_interface_static (filesrc_type, GST_TYPE_URI_HANDLER,
-      &urihandler_info);
-}
-
-GST_BOILERPLATE_FULL (GstAppSink, gst_app_sink, GstBaseSink, GST_TYPE_BASE_SINK,
-    _do_init);
-
-/* Can't use glib-genmarshal for this, as it doesn't know how to handle
- * GstMiniObject-based types, which are a new fundamental type */
-static void
-gst_app_marshal_BUFFER__VOID (GClosure * closure,
-    GValue * return_value,
-    guint n_param_values,
-    const GValue * param_values,
-    gpointer invocation_hint, gpointer marshal_data)
-{
-  typedef GstBuffer *(*GMarshalFunc_BUFFER__VOID) (gpointer data1,
-      gpointer data2);
-  register GMarshalFunc_BUFFER__VOID callback;
-  register GCClosure *cc = (GCClosure *) closure;
-  register gpointer data1, data2;
-  GstBuffer *v_return;
-
-  g_return_if_fail (return_value != NULL);
-  g_return_if_fail (n_param_values == 1);
-
-  if (G_CCLOSURE_SWAP_DATA (closure)) {
-    data1 = closure->data;
-    data2 = g_value_peek_pointer (param_values + 0);
-  } else {
-    data1 = g_value_peek_pointer (param_values + 0);
-    data2 = closure->data;
-  }
-  callback =
-      (GMarshalFunc_BUFFER__VOID) (marshal_data ? marshal_data : cc->callback);
-
-  v_return = callback (data1, data2);
-
-  gst_value_take_buffer (return_value, v_return);
-}
-
-static void
-gst_app_sink_base_init (gpointer g_class)
-{
-  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
-  GST_DEBUG_CATEGORY_INIT (app_sink_debug, "appsink", 0, "appsink element");
-
-  gst_element_class_set_details_simple (element_class, "AppSink",
-      "Generic/Sink", "Allow the application to get access to raw buffer",
-      "David Schleef <ds@schleef.org>, Wim Taymans <wim.taymans@gmail.com>");
-
-  gst_element_class_add_static_pad_template (element_class,
-      &gst_app_sink_template);
-}
+#define gst_app_sink_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstAppSink, gst_app_sink, GST_TYPE_BASE_SINK,
+    G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER,
+        gst_app_sink_uri_handler_init));
 
 static void
 gst_app_sink_class_init (GstAppSinkClass * klass)
 {
   GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *element_class = (GstElementClass *) klass;
   GstBaseSinkClass *basesink_class = (GstBaseSinkClass *) klass;
 
+  GST_DEBUG_CATEGORY_INIT (app_sink_debug, "appsink", 0, "appsink element");
+
   gobject_class->dispose = gst_app_sink_dispose;
   gobject_class->finalize = gst_app_sink_finalize;
 
@@ -290,12 +230,12 @@ gst_app_sink_class_init (GstAppSinkClass * klass)
    * GstAppSink::new-preroll:
    * @appsink: the appsink element that emitted the signal
    *
-   * Signal that a new preroll buffer is available.
+   * Signal that a new preroll sample is available.
    *
    * This signal is emitted from the steaming thread and only when the
    * "emit-signals" property is %TRUE.
    *
-   * The new preroll buffer can be retrieved with the "pull-preroll" action
+   * The new preroll sample can be retrieved with the "pull-preroll" action
    * signal or gst_app_sink_pull_preroll() either from this signal callback
    * or from any other thread.
    *
@@ -307,126 +247,87 @@ gst_app_sink_class_init (GstAppSinkClass * klass)
       G_STRUCT_OFFSET (GstAppSinkClass, new_preroll),
       NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
   /**
-   * GstAppSink::new-buffer:
-   * @appsink: the appsink element that emitted the signal
+   * GstAppSink::new-sample:
+   * @appsink: the appsink element that emited the signal
    *
-   * Signal that a new buffer is available.
+   * Signal that a new sample is available.
    *
    * This signal is emitted from the steaming thread and only when the
    * "emit-signals" property is %TRUE.
    *
-   * The new buffer can be retrieved with the "pull-buffer" action
-   * signal or gst_app_sink_pull_buffer() either from this signal callback
+   * The new sample can be retrieved with the "pull-sample" action
+   * signal or gst_app_sink_pull_sample() either from this signal callback
    * or from any other thread.
    *
    * Note that this signal is only emitted when the "emit-signals" property is
    * set to %TRUE, which it is not by default for performance reasons.
    */
-  gst_app_sink_signals[SIGNAL_NEW_BUFFER] =
-      g_signal_new ("new-buffer", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
-      G_STRUCT_OFFSET (GstAppSinkClass, new_buffer),
-      NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
-  /**
-   * GstAppSink::new-buffer-list:
-   * @appsink: the appsink element that emitted the signal
-   *
-   * Signal that a new bufferlist is available.
-   *
-   * This signal is emitted from the steaming thread and only when the
-   * "emit-signals" property is %TRUE.
-   *
-   * The new buffer can be retrieved with the "pull-buffer-list" action
-   * signal or gst_app_sink_pull_buffer_list() either from this signal callback
-   * or from any other thread.
-   *
-   * Note that this signal is only emitted when the "emit-signals" property is
-   * set to %TRUE, which it is not by default for performance reasons.
-   */
-  gst_app_sink_signals[SIGNAL_NEW_BUFFER_LIST] =
-      g_signal_new ("new-buffer-list", G_TYPE_FROM_CLASS (klass),
-      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstAppSinkClass, new_buffer_list),
+  gst_app_sink_signals[SIGNAL_NEW_SAMPLE] =
+      g_signal_new ("new-sample", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
+      G_STRUCT_OFFSET (GstAppSinkClass, new_sample),
       NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
 
   /**
    * GstAppSink::pull-preroll:
    * @appsink: the appsink element to emit this signal on
    *
-   * Get the last preroll buffer in @appsink. This was the buffer that caused the
-   * appsink to preroll in the PAUSED state. This buffer can be pulled many times
+   * Get the last preroll sample in @appsink. This was the sample that caused the
+   * appsink to preroll in the PAUSED state. This sample can be pulled many times
    * and remains available to the application even after EOS.
    *
    * This function is typically used when dealing with a pipeline in the PAUSED
-   * state. Calling this function after doing a seek will give the buffer right
+   * state. Calling this function after doing a seek will give the sample right
    * after the seek position.
    *
-   * Note that the preroll buffer will also be returned as the first buffer
-   * when calling gst_app_sink_pull_buffer() or the "pull-buffer" action signal.
+   * Note that the preroll sample will also be returned as the first sample
+   * when calling gst_app_sink_pull_sample() or the "pull-sample" action signal.
    *
    * If an EOS event was received before any buffers, this function returns
    * %NULL. Use gst_app_sink_is_eos () to check for the EOS condition.
    *
-   * This function blocks until a preroll buffer or EOS is received or the appsink
+   * This function blocks until a preroll sample or EOS is received or the appsink
    * element is set to the READY/NULL state.
    *
-   * Returns: a #GstBuffer or NULL when the appsink is stopped or EOS.
+   * Returns: a #GstSample or NULL when the appsink is stopped or EOS.
    */
   gst_app_sink_signals[SIGNAL_PULL_PREROLL] =
       g_signal_new ("pull-preroll", G_TYPE_FROM_CLASS (klass),
       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstAppSinkClass,
-          pull_preroll), NULL, NULL, gst_app_marshal_BUFFER__VOID,
-      GST_TYPE_BUFFER, 0, G_TYPE_NONE);
+          pull_preroll), NULL, NULL, __gst_app_marshal_BOXED__VOID,
+      GST_TYPE_SAMPLE, 0, G_TYPE_NONE);
   /**
-   * GstAppSink::pull-buffer:
+   * GstAppSink::pull-sample:
    * @appsink: the appsink element to emit this signal on
    *
-   * This function blocks until a buffer or EOS becomes available or the appsink
+   * This function blocks until a sample or EOS becomes available or the appsink
    * element is set to the READY/NULL state.
    *
-   * This function will only return buffers when the appsink is in the PLAYING
-   * state. All rendered buffers will be put in a queue so that the application
-   * can pull buffers at its own rate.
+   * This function will only return samples when the appsink is in the PLAYING
+   * state. All rendered samples will be put in a queue so that the application
+   * can pull samples at its own rate.
    *
-   * Note that when the application does not pull buffers fast enough, the
-   * queued buffers could consume a lot of memory, especially when dealing with
+   * Note that when the application does not pull samples fast enough, the
+   * queued samples could consume a lot of memory, especially when dealing with
    * raw video frames. It's possible to control the behaviour of the queue with
    * the "drop" and "max-buffers" properties.
    *
    * If an EOS event was received before any buffers, this function returns
    * %NULL. Use gst_app_sink_is_eos () to check for the EOS condition.
    *
-   * Returns: a #GstBuffer or NULL when the appsink is stopped or EOS.
+   * Returns: a #GstSample or NULL when the appsink is stopped or EOS.
    */
-  gst_app_sink_signals[SIGNAL_PULL_BUFFER] =
-      g_signal_new ("pull-buffer", G_TYPE_FROM_CLASS (klass),
+  gst_app_sink_signals[SIGNAL_PULL_SAMPLE] =
+      g_signal_new ("pull-sample", G_TYPE_FROM_CLASS (klass),
       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstAppSinkClass,
-          pull_buffer), NULL, NULL, gst_app_marshal_BUFFER__VOID,
-      GST_TYPE_BUFFER, 0, G_TYPE_NONE);
-  /**
-   * GstAppSink::pull-buffer-list:
-   * @appsink: the appsink element to emit this signal on
-   *
-   * This function blocks until a buffer list or EOS becomes available or the appsink
-   * element is set to the READY/NULL state.
-   *
-   * This function will only return bufferlists when the appsink is in the PLAYING
-   * state. All rendered bufferlists will be put in a queue so that the application
-   * can pull bufferlists at its own rate.
-   *
-   * Note that when the application does not pull bufferlists fast enough, the
-   * queued bufferlists could consume a lot of memory, especially when dealing with
-   * raw video frames. It's possible to control the behaviour of the queue with
-   * the "drop" and "max-buffers" properties.
-   *
-   * If an EOS event was received before any buffers, this function returns
-   * %NULL. Use gst_app_sink_is_eos () to check for the EOS condition.
-   *
-   * Returns: a #GstBufferList or NULL when the appsink is stopped or EOS.
-   */
-  gst_app_sink_signals[SIGNAL_PULL_BUFFER_LIST] =
-      g_signal_new ("pull-buffer-list", G_TYPE_FROM_CLASS (klass),
-      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstAppSinkClass,
-          pull_buffer_list), NULL, NULL, gst_app_marshal_BUFFER__VOID,
-      GST_TYPE_BUFFER_LIST, 0, G_TYPE_NONE);
+          pull_sample), NULL, NULL, __gst_app_marshal_BOXED__VOID,
+      GST_TYPE_SAMPLE, 0, G_TYPE_NONE);
+
+  gst_element_class_set_details_simple (element_class, "AppSink",
+      "Generic/Sink", "Allow the application to get access to raw buffer",
+      "David Schleef <ds@schleef.org>, Wim Taymans <wim.taymans@gmail.com>");
+
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&gst_app_sink_template));
 
   basesink_class->unlock = gst_app_sink_unlock_start;
   basesink_class->unlock_stop = gst_app_sink_unlock_stop;
@@ -435,19 +336,18 @@ gst_app_sink_class_init (GstAppSinkClass * klass)
   basesink_class->event = gst_app_sink_event;
   basesink_class->preroll = gst_app_sink_preroll;
   basesink_class->render = gst_app_sink_render;
-  basesink_class->render_list = gst_app_sink_render_list;
   basesink_class->get_caps = gst_app_sink_getcaps;
+  basesink_class->set_caps = gst_app_sink_setcaps;
   basesink_class->query = gst_app_sink_query;
 
   klass->pull_preroll = gst_app_sink_pull_preroll;
-  klass->pull_buffer = gst_app_sink_pull_buffer;
-  klass->pull_buffer_list = gst_app_sink_pull_buffer_list;
+  klass->pull_sample = gst_app_sink_pull_sample;
 
   g_type_class_add_private (klass, sizeof (GstAppSinkPrivate));
 }
 
 static void
-gst_app_sink_init (GstAppSink * appsink, GstAppSinkClass * klass)
+gst_app_sink_init (GstAppSink * appsink)
 {
   GstAppSinkPrivate *priv;
 
@@ -485,12 +385,11 @@ gst_app_sink_dispose (GObject * obj)
   GST_OBJECT_UNLOCK (appsink);
 
   g_mutex_lock (priv->mutex);
-  if (priv->preroll) {
-    gst_buffer_unref (priv->preroll);
-    priv->preroll = NULL;
-  }
   while ((queue_obj = g_queue_pop_head (priv->queue)))
     gst_mini_object_unref (queue_obj);
+  gst_buffer_replace (&priv->preroll, NULL);
+  gst_caps_replace (&priv->preroll_caps, NULL);
+  gst_caps_replace (&priv->last_caps, NULL);
   g_mutex_unlock (priv->mutex);
 
   G_OBJECT_CLASS (parent_class)->dispose (obj);
@@ -610,24 +509,10 @@ gst_app_sink_flush_unlocked (GstAppSink * appsink)
   gst_buffer_replace (&priv->preroll, NULL);
   while ((obj = g_queue_pop_head (priv->queue)))
     gst_mini_object_unref (obj);
+  priv->num_buffers = 0;
   g_cond_signal (priv->cond);
 }
 
-#define NEW_BUFFER_LIST_SIGID \
-    gst_app_sink_signals[SIGNAL_NEW_BUFFER_LIST]
-
-static gboolean
-gst_app_sink_check_buffer_lists_support (GstAppSink * appsink)
-{
-  gboolean ret;
-
-  ret = (appsink->priv->callbacks.new_buffer_list != NULL) ||
-      g_signal_has_handler_pending (appsink, NEW_BUFFER_LIST_SIGID, 0, FALSE);
-
-  GST_INFO_OBJECT (appsink, "application supports buffer lists: %d", ret);
-  return ret;
-}
-
 static gboolean
 gst_app_sink_start (GstBaseSink * psink)
 {
@@ -638,8 +523,7 @@ gst_app_sink_start (GstBaseSink * psink)
   GST_DEBUG_OBJECT (appsink, "starting");
   priv->flushing = FALSE;
   priv->started = TRUE;
-  priv->buffer_lists_supported =
-      gst_app_sink_check_buffer_lists_support (appsink);
+  gst_segment_init (&priv->last_segment, GST_FORMAT_TIME);
   g_mutex_unlock (priv->mutex);
 
   return TRUE;
@@ -656,6 +540,23 @@ gst_app_sink_stop (GstBaseSink * psink)
   priv->flushing = TRUE;
   priv->started = FALSE;
   gst_app_sink_flush_unlocked (appsink);
+  gst_caps_replace (&priv->preroll_caps, NULL);
+  gst_caps_replace (&priv->last_caps, NULL);
+  g_mutex_unlock (priv->mutex);
+
+  return TRUE;
+}
+
+static gboolean
+gst_app_sink_setcaps (GstBaseSink * sink, GstCaps * caps)
+{
+  GstAppSink *appsink = GST_APP_SINK_CAST (sink);
+  GstAppSinkPrivate *priv = appsink->priv;
+
+  g_mutex_lock (priv->mutex);
+  GST_DEBUG_OBJECT (appsink, "receiving CAPS");
+  g_queue_push_tail (priv->queue, gst_event_new_caps (caps));
+  gst_caps_replace (&priv->preroll_caps, caps);
   g_mutex_unlock (priv->mutex);
 
   return TRUE;
@@ -668,8 +569,13 @@ gst_app_sink_event (GstBaseSink * sink, GstEvent * event)
   GstAppSinkPrivate *priv = appsink->priv;
 
   switch (event->type) {
+    case GST_EVENT_SEGMENT:
+      g_mutex_lock (priv->mutex);
+      GST_DEBUG_OBJECT (appsink, "receiving SEGMENT");
+      g_queue_push_tail (priv->queue, gst_event_ref (event));
+      g_mutex_unlock (priv->mutex);
+      break;
     case GST_EVENT_EOS:
-
       g_mutex_lock (priv->mutex);
       GST_DEBUG_OBJECT (appsink, "receiving EOS");
       priv->is_eos = TRUE;
@@ -697,7 +603,7 @@ gst_app_sink_event (GstBaseSink * sink, GstEvent * event)
     default:
       break;
   }
-  return TRUE;
+  return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
 }
 
 static GstFlowReturn
@@ -730,13 +636,56 @@ flushing:
   {
     GST_DEBUG_OBJECT (appsink, "we are flushing");
     g_mutex_unlock (priv->mutex);
-    return GST_FLOW_WRONG_STATE;
+    return GST_FLOW_FLUSHING;
   }
 }
 
+static GstBuffer *
+dequeue_buffer (GstAppSink * appsink)
+{
+  GstAppSinkPrivate *priv = appsink->priv;
+  GstBuffer *buffer;
+
+  do {
+    GstMiniObject *obj;
+
+    obj = g_queue_pop_head (priv->queue);
+
+    if (GST_IS_BUFFER (obj)) {
+      buffer = GST_BUFFER_CAST (obj);
+      GST_DEBUG_OBJECT (appsink, "dequeued buffer %p", buffer);
+      priv->num_buffers--;
+      break;
+    } else if (GST_IS_EVENT (obj)) {
+      GstEvent *event = GST_EVENT_CAST (obj);
+
+      switch (GST_EVENT_TYPE (obj)) {
+        case GST_EVENT_CAPS:
+        {
+          GstCaps *caps;
+
+          gst_event_parse_caps (event, &caps);
+          GST_DEBUG_OBJECT (appsink, "activating caps %" GST_PTR_FORMAT, caps);
+          gst_caps_replace (&priv->last_caps, caps);
+          break;
+        }
+        case GST_EVENT_SEGMENT:
+          gst_event_copy_segment (event, &priv->last_segment);
+          GST_DEBUG_OBJECT (appsink, "activated segment %" GST_SEGMENT_FORMAT,
+              &priv->last_segment);
+          break;
+        default:
+          break;
+      }
+      gst_mini_object_unref (obj);
+    }
+  } while (TRUE);
+
+  return buffer;
+}
+
 static GstFlowReturn
-gst_app_sink_render_common (GstBaseSink * psink, GstMiniObject * data,
-    gboolean is_list)
+gst_app_sink_render (GstBaseSink * psink, GstBuffer * buffer)
 {
   GstFlowReturn ret;
   GstAppSink *appsink = GST_APP_SINK_CAST (psink);
@@ -748,20 +697,21 @@ restart:
   if (priv->flushing)
     goto flushing;
 
-  GST_DEBUG_OBJECT (appsink, "pushing render buffer%s %p on queue (%d)",
-      is_list ? " list" : "", data, priv->queue->length);
+  GST_DEBUG_OBJECT (appsink, "pushing render buffer %p on queue (%d)",
+      buffer, priv->num_buffers);
 
-  while (priv->max_buffers > 0 && priv->queue->length >= priv->max_buffers) {
+  while (priv->max_buffers > 0 && priv->num_buffers >= priv->max_buffers) {
     if (priv->drop) {
-      GstMiniObject *obj;
+      GstBuffer *old;
 
-      /* we need to drop the oldest buffer/list and try again */
-      obj = g_queue_pop_head (priv->queue);
-      GST_DEBUG_OBJECT (appsink, "dropping old buffer/list %p", obj);
-      gst_mini_object_unref (obj);
+      /* we need to drop the oldest buffer and try again */
+      if ((old = dequeue_buffer (appsink))) {
+        GST_DEBUG_OBJECT (appsink, "dropping old buffer %p", old);
+        gst_buffer_unref (old);
+      }
     } else {
       GST_DEBUG_OBJECT (appsink, "waiting for free space, length %d >= %d",
-          priv->queue->length, priv->max_buffers);
+          priv->num_buffers, priv->max_buffers);
 
       if (priv->unlock) {
         /* we are asked to unlock, call the wait_preroll method */
@@ -780,29 +730,24 @@ restart:
     }
   }
   /* we need to ref the buffer when pushing it in the queue */
-  g_queue_push_tail (priv->queue, gst_mini_object_ref (data));
+  g_queue_push_tail (priv->queue, gst_buffer_ref (buffer));
+  priv->num_buffers++;
   g_cond_signal (priv->cond);
   emit = priv->emit_signals;
   g_mutex_unlock (priv->mutex);
 
-  if (is_list) {
-    if (priv->callbacks.new_buffer_list)
-      priv->callbacks.new_buffer_list (appsink, priv->user_data);
-    else if (emit)
-      g_signal_emit (appsink, gst_app_sink_signals[SIGNAL_NEW_BUFFER_LIST], 0);
-  } else {
-    if (priv->callbacks.new_buffer)
-      priv->callbacks.new_buffer (appsink, priv->user_data);
-    else if (emit)
-      g_signal_emit (appsink, gst_app_sink_signals[SIGNAL_NEW_BUFFER], 0);
-  }
+  if (priv->callbacks.new_sample)
+    priv->callbacks.new_sample (appsink, priv->user_data);
+  else if (emit)
+    g_signal_emit (appsink, gst_app_sink_signals[SIGNAL_NEW_SAMPLE], 0);
+
   return GST_FLOW_OK;
 
 flushing:
   {
     GST_DEBUG_OBJECT (appsink, "we are flushing");
     g_mutex_unlock (priv->mutex);
-    return GST_FLOW_WRONG_STATE;
+    return GST_FLOW_FLUSHING;
   }
 stopping:
   {
@@ -811,66 +756,20 @@ stopping:
   }
 }
 
-static GstFlowReturn
-gst_app_sink_render (GstBaseSink * psink, GstBuffer * buffer)
-{
-  return gst_app_sink_render_common (psink, GST_MINI_OBJECT_CAST (buffer),
-      FALSE);
-}
-
-static GstFlowReturn
-gst_app_sink_render_list (GstBaseSink * sink, GstBufferList * list)
-{
-  GstBufferListIterator *it;
-  GstFlowReturn flow;
-  GstAppSink *appsink;
-  GstBuffer *group;
-
-  appsink = GST_APP_SINK_CAST (sink);
-
-  if (appsink->priv->buffer_lists_supported)
-    return gst_app_sink_render_common (sink, GST_MINI_OBJECT_CAST (list), TRUE);
-
-  /* The application doesn't support buffer lists, extract individual buffers
-   * then and push them one-by-one */
-  GST_INFO_OBJECT (sink, "chaining each group in list as a merged buffer");
-
-  it = gst_buffer_list_iterate (list);
-
-  if (gst_buffer_list_iterator_next_group (it)) {
-    do {
-      group = gst_buffer_list_iterator_merge_group (it);
-      if (group == NULL) {
-        group = gst_buffer_new ();
-        GST_DEBUG_OBJECT (sink, "chaining empty group");
-      } else {
-        GST_DEBUG_OBJECT (sink, "chaining group");
-      }
-      flow = gst_app_sink_render (sink, group);
-      gst_buffer_unref (group);
-    } while (flow == GST_FLOW_OK && gst_buffer_list_iterator_next_group (it));
-  } else {
-    GST_DEBUG_OBJECT (sink, "chaining empty group");
-    group = gst_buffer_new ();
-    flow = gst_app_sink_render (sink, group);
-    gst_buffer_unref (group);
-  }
-
-  gst_buffer_list_iterator_free (it);
-
-  return flow;
-}
-
 static GstCaps *
-gst_app_sink_getcaps (GstBaseSink * psink)
+gst_app_sink_getcaps (GstBaseSink * psink, GstCaps * filter)
 {
   GstCaps *caps;
   GstAppSink *appsink = GST_APP_SINK_CAST (psink);
   GstAppSinkPrivate *priv = appsink->priv;
 
   GST_OBJECT_LOCK (appsink);
-  if ((caps = priv->caps))
-    gst_caps_ref (caps);
+  if ((caps = priv->caps)) {
+    if (filter)
+      caps = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+    else
+      gst_caps_ref (caps);
+  }
   GST_DEBUG_OBJECT (appsink, "got caps %" GST_PTR_FORMAT, caps);
   GST_OBJECT_UNLOCK (appsink);
 
@@ -901,55 +800,6 @@ gst_app_sink_query (GstBaseSink * bsink, GstQuery * query)
   return ret;
 }
 
-static GstMiniObject *
-gst_app_sink_pull_object (GstAppSink * appsink)
-{
-  GstMiniObject *obj = NULL;
-  GstAppSinkPrivate *priv;
-
-  g_return_val_if_fail (GST_IS_APP_SINK (appsink), NULL);
-
-  priv = appsink->priv;
-
-  g_mutex_lock (priv->mutex);
-
-  while (TRUE) {
-    GST_DEBUG_OBJECT (appsink, "trying to grab a buffer/list");
-    if (!priv->started)
-      goto not_started;
-
-    if (!g_queue_is_empty (priv->queue))
-      break;
-
-    if (priv->is_eos)
-      goto eos;
-
-    /* nothing to return, wait */
-    GST_DEBUG_OBJECT (appsink, "waiting for a buffer/list");
-    g_cond_wait (priv->cond, priv->mutex);
-  }
-  obj = g_queue_pop_head (priv->queue);
-  GST_DEBUG_OBJECT (appsink, "we have a buffer/list %p", obj);
-  g_cond_signal (priv->cond);
-  g_mutex_unlock (priv->mutex);
-
-  return obj;
-
-  /* special conditions */
-eos:
-  {
-    GST_DEBUG_OBJECT (appsink, "we are EOS, return NULL");
-    g_mutex_unlock (priv->mutex);
-    return NULL;
-  }
-not_started:
-  {
-    GST_DEBUG_OBJECT (appsink, "we are stopped, return NULL");
-    g_mutex_unlock (priv->mutex);
-    return NULL;
-  }
-}
-
 /* external API */
 
 /**
@@ -1020,13 +870,13 @@ gst_app_sink_get_caps (GstAppSink * appsink)
  * gst_app_sink_is_eos:
  * @appsink: a #GstAppSink
  *
- * Check if @appsink is EOS, which is when no more buffers can be pulled because
+ * Check if @appsink is EOS, which is when no more samples can be pulled because
  * an EOS event was received.
  *
  * This function also returns %TRUE when the appsink is not in the PAUSED or
  * PLAYING state.
  *
- * Returns: %TRUE if no more buffers can be pulled and the appsink is EOS.
+ * Returns: %TRUE if no more samples can be pulled and the appsink is EOS.
  *
  * Since: 0.10.22
  */
@@ -1044,7 +894,7 @@ gst_app_sink_is_eos (GstAppSink * appsink)
   if (!priv->started)
     goto not_started;
 
-  if (priv->is_eos && g_queue_is_empty (priv->queue)) {
+  if (priv->is_eos && priv->num_buffers == 0) {
     GST_DEBUG_OBJECT (appsink, "we are EOS and the queue is empty");
     ret = TRUE;
   } else {
@@ -1068,7 +918,7 @@ not_started:
  * @appsink: a #GstAppSink
  * @emit: the new state
  *
- * Make appsink emit the "new-preroll" and "new-buffer" signals. This option is
+ * Make appsink emit the "new-preroll" and "new-sample" signals. This option is
  * by default disabled because signal emission is expensive and unneeded when
  * the application prefers to operate in pull mode.
  *
@@ -1092,9 +942,9 @@ gst_app_sink_set_emit_signals (GstAppSink * appsink, gboolean emit)
  * gst_app_sink_get_emit_signals:
  * @appsink: a #GstAppSink
  *
- * Check if appsink will emit the "new-preroll" and "new-buffer" signals.
+ * Check if appsink will emit the "new-preroll" and "new-sample" signals.
  *
- * Returns: %TRUE if @appsink is emitting the "new-preroll" and "new-buffer"
+ * Returns: %TRUE if @appsink is emiting the "new-preroll" and "new-sample"
  * signals.
  *
  * Since: 0.10.22
@@ -1123,7 +973,7 @@ gst_app_sink_get_emit_signals (GstAppSink * appsink)
  *
  * Set the maximum amount of buffers that can be queued in @appsink. After this
  * amount of buffers are queued in appsink, any more buffers will block upstream
- * elements until a buffer is pulled from @appsink.
+ * elements until a sample is pulled from @appsink.
  *
  * Since: 0.10.22
  */
@@ -1233,31 +1083,31 @@ gst_app_sink_get_drop (GstAppSink * appsink)
  * gst_app_sink_pull_preroll:
  * @appsink: a #GstAppSink
  *
- * Get the last preroll buffer in @appsink. This was the buffer that caused the
- * appsink to preroll in the PAUSED state. This buffer can be pulled many times
+ * Get the last preroll sample in @appsink. This was the sample that caused the
+ * appsink to preroll in the PAUSED state. This sample can be pulled many times
  * and remains available to the application even after EOS.
  *
  * This function is typically used when dealing with a pipeline in the PAUSED
- * state. Calling this function after doing a seek will give the buffer right
+ * state. Calling this function after doing a seek will give the sample right
  * after the seek position.
  *
- * Note that the preroll buffer will also be returned as the first buffer
- * when calling gst_app_sink_pull_buffer().
+ * Note that the preroll sample will also be returned as the first sample
+ * when calling gst_app_sink_pull_sample().
  *
  * If an EOS event was received before any buffers, this function returns
  * %NULL. Use gst_app_sink_is_eos () to check for the EOS condition.
  *
- * This function blocks until a preroll buffer or EOS is received or the appsink
+ * This function blocks until a preroll sample or EOS is received or the appsink
  * element is set to the READY/NULL state.
  *
  * Returns: a #GstBuffer or NULL when the appsink is stopped or EOS.
  *
  * Since: 0.10.22
  */
-GstBuffer *
+GstSample *
 gst_app_sink_pull_preroll (GstAppSink * appsink)
 {
-  GstBuffer *buf = NULL;
+  GstSample *sample = NULL;
   GstAppSinkPrivate *priv;
 
   g_return_val_if_fail (GST_IS_APP_SINK (appsink), NULL);
@@ -1281,11 +1131,13 @@ gst_app_sink_pull_preroll (GstAppSink * appsink)
     GST_DEBUG_OBJECT (appsink, "waiting for the preroll buffer");
     g_cond_wait (priv->cond, priv->mutex);
   }
-  buf = gst_buffer_ref (priv->preroll);
-  GST_DEBUG_OBJECT (appsink, "we have the preroll buffer %p", buf);
+  sample =
+      gst_sample_new (priv->preroll, priv->preroll_caps, &priv->last_segment,
+      NULL);
+  GST_DEBUG_OBJECT (appsink, "we have the preroll sample %p", sample);
   g_mutex_unlock (priv->mutex);
 
-  return buf;
+  return sample;
 
   /* special conditions */
 eos:
@@ -1303,16 +1155,16 @@ not_started:
 }
 
 /**
- * gst_app_sink_pull_buffer:
+ * gst_app_sink_pull_sample:
  * @appsink: a #GstAppSink
  *
- * This function blocks until a buffer or EOS becomes available or the appsink
+ * This function blocks until a sample or EOS becomes available or the appsink
  * element is set to the READY/NULL state.
  *
- * This function will only return buffers when the appsink is in the PLAYING
+ * This function will only return samples when the appsink is in the PLAYING
  * state. All rendered buffers will be put in a queue so that the application
- * can pull buffers at its own rate. Note that when the application does not
- * pull buffers fast enough, the queued buffers could consume a lot of memory,
+ * can pull samples at its own rate. Note that when the application does not
+ * pull samples fast enough, the queued buffers could consume a lot of memory,
  * especially when dealing with raw video frames.
  *
  * If an EOS event was received before any buffers, this function returns
@@ -1323,37 +1175,57 @@ not_started:
  * Since: 0.10.22
  */
 
-GstBuffer *
-gst_app_sink_pull_buffer (GstAppSink * appsink)
+GstSample *
+gst_app_sink_pull_sample (GstAppSink * appsink)
 {
-  GST_DEBUG_OBJECT (appsink, "pull a buffer");
-  return GST_BUFFER_CAST (gst_app_sink_pull_object (appsink));
-}
+  GstSample *sample = NULL;
+  GstBuffer *buffer;
+  GstAppSinkPrivate *priv;
 
-/**
- * gst_app_sink_pull_buffer_list:
- * @appsink: a #GstAppSink
- *
- * This function blocks until a buffer list or EOS becomes available or the
- * appsink element is set to the READY/NULL state.
- *
- * This function will only return buffer lists when the appsink is in the
- * PLAYING state. All rendered buffer lists will be put in a queue so that
- * the application can pull buffer lists at its own rate. Note that when
- * the application does not pull buffer lists fast enough, the queued buffer
- * lists could consume a lot of memory, especially when dealing with raw
- * video frames.
- *
- * If an EOS event was received before any buffer lists, this function returns
- * %NULL. Use gst_app_sink_is_eos () to check for the EOS condition.
- *
- * Returns: a #GstBufferList or NULL when the appsink is stopped or EOS.
- */
-GstBufferList *
-gst_app_sink_pull_buffer_list (GstAppSink * appsink)
-{
-  GST_DEBUG_OBJECT (appsink, "pull a buffer list");
-  return GST_BUFFER_LIST_CAST (gst_app_sink_pull_object (appsink));
+  g_return_val_if_fail (GST_IS_APP_SINK (appsink), NULL);
+
+  priv = appsink->priv;
+
+  g_mutex_lock (priv->mutex);
+
+  while (TRUE) {
+    GST_DEBUG_OBJECT (appsink, "trying to grab a buffer");
+    if (!priv->started)
+      goto not_started;
+
+    if (priv->num_buffers > 0)
+      break;
+
+    if (priv->is_eos)
+      goto eos;
+
+    /* nothing to return, wait */
+    GST_DEBUG_OBJECT (appsink, "waiting for a buffer");
+    g_cond_wait (priv->cond, priv->mutex);
+  }
+  buffer = dequeue_buffer (appsink);
+  GST_DEBUG_OBJECT (appsink, "we have a buffer %p", buffer);
+  sample = gst_sample_new (buffer, priv->last_caps, &priv->last_segment, NULL);
+  gst_buffer_unref (buffer);
+
+  g_cond_signal (priv->cond);
+  g_mutex_unlock (priv->mutex);
+
+  return sample;
+
+  /* special conditions */
+eos:
+  {
+    GST_DEBUG_OBJECT (appsink, "we are EOS, return NULL");
+    g_mutex_unlock (priv->mutex);
+    return NULL;
+  }
+not_started:
+  {
+    GST_DEBUG_OBJECT (appsink, "we are stopped, return NULL");
+    g_mutex_unlock (priv->mutex);
+    return NULL;
+  }
 }
 
 /**
@@ -1363,7 +1235,7 @@ gst_app_sink_pull_buffer_list (GstAppSink * appsink)
  * @user_data: a user_data argument for the callbacks
  * @notify: a destroy notify function
  *
- * Set callbacks which will be executed for each new preroll, new buffer and eos.
+ * Set callbacks which will be executed for each new preroll, new sample and eos.
  * This is an alternative to using the signals, it has lower overhead and is thus
  * less expensive, but also less flexible.
  *
@@ -1403,44 +1275,37 @@ gst_app_sink_set_callbacks (GstAppSink * appsink,
   priv->callbacks = *callbacks;
   priv->user_data = user_data;
   priv->notify = notify;
-  priv->buffer_lists_supported =
-      gst_app_sink_check_buffer_lists_support (appsink);
   GST_OBJECT_UNLOCK (appsink);
 }
 
 /*** GSTURIHANDLER INTERFACE *************************************************/
 
 static GstURIType
-gst_app_sink_uri_get_type (void)
+gst_app_sink_uri_get_type (GType type)
 {
   return GST_URI_SINK;
 }
 
-static gchar **
-gst_app_sink_uri_get_protocols (void)
+static const gchar *const *
+gst_app_sink_uri_get_protocols (GType type)
 {
-  static gchar *protocols[] = { (char *) "appsink", NULL };
+  static const gchar *protocols[] = { "appsink", NULL };
 
   return protocols;
 }
 
-static const gchar *
+static gchar *
 gst_app_sink_uri_get_uri (GstURIHandler * handler)
 {
-  return "appsink";
+  return g_strdup ("appsink");
 }
 
 static gboolean
-gst_app_sink_uri_set_uri (GstURIHandler * handler, const gchar * uri)
+gst_app_sink_uri_set_uri (GstURIHandler * handler, const gchar * uri,
+    GError ** error)
 {
-  gchar *protocol;
-  gboolean ret;
-
-  protocol = gst_uri_get_protocol (uri);
-  ret = !strcmp (protocol, "appsink");
-  g_free (protocol);
-
-  return ret;
+  /* GstURIHandler checks the protocol for us */
+  return TRUE;
 }
 
 static void
@@ -1452,4 +1317,5 @@ gst_app_sink_uri_handler_init (gpointer g_iface, gpointer iface_data)
   iface->get_protocols = gst_app_sink_uri_get_protocols;
   iface->get_uri = gst_app_sink_uri_get_uri;
   iface->set_uri = gst_app_sink_uri_set_uri;
+
 }