summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBranko Subasic <branko.subasic at axis.com>2009-06-16 13:32:37 +0200
committerWim Taymans <wim.taymans@collabora.co.uk>2009-06-16 13:32:37 +0200
commitde5bcfc4cd0d7333ede227bc6d81917922a03a68 (patch)
treefc8edb705f9448c08a3acd3b84f015e303834b7a
parentf44b6671201e6ab99fa6ee26e1b4882f1b5a3bf2 (diff)
basesink: add support for buffer list
Fixes #585960
-rw-r--r--libs/gst/base/gstbasesink.c205
-rw-r--r--libs/gst/base/gstbasesink.h9
2 files changed, 167 insertions, 47 deletions
diff --git a/libs/gst/base/gstbasesink.c b/libs/gst/base/gstbasesink.c
index a0b9d481a7..6fd1fc1a21 100644
--- a/libs/gst/base/gstbasesink.c
+++ b/libs/gst/base/gstbasesink.c
@@ -351,6 +351,9 @@ static GstStateChangeReturn gst_base_sink_change_state (GstElement * element,
GstStateChange transition);
static GstFlowReturn gst_base_sink_chain (GstPad * pad, GstBuffer * buffer);
+static GstFlowReturn gst_base_sink_chain_list (GstPad * pad,
+ GstBufferList * list);
+
static void gst_base_sink_loop (GstPad * pad);
static gboolean gst_base_sink_pad_activate (GstPad * pad);
static gboolean gst_base_sink_pad_activate_push (GstPad * pad, gboolean active);
@@ -365,7 +368,7 @@ static gboolean gst_base_sink_is_too_late (GstBaseSink * basesink,
GstMiniObject * obj, GstClockTime start, GstClockTime stop,
GstClockReturn status, GstClockTimeDiff jitter);
static GstFlowReturn gst_base_sink_preroll_object (GstBaseSink * basesink,
- GstMiniObject * obj);
+ gboolean is_list, GstMiniObject * obj);
static void
gst_base_sink_class_init (GstBaseSinkClass * klass)
@@ -610,6 +613,8 @@ gst_base_sink_init (GstBaseSink * basesink, gpointer g_class)
GST_DEBUG_FUNCPTR (gst_base_sink_event));
gst_pad_set_chain_function (basesink->sinkpad,
GST_DEBUG_FUNCPTR (gst_base_sink_chain));
+ gst_pad_set_chain_list_function (basesink->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_base_sink_chain_list));
gst_element_add_pad (GST_ELEMENT_CAST (basesink), basesink->sinkpad);
basesink->pad_mode = GST_ACTIVATE_NONE;
@@ -2075,7 +2080,7 @@ gst_base_sink_do_preroll (GstBaseSink * sink, GstMiniObject * obj)
while (G_UNLIKELY (sink->need_preroll)) {
GST_DEBUG_OBJECT (sink, "prerolling object %p", obj);
- ret = gst_base_sink_preroll_object (sink, obj);
+ ret = gst_base_sink_preroll_object (sink, FALSE, obj);
if (ret != GST_FLOW_OK)
goto preroll_failed;
@@ -2639,16 +2644,32 @@ gst_base_sink_do_render_stats (GstBaseSink * basesink, gboolean start)
*/
static GstFlowReturn
gst_base_sink_render_object (GstBaseSink * basesink, GstPad * pad,
- GstMiniObject * obj)
+ gboolean is_list, gpointer obj)
{
GstFlowReturn ret;
GstBaseSinkClass *bclass;
gboolean late, step_end;
+ gpointer sync_obj;
GstBaseSinkPrivate *priv;
priv = basesink->priv;
+ if (is_list) {
+ /*
+ * If buffer list, use the first group buffer within the list
+ * for syncing
+ */
+ GstBufferListIterator *it;
+ it = gst_buffer_list_iterate (GST_BUFFER_LIST_CAST (obj));
+ g_assert (gst_buffer_list_iterator_next_group (it));
+ sync_obj = gst_buffer_list_iterator_next (it);
+ gst_buffer_list_iterator_free (it);
+ g_assert (NULL != sync_obj);
+ } else {
+ sync_obj = obj;
+ }
+
again:
late = FALSE;
step_end = FALSE;
@@ -2656,37 +2677,48 @@ again:
/* synchronize this object, non syncable objects return OK
* immediatly. */
- ret = gst_base_sink_do_sync (basesink, pad, obj, &late, &step_end);
+ ret = gst_base_sink_do_sync (basesink, pad, sync_obj, &late, &step_end);
if (G_UNLIKELY (ret != GST_FLOW_OK))
goto sync_failed;
- /* and now render, event or buffer. */
- if (G_LIKELY (GST_IS_BUFFER (obj))) {
- GstBuffer *buf;
-
+ /* and now render, event or buffer/buffer list. */
+ if (G_LIKELY (is_list || GST_IS_BUFFER (obj))) {
/* drop late buffers unconditionally, let's hope it's unlikely */
if (G_UNLIKELY (late))
goto dropped;
- buf = GST_BUFFER_CAST (obj);
-
- gst_base_sink_set_last_buffer (basesink, buf);
-
bclass = GST_BASE_SINK_GET_CLASS (basesink);
- if (G_LIKELY (bclass->render)) {
+ if (G_LIKELY ((is_list && bclass->render_list) ||
+ (!is_list && bclass->render))) {
gint do_qos;
/* read once, to get same value before and after */
do_qos = g_atomic_int_get (&priv->qos_enabled);
- GST_DEBUG_OBJECT (basesink, "rendering buffer %p", obj);
+ GST_DEBUG_OBJECT (basesink, "rendering object %p", obj);
/* record rendering time for QoS and stats */
if (do_qos)
gst_base_sink_do_render_stats (basesink, TRUE);
- ret = bclass->render (basesink, buf);
+ if (!is_list) {
+ GstBuffer *buf;
+
+ /* For buffer lists do not set last buffer. Creating buffer
+ * with meaningful data can be done only with memcpy which will
+ * significantly affect performance */
+ buf = GST_BUFFER_CAST (obj);
+ gst_base_sink_set_last_buffer (basesink, buf);
+
+ ret = bclass->render (basesink, buf);
+ } else {
+ GstBufferList *buflist;
+
+ buflist = GST_BUFFER_LIST_CAST (obj);
+
+ ret = bclass->render_list (basesink, buflist);
+ }
if (do_qos)
gst_base_sink_do_render_stats (basesink, FALSE);
@@ -2769,8 +2801,7 @@ done:
gst_base_sink_perform_qos (basesink, late);
GST_DEBUG_OBJECT (basesink, "object unref after render %p", obj);
- gst_mini_object_unref (obj);
-
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
return ret;
/* ERRORS */
@@ -2802,14 +2833,15 @@ flushing:
* function does not take ownership of obj.
*/
static GstFlowReturn
-gst_base_sink_preroll_object (GstBaseSink * basesink, GstMiniObject * obj)
+gst_base_sink_preroll_object (GstBaseSink * basesink, gboolean is_list,
+ GstMiniObject * obj)
{
GstFlowReturn ret;
GST_DEBUG_OBJECT (basesink, "prerolling object %p", obj);
/* if it's a buffer, we need to call the preroll method */
- if (G_LIKELY (GST_IS_BUFFER (obj)) && basesink->priv->call_preroll) {
+ if (G_LIKELY (is_list || GST_IS_BUFFER (obj)) && basesink->priv->call_preroll) {
GstBaseSinkClass *bclass;
GstBuffer *buf;
GstClockTime timestamp;
@@ -2817,10 +2849,28 @@ gst_base_sink_preroll_object (GstBaseSink * basesink, GstMiniObject * obj)
buf = GST_BUFFER_CAST (obj);
timestamp = GST_BUFFER_TIMESTAMP (buf);
+ if (is_list) {
+ GstBufferListIterator *it;
+ it = gst_buffer_list_iterate (GST_BUFFER_LIST_CAST (obj));
+ g_assert (gst_buffer_list_iterator_next_group (it));
+ buf = gst_buffer_list_iterator_next (it);
+ gst_buffer_list_iterator_free (it);
+ g_assert (NULL != buf);
+ } else {
+ buf = GST_BUFFER_CAST (obj);
+ }
+
GST_DEBUG_OBJECT (basesink, "preroll buffer %" GST_TIME_FORMAT,
GST_TIME_ARGS (timestamp));
- gst_base_sink_set_last_buffer (basesink, buf);
+ /*
+ * For buffer lists do not set last buffer. Creating buffer
+ * with meaningful data can be done only with memcpy which will
+ * significantly affect performance
+ */
+ if (!is_list) {
+ gst_base_sink_set_last_buffer (basesink, buf);
+ }
bclass = GST_BASE_SINK_GET_CLASS (basesink);
if (bclass->preroll)
@@ -2862,7 +2912,7 @@ stopping:
*/
static GstFlowReturn
gst_base_sink_queue_object_unlocked (GstBaseSink * basesink, GstPad * pad,
- GstMiniObject * obj, gboolean prerollable)
+ gboolean is_list, gpointer obj, gboolean prerollable)
{
GstFlowReturn ret = GST_FLOW_OK;
gint length;
@@ -2878,7 +2928,7 @@ gst_base_sink_queue_object_unlocked (GstBaseSink * basesink, GstPad * pad,
/* first prerollable item needs to finish the preroll */
if (length == 1) {
- ret = gst_base_sink_preroll_object (basesink, obj);
+ ret = gst_base_sink_preroll_object (basesink, is_list, obj);
if (G_UNLIKELY (ret != GST_FLOW_OK))
goto preroll_failed;
}
@@ -2891,7 +2941,6 @@ gst_base_sink_queue_object_unlocked (GstBaseSink * basesink, GstPad * pad,
goto more_preroll;
}
}
-
/* we can start rendering (or blocking) the queued object
* if any. */
q = basesink->preroll_queue;
@@ -2902,13 +2951,13 @@ gst_base_sink_queue_object_unlocked (GstBaseSink * basesink, GstPad * pad,
GST_DEBUG_OBJECT (basesink, "rendering queued object %p", o);
/* do something with the return value */
- ret = gst_base_sink_render_object (basesink, pad, o);
+ ret = gst_base_sink_render_object (basesink, pad, FALSE, o);
if (ret != GST_FLOW_OK)
goto dequeue_failed;
}
/* now render the object */
- ret = gst_base_sink_render_object (basesink, pad, obj);
+ ret = gst_base_sink_render_object (basesink, pad, is_list, obj);
basesink->preroll_queued = 0;
return ret;
@@ -2918,7 +2967,7 @@ preroll_failed:
{
GST_DEBUG_OBJECT (basesink, "preroll failed, reason %s",
gst_flow_get_name (ret));
- gst_mini_object_unref (obj);
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
return ret;
}
more_preroll:
@@ -2933,7 +2982,7 @@ dequeue_failed:
{
GST_DEBUG_OBJECT (basesink, "rendering queued objects failed, reason %s",
gst_flow_get_name (ret));
- gst_mini_object_unref (obj);
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
return ret;
}
}
@@ -2958,7 +3007,9 @@ gst_base_sink_queue_object (GstBaseSink * basesink, GstPad * pad,
if (G_UNLIKELY (basesink->priv->received_eos))
goto was_eos;
- ret = gst_base_sink_queue_object_unlocked (basesink, pad, obj, prerollable);
+ ret =
+ gst_base_sink_queue_object_unlocked (basesink, pad, FALSE, obj,
+ prerollable);
GST_PAD_PREROLL_UNLOCK (pad);
return ret;
@@ -3065,7 +3116,7 @@ gst_base_sink_event (GstPad * pad, GstEvent * event)
/* EOS is a prerollable object, we call the unlocked version because it
* does not check the received_eos flag. */
ret = gst_base_sink_queue_object_unlocked (basesink, pad,
- GST_MINI_OBJECT_CAST (event), TRUE);
+ FALSE, GST_MINI_OBJECT_CAST (event), TRUE);
if (G_UNLIKELY (ret != GST_FLOW_OK))
result = FALSE;
}
@@ -3095,7 +3146,7 @@ gst_base_sink_event (GstPad * pad, GstEvent * event)
ret =
gst_base_sink_queue_object_unlocked (basesink, pad,
- GST_MINI_OBJECT_CAST (event), FALSE);
+ FALSE, GST_MINI_OBJECT_CAST (event), FALSE);
if (G_UNLIKELY (ret != GST_FLOW_OK))
result = FALSE;
else {
@@ -3206,12 +3257,13 @@ gst_base_sink_needs_preroll (GstBaseSink * basesink)
*/
static GstFlowReturn
gst_base_sink_chain_unlocked (GstBaseSink * basesink, GstPad * pad,
- GstBuffer * buf)
+ gboolean is_list, gpointer obj)
{
GstBaseSinkClass *bclass;
GstFlowReturn result;
GstClockTime start = GST_CLOCK_TIME_NONE, end = GST_CLOCK_TIME_NONE;
GstSegment *clip_segment;
+ GstBuffer *time_buf;
if (G_UNLIKELY (basesink->flushing))
goto flushing;
@@ -3219,6 +3271,17 @@ gst_base_sink_chain_unlocked (GstBaseSink * basesink, GstPad * pad,
if (G_UNLIKELY (basesink->priv->received_eos))
goto was_eos;
+ if (is_list) {
+ GstBufferListIterator *it;
+ it = gst_buffer_list_iterate (GST_BUFFER_LIST_CAST (obj));
+ g_assert (gst_buffer_list_iterator_next_group (it));
+ time_buf = gst_buffer_list_iterator_next (it);
+ gst_buffer_list_iterator_free (it);
+ g_assert (NULL != time_buf);
+ } else {
+ time_buf = GST_BUFFER_CAST (obj);
+ }
+
/* for code clarity */
clip_segment = basesink->abidata.ABI.clip_segment;
@@ -3247,12 +3310,12 @@ gst_base_sink_chain_unlocked (GstBaseSink * basesink, GstPad * pad,
/* check if the buffer needs to be dropped, we first ask the subclass for the
* start and end */
if (bclass->get_times)
- bclass->get_times (basesink, buf, &start, &end);
+ bclass->get_times (basesink, time_buf, &start, &end);
if (start == -1) {
/* if the subclass does not want sync, we use our own values so that we at
* least clip the buffer to the segment */
- gst_base_sink_get_times (basesink, buf, &start, &end);
+ gst_base_sink_get_times (basesink, time_buf, &start, &end);
}
GST_DEBUG_OBJECT (basesink, "got times start: %" GST_TIME_FORMAT
@@ -3269,28 +3332,27 @@ gst_base_sink_chain_unlocked (GstBaseSink * basesink, GstPad * pad,
/* now we can process the buffer in the queue, this function takes ownership
* of the buffer */
result = gst_base_sink_queue_object_unlocked (basesink, pad,
- GST_MINI_OBJECT_CAST (buf), TRUE);
-
+ is_list, obj, TRUE);
return result;
/* ERRORS */
flushing:
{
GST_DEBUG_OBJECT (basesink, "sink is flushing");
- gst_buffer_unref (buf);
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
return GST_FLOW_WRONG_STATE;
}
was_eos:
{
GST_DEBUG_OBJECT (basesink,
"we are EOS, dropping object, return UNEXPECTED");
- gst_buffer_unref (buf);
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
return GST_FLOW_UNEXPECTED;
}
out_of_segment:
{
GST_DEBUG_OBJECT (basesink, "dropping buffer, out of clipping segment");
- gst_buffer_unref (buf);
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
return GST_FLOW_OK;
}
}
@@ -3298,18 +3360,16 @@ out_of_segment:
/* with STREAM_LOCK
*/
static GstFlowReturn
-gst_base_sink_chain (GstPad * pad, GstBuffer * buf)
+gst_base_sink_chain_main (GstBaseSink * basesink, GstPad * pad,
+ gboolean is_list, gpointer obj)
{
- GstBaseSink *basesink;
GstFlowReturn result;
- basesink = GST_BASE_SINK (GST_OBJECT_PARENT (pad));
-
if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PUSH))
goto wrong_mode;
GST_PAD_PREROLL_LOCK (pad);
- result = gst_base_sink_chain_unlocked (basesink, pad, buf);
+ result = gst_base_sink_chain_unlocked (basesink, pad, is_list, obj);
GST_PAD_PREROLL_UNLOCK (pad);
done:
@@ -3323,7 +3383,7 @@ wrong_mode:
"Push on pad %s:%s, but it was not activated in push mode",
GST_DEBUG_PAD_NAME (pad));
GST_OBJECT_UNLOCK (pad);
- gst_buffer_unref (buf);
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
/* we don't post an error message this will signal to the peer
* pushing that EOS is reached. */
result = GST_FLOW_UNEXPECTED;
@@ -3331,6 +3391,61 @@ wrong_mode:
}
}
+static GstFlowReturn
+gst_base_sink_chain (GstPad * pad, GstBuffer * buf)
+{
+ GstBaseSink *basesink;
+
+ basesink = GST_BASE_SINK (GST_OBJECT_PARENT (pad));
+
+ return gst_base_sink_chain_main (basesink, pad, FALSE, buf);
+}
+
+static GstFlowReturn
+gst_base_sink_chain_list (GstPad * pad, GstBufferList * list)
+{
+ GstBaseSink *basesink;
+ GstBaseSinkClass *bclass;
+ GstFlowReturn result;
+
+ basesink = GST_BASE_SINK (GST_OBJECT_PARENT (pad));
+ bclass = GST_BASE_SINK_GET_CLASS (basesink);
+
+ if (G_LIKELY (bclass->render_list)) {
+ result = gst_base_sink_chain_main (basesink, pad, TRUE, list);
+ } else {
+ GstBufferListIterator *it;
+ GstBuffer *group;
+
+ GST_INFO_OBJECT (pad, "chaining each group in list as a merged buffer");
+
+ it = gst_buffer_list_iterate (list);
+
+ result = GST_FLOW_OK;
+ 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_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining empty group");
+ } else {
+ GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining group");
+ }
+ result = gst_base_sink_chain_main (basesink, pad, FALSE, group);
+ } while (result == GST_FLOW_OK
+ && gst_buffer_list_iterator_next_group (it));
+ } else {
+ GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining empty group");
+ result =
+ gst_base_sink_chain_main (basesink, pad, FALSE, gst_buffer_new ());
+ }
+ gst_buffer_list_iterator_free (it);
+ gst_buffer_list_unref (list);
+ }
+ return result;
+}
+
+
static gboolean
gst_base_sink_default_do_seek (GstBaseSink * sink, GstSegment * segment)
{
@@ -3665,7 +3780,7 @@ gst_base_sink_loop (GstPad * pad)
gst_segment_set_last_stop (&basesink->segment, GST_FORMAT_BYTES, offset);
GST_PAD_PREROLL_LOCK (pad);
- result = gst_base_sink_chain_unlocked (basesink, pad, buf);
+ result = gst_base_sink_chain_unlocked (basesink, pad, FALSE, buf);
GST_PAD_PREROLL_UNLOCK (pad);
if (G_UNLIKELY (result != GST_FLOW_OK))
goto paused;
diff --git a/libs/gst/base/gstbasesink.h b/libs/gst/base/gstbasesink.h
index d9b26fbc9a..1b591cd627 100644
--- a/libs/gst/base/gstbasesink.h
+++ b/libs/gst/base/gstbasesink.h
@@ -121,6 +121,8 @@ struct _GstBaseSink {
* @preroll: Called to present the preroll buffer if desired
* @render: Called when a buffer should be presented or output, at the
* correct moment if the #GstBaseSink has been set to sync to the clock.
+ * @render_list: Same as @render but used whith buffer lists instead of
+ * buffers
* @async_play: Subclasses should override this when they need to perform
* special processing when changing to the PLAYING state asynchronously.
* Called with the OBJECT_LOCK held.
@@ -180,10 +182,13 @@ struct _GstBaseSinkClass {
/* Clear a previously indicated unlock request not that unlocking is
* complete. Sub-classes should clear any command queue or indicator they
* set during unlock */
- gboolean (*unlock_stop) (GstBaseSink *sink);
+ gboolean (*unlock_stop) (GstBaseSink *sink);
+
+ /* Render a BufferList */
+ GstFlowReturn (*render_list) (GstBaseSink *sink, GstBufferList *buffer_list);
/*< private >*/
- gpointer _gst_reserved[GST_PADDING_LARGE-4];
+ gpointer _gst_reserved[GST_PADDING_LARGE-5];
};
GType gst_base_sink_get_type(void);