From 602bd2996073691420d67b361adc68fff0cd479e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 16 May 2012 12:08:44 +0200 Subject: [PATCH] basesink: add prepare method Add a prepare method that is called before sync happens. The purpose of this method is to prepare the rendering of the giving buffer so that the following render() call after sync is a quick as possible. --- libs/gst/base/gstbasesink.c | 55 +++++++++++++++++++++++++++++-------- libs/gst/base/gstbasesink.h | 12 ++++++-- 2 files changed, 54 insertions(+), 13 deletions(-) diff --git a/libs/gst/base/gstbasesink.c b/libs/gst/base/gstbasesink.c index e404ed42a1..4fb6ba167a 100644 --- a/libs/gst/base/gstbasesink.c +++ b/libs/gst/base/gstbasesink.c @@ -2003,8 +2003,8 @@ gst_base_sink_wait_clock (GstBaseSink * sink, GstClockTime time, /* FIXME: Casting to GstClockEntry only works because the types * are the same */ if (G_LIKELY (sink->priv->cached_clock_id != NULL - && GST_CLOCK_ENTRY_CLOCK ((GstClockEntry *) sink->priv-> - cached_clock_id) == clock)) { + && GST_CLOCK_ENTRY_CLOCK ((GstClockEntry *) sink-> + priv->cached_clock_id) == clock)) { if (!gst_clock_single_shot_id_reinit (clock, sink->priv->cached_clock_id, time)) { gst_clock_id_unref (sink->priv->cached_clock_id); @@ -2148,6 +2148,11 @@ gst_base_sink_do_preroll (GstBaseSink * sink, GstMiniObject * obj) GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); bclass = GST_BASE_SINK_GET_CLASS (sink); + + if (bclass->prepare) + if ((ret = bclass->prepare (sink, buf)) != GST_FLOW_OK) + goto prepare_canceled; + if (bclass->preroll) if ((ret = bclass->preroll (sink, buf)) != GST_FLOW_OK) goto preroll_canceled; @@ -2174,6 +2179,12 @@ gst_base_sink_do_preroll (GstBaseSink * sink, GstMiniObject * obj) return GST_FLOW_OK; /* ERRORS */ +prepare_canceled: + { + GST_DEBUG_OBJECT (sink, "prepare failed, abort state"); + gst_element_abort_state (GST_ELEMENT_CAST (sink)); + return ret; + } preroll_canceled: { GST_DEBUG_OBJECT (sink, "preroll failed, abort state"); @@ -3068,7 +3079,7 @@ gst_base_sink_needs_preroll (GstBaseSink * basesink) */ static GstFlowReturn gst_base_sink_chain_unlocked (GstBaseSink * basesink, GstPad * pad, - gpointer obj) + gpointer obj, gboolean is_list) { GstBaseSinkClass *bclass; GstBaseSinkPrivate *priv = basesink->priv; @@ -3085,7 +3096,7 @@ gst_base_sink_chain_unlocked (GstBaseSink * basesink, GstPad * pad, if (G_UNLIKELY (priv->received_eos)) goto was_eos; - if (GST_IS_BUFFER_LIST (obj)) { + if (is_list) { sync_buf = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0); g_assert (NULL != sync_buf); } else { @@ -3138,6 +3149,20 @@ gst_base_sink_chain_unlocked (GstBaseSink * basesink, GstPad * pad, goto out_of_segment; } + if (!is_list) { + if (bclass->prepare) { + ret = bclass->prepare (basesink, GST_BUFFER_CAST (obj)); + if (G_UNLIKELY (ret != GST_FLOW_OK)) + goto prepare_failed; + } + } else { + if (bclass->prepare_list) { + ret = bclass->prepare_list (basesink, GST_BUFFER_LIST_CAST (obj)); + if (G_UNLIKELY (ret != GST_FLOW_OK)) + goto prepare_failed; + } + } + again: late = FALSE; step_end = FALSE; @@ -3162,7 +3187,7 @@ again: if (do_qos) gst_base_sink_do_render_stats (basesink, TRUE); - if (!GST_IS_BUFFER_LIST (obj)) { + if (!is_list) { /* For buffer lists do not set last buffer for now. */ gst_base_sink_set_last_buffer (basesink, GST_BUFFER_CAST (obj)); @@ -3219,6 +3244,13 @@ out_of_segment: gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj)); return GST_FLOW_OK; } +prepare_failed: + { + GST_DEBUG_OBJECT (basesink, "prepare buffer failed %s", + gst_flow_get_name (ret)); + gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj)); + return ret; + } sync_failed: { GST_DEBUG_OBJECT (basesink, "do_sync returned %s", gst_flow_get_name (ret)); @@ -3262,7 +3294,8 @@ dropped: /* with STREAM_LOCK */ static GstFlowReturn -gst_base_sink_chain_main (GstBaseSink * basesink, GstPad * pad, gpointer obj) +gst_base_sink_chain_main (GstBaseSink * basesink, GstPad * pad, gpointer obj, + gboolean is_list) { GstFlowReturn result; @@ -3270,7 +3303,7 @@ gst_base_sink_chain_main (GstBaseSink * basesink, GstPad * pad, gpointer obj) goto wrong_mode; GST_BASE_SINK_PREROLL_LOCK (basesink); - result = gst_base_sink_chain_unlocked (basesink, pad, obj); + result = gst_base_sink_chain_unlocked (basesink, pad, obj, is_list); GST_BASE_SINK_PREROLL_UNLOCK (basesink); done: @@ -3299,7 +3332,7 @@ gst_base_sink_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) basesink = GST_BASE_SINK (parent); - return gst_base_sink_chain_main (basesink, pad, buf); + return gst_base_sink_chain_main (basesink, pad, buf, FALSE); } static GstFlowReturn @@ -3314,7 +3347,7 @@ gst_base_sink_chain_list (GstPad * pad, GstObject * parent, bclass = GST_BASE_SINK_GET_CLASS (basesink); if (G_LIKELY (bclass->render_list)) { - result = gst_base_sink_chain_main (basesink, pad, list); + result = gst_base_sink_chain_main (basesink, pad, list, TRUE); } else { guint i, len; GstBuffer *buffer; @@ -3327,7 +3360,7 @@ gst_base_sink_chain_list (GstPad * pad, GstObject * parent, for (i = 0; i < len; i++) { buffer = gst_buffer_list_get (list, i); result = gst_base_sink_chain_main (basesink, pad, - gst_buffer_ref (buffer)); + gst_buffer_ref (buffer), FALSE); if (result != GST_FLOW_OK) break; } @@ -3672,7 +3705,7 @@ gst_base_sink_loop (GstPad * pad) basesink->segment.position = offset; GST_BASE_SINK_PREROLL_LOCK (basesink); - result = gst_base_sink_chain_unlocked (basesink, pad, buf); + result = gst_base_sink_chain_unlocked (basesink, pad, buf, FALSE); GST_BASE_SINK_PREROLL_UNLOCK (basesink); if (G_UNLIKELY (result != GST_FLOW_OK)) goto paused; diff --git a/libs/gst/base/gstbasesink.h b/libs/gst/base/gstbasesink.h index f4ab7e6076..bf7a41fc2e 100644 --- a/libs/gst/base/gstbasesink.h +++ b/libs/gst/base/gstbasesink.h @@ -125,15 +125,19 @@ struct _GstBaseSink { * unblock any blocked function ASAP * @unlock_stop: Clear the previous unlock request. Subclasses should clear * any state they set during unlock(), such as clearing command queues. + * @query: perform a #GstQuery on the element. Since: 0.10.36 * @event: Override this to handle events arriving on the sink pad * @wait_eos: Override this to implement custom logic to wait for the EOS time. * subclasses should always first chain up to the default implementation. - * @preroll: Called to present the preroll buffer if desired + * @prepare: Called to prepare the buffer for @render and @preroll. This + * function is called before synchronisation is performed. + * @prepare_list: Called to prepare the buffer list for @render_list. This + * function is called before synchronisation is performed. + * @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. Since: 0.10.24 - * @query: perform a #GstQuery on the element. Since: 0.10.36 * * Subclasses can override any of the available virtual methods or not, as * needed. At the minimum, the @render method should be overridden to @@ -179,6 +183,10 @@ struct _GstBaseSinkClass { /* wait for eos, subclasses should chain up to parent first */ GstFlowReturn (*wait_eos) (GstBaseSink *sink, GstEvent *event); + /* notify subclass of buffer or list before doing sync */ + GstFlowReturn (*prepare) (GstBaseSink *sink, GstBuffer *buffer); + GstFlowReturn (*prepare_list) (GstBaseSink *sink, GstBufferList *buffer_list); + /* notify subclass of preroll buffer or real buffer */ GstFlowReturn (*preroll) (GstBaseSink *sink, GstBuffer *buffer); GstFlowReturn (*render) (GstBaseSink *sink, GstBuffer *buffer);