diff --git a/docs/gst/gstreamer-sections.txt b/docs/gst/gstreamer-sections.txt index 3273fc622b..ce6249b9b8 100644 --- a/docs/gst/gstreamer-sections.txt +++ b/docs/gst/gstreamer-sections.txt @@ -2144,6 +2144,9 @@ gst_pipeline_get_auto_flush_bus gst_pipeline_set_delay gst_pipeline_get_delay +gst_pipeline_set_latency +gst_pipeline_get_latency + GstPipelineClass GST_PIPELINE diff --git a/gst/gstpipeline.c b/gst/gstpipeline.c index 92d1405132..a258c345f9 100644 --- a/gst/gstpipeline.c +++ b/gst/gstpipeline.c @@ -94,12 +94,14 @@ enum #define DEFAULT_DELAY 0 #define DEFAULT_AUTO_FLUSH_BUS TRUE +#define DEFAULT_LATENCY GST_CLOCK_TIME_NONE enum { PROP_0, PROP_DELAY, - PROP_AUTO_FLUSH_BUS + PROP_AUTO_FLUSH_BUS, + PROP_LATENCY }; #define GST_PIPELINE_GET_PRIVATE(obj) \ @@ -114,6 +116,8 @@ struct _GstPipelinePrivate * PLAYING*/ GstClockTime last_start_time; gboolean update_clock; + + GstClockTime latency; }; @@ -128,6 +132,7 @@ static GstStateChangeReturn gst_pipeline_change_state (GstElement * element, GstStateChange transition); static void gst_pipeline_handle_message (GstBin * bin, GstMessage * message); +static gboolean gst_pipeline_do_latency (GstBin * bin); /* static guint gst_pipeline_signals[LAST_SIGNAL] = { 0 }; */ @@ -178,6 +183,18 @@ gst_pipeline_class_init (GstPipelineClass * klass) "from READY into NULL state", DEFAULT_AUTO_FLUSH_BUS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstPipeline:latency: + * + * Latency to configure on the pipeline. See gst_pipeline_set_latency(). + * + * Since: 1.6 + **/ + g_object_class_install_property (gobject_class, PROP_LATENCY, + g_param_spec_uint64 ("latency", "Latency", + "Latency to configure on the pipeline", 0, G_MAXUINT64, + DEFAULT_LATENCY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gobject_class->dispose = gst_pipeline_dispose; gst_element_class_set_static_metadata (gstelement_class, "Pipeline object", @@ -191,6 +208,7 @@ gst_pipeline_class_init (GstPipelineClass * klass) GST_DEBUG_FUNCPTR (gst_pipeline_provide_clock_func); gstbin_class->handle_message = GST_DEBUG_FUNCPTR (gst_pipeline_handle_message); + gstbin_class->do_latency = GST_DEBUG_FUNCPTR (gst_pipeline_do_latency); } static void @@ -203,6 +221,7 @@ gst_pipeline_init (GstPipeline * pipeline) /* set default property values */ pipeline->priv->auto_flush_bus = DEFAULT_AUTO_FLUSH_BUS; pipeline->delay = DEFAULT_DELAY; + pipeline->priv->latency = DEFAULT_LATENCY; /* create and set a default bus */ bus = gst_bus_new (); @@ -245,6 +264,9 @@ gst_pipeline_set_property (GObject * object, guint prop_id, case PROP_AUTO_FLUSH_BUS: gst_pipeline_set_auto_flush_bus (pipeline, g_value_get_boolean (value)); break; + case PROP_LATENCY: + gst_pipeline_set_latency (pipeline, g_value_get_uint64 (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -264,6 +286,9 @@ gst_pipeline_get_property (GObject * object, guint prop_id, case PROP_AUTO_FLUSH_BUS: g_value_set_boolean (value, gst_pipeline_get_auto_flush_bus (pipeline)); break; + case PROP_LATENCY: + g_value_set_uint64 (value, gst_pipeline_get_latency (pipeline)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -574,6 +599,75 @@ gst_pipeline_handle_message (GstBin * bin, GstMessage * message) GST_BIN_CLASS (parent_class)->handle_message (bin, message); } +static gboolean +gst_pipeline_do_latency (GstBin * bin) +{ + GstPipeline *pipeline = GST_PIPELINE (bin); + GstQuery *query; + GstClockTime latency; + GstClockTime min_latency, max_latency; + gboolean res; + + GST_OBJECT_LOCK (pipeline); + latency = pipeline->priv->latency; + GST_OBJECT_UNLOCK (pipeline); + + if (latency == GST_CLOCK_TIME_NONE) + return GST_BIN_CLASS (parent_class)->do_latency (bin); + + GST_DEBUG_OBJECT (pipeline, "querying latency"); + + query = gst_query_new_latency (); + if ((res = gst_element_query (GST_ELEMENT_CAST (pipeline), query))) { + gboolean live; + + gst_query_parse_latency (query, &live, &min_latency, &max_latency); + + GST_DEBUG_OBJECT (pipeline, + "got min latency %" GST_TIME_FORMAT ", max latency %" + GST_TIME_FORMAT ", live %d", GST_TIME_ARGS (min_latency), + GST_TIME_ARGS (max_latency), live); + + if (max_latency < min_latency) { + /* this is an impossible situation, some parts of the pipeline might not + * work correctly. We post a warning for now. */ + GST_ELEMENT_WARNING (pipeline, CORE, CLOCK, (NULL), + ("Impossible to configure latency: max %" GST_TIME_FORMAT " < min %" + GST_TIME_FORMAT ". Add queues or other buffering elements.", + GST_TIME_ARGS (max_latency), GST_TIME_ARGS (min_latency))); + } + + if (latency < min_latency) { + /* This is a problematic situation as we will most likely drop lots of + * data if we configure a too low latency */ + GST_ELEMENT_WARNING (pipeline, CORE, CLOCK, (NULL), + ("Configured latency is lower than detected minimum latency: configured %" + GST_TIME_FORMAT " < min %" GST_TIME_FORMAT, + GST_TIME_ARGS (latency), GST_TIME_ARGS (min_latency))); + } + } else { + /* this is not a real problem, we just don't configure any latency. */ + GST_WARNING_OBJECT (pipeline, "failed to query latency"); + } + gst_query_unref (query); + + + /* configure latency on elements */ + res = + gst_element_send_event (GST_ELEMENT_CAST (pipeline), + gst_event_new_latency (latency)); + if (res) { + GST_INFO_OBJECT (pipeline, "configured latency of %" GST_TIME_FORMAT, + GST_TIME_ARGS (latency)); + } else { + GST_WARNING_OBJECT (pipeline, + "did not really configure latency of %" GST_TIME_FORMAT, + GST_TIME_ARGS (latency)); + } + + return res; +} + /** * gst_pipeline_get_bus: * @pipeline: a #GstPipeline @@ -862,3 +956,60 @@ gst_pipeline_get_auto_flush_bus (GstPipeline * pipeline) return res; } + +/** + * gst_pipeline_set_latency: + * @pipeline: a #GstPipeline + * @latency: latency to configure + * + * Sets the latency that should be configured on the pipeline. Setting + * GST_CLOCK_TIME_NONE will restore the default behaviour of using the minimum + * latency from the LATENCY query. Setting this is usually not required and + * the pipeline will figure out an appropriate latency automatically. + * + * Setting a too low latency, especially lower than the minimum latency from + * the LATENCY query, will most likely cause the pipeline to fail. + * + * Since: 1.6 + */ +void +gst_pipeline_set_latency (GstPipeline * pipeline, GstClockTime latency) +{ + gboolean changed; + + g_return_if_fail (GST_IS_PIPELINE (pipeline)); + + GST_OBJECT_LOCK (pipeline); + changed = (pipeline->priv->latency != latency); + pipeline->priv->latency = latency; + GST_OBJECT_UNLOCK (pipeline); + + if (changed) + gst_bin_recalculate_latency (GST_BIN_CAST (pipeline)); +} + +/** + * gst_pipeline_get_latency: + * @pipeline: a #GstPipeline + * + * Gets the latency that should be configured on the pipeline. See + * gst_pipeline_set_latency(). + * + * Returns: Latency to configure on the pipeline or GST_CLOCK_TIME_NONE + * + * Since: 1.6 + */ + +GstClockTime +gst_pipeline_get_latency (GstPipeline * pipeline) +{ + GstClockTime latency; + + g_return_val_if_fail (GST_IS_PIPELINE (pipeline), GST_CLOCK_TIME_NONE); + + GST_OBJECT_LOCK (pipeline); + latency = pipeline->priv->latency; + GST_OBJECT_UNLOCK (pipeline); + + return latency; +} diff --git a/gst/gstpipeline.h b/gst/gstpipeline.h index 192ec2dfd6..73fdeb4d05 100644 --- a/gst/gstpipeline.h +++ b/gst/gstpipeline.h @@ -102,6 +102,9 @@ void gst_pipeline_auto_clock (GstPipeline *pipeline); void gst_pipeline_set_delay (GstPipeline *pipeline, GstClockTime delay); GstClockTime gst_pipeline_get_delay (GstPipeline *pipeline); +void gst_pipeline_set_latency (GstPipeline *pipeline, GstClockTime latency); +GstClockTime gst_pipeline_get_latency (GstPipeline *pipeline); + void gst_pipeline_set_auto_flush_bus (GstPipeline *pipeline, gboolean auto_flush); gboolean gst_pipeline_get_auto_flush_bus (GstPipeline *pipeline); diff --git a/win32/common/libgstreamer.def b/win32/common/libgstreamer.def index 76dcb079e7..4db73f843f 100644 --- a/win32/common/libgstreamer.def +++ b/win32/common/libgstreamer.def @@ -922,12 +922,14 @@ EXPORTS gst_pipeline_get_bus gst_pipeline_get_clock gst_pipeline_get_delay + gst_pipeline_get_latency gst_pipeline_get_pipeline_clock gst_pipeline_get_type gst_pipeline_new gst_pipeline_set_auto_flush_bus gst_pipeline_set_clock gst_pipeline_set_delay + gst_pipeline_set_latency gst_pipeline_use_clock gst_plugin_add_dependency gst_plugin_add_dependency_simple