diff --git a/ChangeLog b/ChangeLog index b16dfe3f6f..6ef9122ee3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,31 @@ +2006-03-13 Wim Taymans + + * docs/gst/gstreamer-sections.txt: + * gst/gstbin.c: (bin_bus_handler), (gst_bin_handle_message_func): + * gst/gstbin.h: + * gst/gstbus.c: (gst_bus_class_init): + * gst/gstbus.h: + * gst/gstclock.c: + * gst/gstelement.c: (gst_element_set_locked_state): + * gst/gstsegment.c: + Documentation updates. + + * gst/gstpipeline.c: (gst_pipeline_get_type), + (gst_pipeline_class_init), (gst_pipeline_init), + (gst_pipeline_dispose), (gst_pipeline_set_property), + (gst_pipeline_get_property), (do_pipeline_seek), + (gst_pipeline_send_event), (gst_pipeline_change_state), + (gst_pipeline_provide_clock_func), (gst_pipeline_set_delay), + (gst_pipeline_get_delay): + * gst/gstpipeline.h: + Added methods for setting the delay. + API: gst_pipeline_set_delay + API: gst_pipeline_get_delay + Add pipeline debug category + Various cleanups. + Updated docs. + Don't reset stream time when seek failed. + 2006-03-13 Wim Taymans * docs/design/draft-klass.txt: diff --git a/docs/gst/gstreamer-sections.txt b/docs/gst/gstreamer-sections.txt index 24b6b9eec0..c91c4a9305 100644 --- a/docs/gst/gstreamer-sections.txt +++ b/docs/gst/gstreamer-sections.txt @@ -1404,16 +1404,23 @@ GstPipelineFlags gst_pipeline_new -gst_pipeline_auto_clock gst_pipeline_get_bus -gst_pipeline_get_clock -gst_pipeline_get_last_stream_time -gst_pipeline_set_clock -gst_pipeline_set_new_stream_time -gst_pipeline_use_clock -gst_pipeline_get_auto_flush_bus +gst_pipeline_set_clock +gst_pipeline_get_clock + +gst_pipeline_use_clock +gst_pipeline_auto_clock + +gst_pipeline_set_new_stream_time +gst_pipeline_get_last_stream_time + gst_pipeline_set_auto_flush_bus +gst_pipeline_get_auto_flush_bus + +gst_pipeline_set_delay +gst_pipeline_get_delay + GstPipelineClass GST_PIPELINE diff --git a/gst/gstbin.c b/gst/gstbin.c index 995ff430a2..bc7af2e7a3 100644 --- a/gst/gstbin.c +++ b/gst/gstbin.c @@ -79,21 +79,58 @@ * a SEGMENT_START have posted a SEGMENT_DONE. * * + * GST_MESSAGE_DURATION + * Is posted by an element that detected a change + * in the stream duration. The default bin behaviour is to clear any + * cached duration values so that the next duration query will perform + * a full duration recalculation. The duration change is posted to the + * application so that it can refetch the new duration with a duration + * query. + * + * + * + * GST_MESSAGE_CLOCK_LOST + * This message is posted by an element when it + * can no longer provide a clock. The default bin behaviour is to + * check if the lost clock was the one provided by the bin. If so and + * the bin is currently in the PLAYING state, the message is forwarded to + * the bin parent. + * This message is also generated when a clock provider is removed from + * the bin. If this message is received by the application, it should + * PAUSE the pipeline and set it back to PLAYING to force a new clock + * distribution. + * + * + * + * GST_MESSAGE_CLOCK_PROVIDE + * This message is generated when an element + * can provide a clock. This mostly happens when a new clock + * provider is added to the bin. The default behaviour of the bin is to + * mark the currently selected clock as dirty, which will perform a clock + * recalculation the next time the bin is asked to provide a clock. + * This message is never sent tot the application but is forwarded to + * the parent of the bin. + * + * + * * OTHERS * posted upwards. * * * + * * A #GstBin implements the following default behaviour for answering to a * #GstQuery: * * * GST_QUERY_DURATION - * If the query has been asked before with the same format, + * If the query has been asked before with the same format + * and the bin is a toplevel bin (ie. has no parent), * use the cached previous value. If no previous value was cached, the * query is sent to all sink elements in the bin and the MAXIMUM of all - * values is returned and cached. If no sinks are available in the bin, the - * query fails. + * values is returned. If the bin is a toplevel bin the value is cached. + * If no sinks are available in the bin, the query fails. + * * * * OTHERS @@ -110,7 +147,7 @@ * * * - * Last reviewed on 2005-12-16 (0.10.0) + * Last reviewed on 2006-03-12 (0.10.5) */ #include "gst_private.h" @@ -1918,6 +1955,21 @@ gst_bin_recalc_func (GstBin * bin, gpointer data) gst_object_unref (bin); } +static GstBusSyncReply +bin_bus_handler (GstBus * bus, GstMessage * message, GstBin * bin) +{ + + GstBinClass *bclass; + + bclass = GST_BIN_GET_CLASS (bin); + if (bclass->handle_message) + bclass->handle_message (bin, message); + else + gst_message_unref (message); + + return GST_BUS_DROP; +} + /* handle child messages: * * GST_MESSAGE_EOS: This message is only posted by sinks @@ -1941,23 +1993,26 @@ gst_bin_recalc_func (GstBin * bin, gpointer data) * changes its duration marks our cached values invalid. * This message is also posted upwards. * + * GST_MESSAGE_CLOCK_LOST: This message is posted by an element when it + * can no longer provide a clock. The default bin behaviour is to + * check if the lost clock was the one provided by the bin. If so and + * we are currently in the PLAYING state, we forward the message to + * our parent. + * This message is also generated when we remove a clock provider from + * a bin. If this message is received by the application, it should + * PAUSE the pipeline and set it back to PLAYING to force a new clock + * distribution. + * + * GST_MESSAGE_CLOCK_PROVIDE: This message is generated when an element + * can provide a clock. This mostly happens when we add a new clock + * provider to the bin. The default behaviour of the bin is to mark the + * currently selected clock as dirty, which will perform a clock + * recalculation the next time we are asked to provide a clock. + * This message is never sent tot the application but is forwarded to + * the parent. + * * OTHER: post upwards. */ -static GstBusSyncReply -bin_bus_handler (GstBus * bus, GstMessage * message, GstBin * bin) -{ - - GstBinClass *bclass; - - bclass = GST_BIN_GET_CLASS (bin); - if (bclass->handle_message) - bclass->handle_message (bin, message); - else - gst_message_unref (message); - - return GST_BUS_DROP; -} - static void gst_bin_handle_message_func (GstBin * bin, GstMessage * message) { diff --git a/gst/gstbin.h b/gst/gstbin.h index 215ec9f5c1..939a6bae6c 100644 --- a/gst/gstbin.h +++ b/gst/gstbin.h @@ -83,7 +83,7 @@ typedef struct _GstBinClass GstBinClass; * @children: the list of children in this bin * @children_cookie: updated whenever @children changes * @child_bus: internal bus for handling child messages - * @messages: queued messages + * @messages: queued and cached messages * @polling: the bin is currently calculating its state * @state_dirty: the bin needs to recalculate its state * @clock_dirty: the bin needs to select a new clock diff --git a/gst/gstbus.c b/gst/gstbus.c index b9ee671e7e..0e7f7a08e2 100644 --- a/gst/gstbus.c +++ b/gst/gstbus.c @@ -48,7 +48,9 @@ * bus to handle them. * Alternatively the application can register an asynchronous bus function * using gst_bus_add_watch_full() or gst_bus_add_watch(). This function will - * receive messages a short while after they have been posted. + * install a #GSource in the default glib main loop and will deliver messages + * a short while after they have been posted. Note that the main loop should + * be running for the asynchronous callbacks. * * It is also possible to get messages from the bus without any thread * marshalling with the gst_bus_set_sync_handler() method. This makes it @@ -61,7 +63,7 @@ * Note that a #GstPipeline will set its bus into flushing state when changing * from READY to NULL state. * - * Last reviewed on 2005-10-28 (0.9.4) + * Last reviewed on 2006-03-12 (0.10.5) */ #include @@ -195,7 +197,8 @@ gst_bus_class_init (GstBusClass * klass) * @message: the message that has been posted asynchronously * * A message has been posted on the bus. This signal is emitted from a - * GSource added to the mainloop. + * GSource added to the mainloop. this signal will only be emited when + * there is a mainloop running. */ gst_bus_signals[ASYNC_MESSAGE] = g_signal_new ("message", G_TYPE_FROM_CLASS (klass), @@ -684,13 +687,13 @@ gst_bus_create_watch (GstBus * bus) * @user_data: user data passed to @func. * @notify: the function to call when the source is removed. * - * Adds a bus watch to the default main context with the given priority. - * If the func returns FALSE, the source will be removed. + * Adds a bus watch to the default main context with the given @priority. * - * When the func is called, the message belongs to the caller; if you want to - * keep a copy of it, call gst_message_ref() before leaving the func. + * When @func is called, the message belongs to the caller; if you want to + * keep a copy of it, call gst_message_ref() before leaving @func. * - * The watch can be removed using #g_source_remove(). + * The watch can be removed using g_source_remove() or by returning FALSE + * from @func. * * Returns: The event source id. * @@ -727,7 +730,8 @@ gst_bus_add_watch_full (GstBus * bus, gint priority, * * Adds a bus watch to the default main context with the default priority. * - * The watch can be removed using #g_source_remove(). + * The watch can be removed using g_source_remove() or by returning FALSE + * from @func. * * Returns: The event source id. * @@ -874,7 +878,7 @@ gst_bus_poll (GstBus * bus, GstMessageType events, GstClockTimeDiff timeout) * @message: the #GstMessage received * @data: user data * - * A helper GstBusFunc that can be used to convert all asynchronous messages + * A helper #GstBusFunc that can be used to convert all asynchronous messages * into signals. * * Returns: TRUE @@ -925,7 +929,7 @@ gst_bus_sync_signal_handler (GstBus * bus, GstMessage * message, gpointer data) * gst_bus_enable_sync_message_emission: * @bus: a #GstBus on which you want to receive the "sync-message" signal * - * Instructs GStreamer to emit the sync-message signal after running the bus's + * Instructs GStreamer to emit the "sync-message" signal after running the bus's * sync handler. This function is here so that code can ensure that they can * synchronously receive messages without having to affect what the bin's sync * handler is. @@ -936,9 +940,9 @@ gst_bus_sync_signal_handler (GstBus * bus, GstMessage * message, gpointer data) * * While this function looks similar to gst_bus_add_signal_watch(), it is not * exactly the same -- this function enables synchronous emission of - * signals when messages arrive; gst_bus_add_signal_watch adds an idle callback + * signals when messages arrive; gst_bus_add_signal_watch() adds an idle callback * to pop messages off the bus asynchronously. The sync-message signal - * comes from the thread of whatever object posted the message; the message + * comes from the thread of whatever object posted the message; the "message" * signal is marshalled to the main thread via the main loop. * * MT safe. @@ -960,14 +964,14 @@ gst_bus_enable_sync_message_emission (GstBus * bus) * @bus: a #GstBus on which you previously called * gst_bus_enable_sync_message_emission() * - * Instructs GStreamer to stop emitting the sync-message signal for this bus. + * Instructs GStreamer to stop emitting the "sync-message" signal for this bus. * See gst_bus_enable_sync_message_emission() for more information. * * In the event that multiple pieces of code have called * gst_bus_enable_sync_message_emission(), the sync-message emissions will only * be stopped after all calls to gst_bus_enable_sync_message_emission() were * "cancelled" by calling this function. In this way the semantics are exactly - * the same as gst_object_ref(); that which calls enable should also call + * the same as gst_object_ref() that which calls enable should also call * disable. * * MT safe. @@ -992,8 +996,8 @@ gst_bus_disable_sync_message_emission (GstBus * bus) * @priority: The priority of the watch. * * Adds a bus signal watch to the default main context with the given priority. - * After calling this statement, the bus will emit the message signal for each - * message posted on the bus. + * After calling this statement, the bus will emit the "message" signal for each + * message posted on the bus when the main loop is running. * * This function may be called multiple times. To clean up, the caller is * responsible for calling gst_bus_remove_signal_watch() as many times as this @@ -1031,7 +1035,7 @@ done: * * Adds a bus signal watch to the default main context with the default * priority. - * After calling this statement, the bus will emit the message signal for each + * After calling this statement, the bus will emit the "message" signal for each * message posted on the bus. * * This function may be called multiple times. To clean up, the caller is diff --git a/gst/gstbus.h b/gst/gstbus.h index d8e336964d..3aa599128b 100644 --- a/gst/gstbus.h +++ b/gst/gstbus.h @@ -98,6 +98,9 @@ typedef GstBusSyncReply (*GstBusSyncHandler) (GstBus * bus, GstMessage * messag * The message passed to the function will be unreffed after execution of this * function so it should not be freed in the function. * + * Note that this function is used as a GSourceFunc which means that returning + * FALSE will remove the GSource from the mainloop. + * * Returns: %FALSE if the event source should be removed. */ typedef gboolean (*GstBusFunc) (GstBus * bus, GstMessage * message, gpointer data); diff --git a/gst/gstclock.c b/gst/gstclock.c index 931b24b468..5fccbdb74c 100644 --- a/gst/gstclock.c +++ b/gst/gstclock.c @@ -24,7 +24,7 @@ /** * SECTION:gstclock * @short_description: Abstract class for global clocks - * @see_also: #GstSystemClock + * @see_also: #GstSystemClock, #GstPipeline * * GStreamer uses a global clock to synchronize the plugins in a pipeline. * Different clock implementations are possible by implementing this abstract @@ -35,10 +35,11 @@ * clock implementation but time is always expressed in nanoseconds. Since the * baseline of the clock is undefined, the clock time returned is not * meaningful in itself, what matters are the deltas between two clock times. + * The time returned by a clock is called the absolute time. * * The pipeline uses the clock to calculate the stream time. Usually all * renderers synchronize to the global clock using the buffer timestamps, the - * newsegment events and the element's base time. + * newsegment events and the element's base time, see #GstPipeline. * * A clock implementation can support periodic and single shot clock * notifications both synchronous and asynchronous. diff --git a/gst/gstelement.c b/gst/gstelement.c index 900030279b..355af89715 100644 --- a/gst/gstelement.c +++ b/gst/gstelement.c @@ -25,9 +25,9 @@ * @short_description: Abstract base class for all pipeline elements * @see_also: #GstElementFactory, #GstPad * - * GstElement is the base class needed to construct an element that can be - * used in a GStreamer pipeline. As such, it is not a functional entity, and - * cannot do anything when placed in a pipeline. + * GstElement is the abstract base class needed to construct an element that + * can be used in a GStreamer pipeline. Please refer to the plugin writers + * guide for more information on creating #GstElement subclasses. * * The name of a #GstElement can be get with gst_element_get_name() and set with * gst_element_set_name(). For speed, GST_ELEMENT_NAME() can be used in the @@ -73,7 +73,7 @@ * toplevel #GstPipeline so the clock functions are only to be used in very * specific situations. * - * Last reviewed on 2005-11-23 (0.9.5) + * Last reviewed on 2006-03-12 (0.10.5) */ #include "gst_private.h" diff --git a/gst/gstpipeline.c b/gst/gstpipeline.c index 96b74a30b7..5d792350b9 100644 --- a/gst/gstpipeline.c +++ b/gst/gstpipeline.c @@ -24,23 +24,59 @@ * SECTION:gstpipeline * @short_description: Top-level bin with clocking and bus management functionality. - * @see_also: #GstBin + * @see_also: #GstElement, #GstBin, #GstClock, #GstBus * - * In almost all cases, you'll want to use a GstPipeline when creating a filter - * graph. The GstPipeline will manage the selection and distribution of a - * global - * clock as well as provide a GstBus to the application. - * - * The pipeline will also use the selected clock to calculate the stream time - * of the pipeline. - * - * When sending a seek event to a GstPipeline, it will make sure that the - * pipeline is properly PAUSED and resumed as well as update the new stream - * time after the seek. + * A #GstPipeline is a special #GstBin used as the toplevel container for + * the filter graph. The #GstPipeline will manage the selection and + * distribution of a global #GstClock as well as provide a #GstBus to the + * application. It will also implement a default behavour for managing + * seek events (see gst_element_seek()). * * gst_pipeline_new() is used to create a pipeline. when you are done with * the pipeline, use gst_object_unref() to free its resources including all * added #GstElement objects (if not otherwise referenced). + * + * Elements are added and removed from the pipeline using the #GstBin + * methods like gst_bin_add() and gst_bin_remove() (see #GstBin). + * + * Before changing the state of the #GstPipeline (see #GstElement) a #GstBus + * can be retrieved with gst_pipeline_get_bus(). This bus can then be + * used to receive #GstMessage from the elements in the pipeline. + * + * By default, a #GstPipeline will automatically flush the pending #GstBus + * messages when going to the NULL state to ensure that no circular + * references exist when no messages are read from the #GstBus. This + * behaviour can be changed with gst_pipeline_set_auto_flush_bus(). + * + * When the #GstPipeline performs the PAUSED to PLAYING state change it will + * select a clock for the elements. The clock selection algorithm will by + * default select a clock provided by an element that is most upstream + * (closest to the source). For live pipelines (ones that return + * #GST_STATE_CHANGE_NO_PREROLL from the gst_element_set_state() call) this + * will select the clock provided by the live source. For normal pipelines + * this will select a clock provided by the sinks (most likely the audio + * sink). If no element provides a clock, a default #GstSystemClock is used. + * + * The clock selection can be controlled with the gst_pipeline_use_clock() + * method, which will enforce a given clock on the pipeline. With + * gst_pipeline_auto_clock() the default clock selection algorithm can be + * restored. + * + * A #GstPipeline maintains a stream time for the elements. The stream + * time is defined as the difference between the current clock time and + * the base time. When the pipeline goes to READY or a flushing seek is + * performed on it, the stream time is reset to 0. When the pipeline is + * set from PLAYING to PAUSED, the current clock time is sampled and used to + * configure the base time for the elements when the pipeline is set + * to PLAYING again. This default behaviour can be changed with the + * gst_pipeline_set_new_stream_time() method. + * + * When sending a flushing seek event to a GstPipeline (see + * gst_element_seek()), it will make sure that the pipeline is properly + * PAUSED and resumed as well as set the new stream time to 0 when the + * seek succeeded. + * + * Last reviewed on 2006-03-12 (0.10.5) */ #include "gst_private.h" @@ -51,6 +87,9 @@ #include "gstinfo.h" #include "gstsystemclock.h" +GST_DEBUG_CATEGORY_STATIC (pipeline_debug); +#define GST_CAT_DEFAULT pipeline_debug + static GstElementDetails gst_pipeline_details = GST_ELEMENT_DETAILS ("Pipeline object", "Generic/Bin", @@ -80,6 +119,7 @@ enum struct _GstPipelinePrivate { + /* with LOCK */ gboolean auto_flush_bus; }; @@ -110,7 +150,7 @@ gst_pipeline_get_type (void) { static GType pipeline_type = 0; - if (!pipeline_type) { + if (G_UNLIKELY (pipeline_type == 0)) { static const GTypeInfo pipeline_info = { sizeof (GstPipelineClass), gst_pipeline_base_init, @@ -126,6 +166,9 @@ gst_pipeline_get_type (void) pipeline_type = g_type_register_static (GST_TYPE_BIN, "GstPipeline", &pipeline_info, 0); + + GST_DEBUG_CATEGORY_INIT (pipeline_debug, "pipeline", GST_DEBUG_BOLD, + "debugging info for the 'pipeline' container element"); } return pipeline_type; } @@ -152,21 +195,28 @@ gst_pipeline_class_init (gpointer g_class, gpointer class_data) gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_pipeline_set_property); gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_pipeline_get_property); + /** + * GstPipeline:delay + * + * The expected delay needed for elements to spin up to the + * PLAYING state expressed in nanoseconds. + * see gst_pipeline_set_delay() for more information on this option. + **/ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DELAY, g_param_spec_uint64 ("delay", "Delay", "Expected delay needed for elements " "to spin up to PLAYING in nanoseconds", 0, G_MAXUINT64, DEFAULT_DELAY, G_PARAM_READWRITE)); - /** - * GstPipeline:auto-flush-bus: - * - * Whether or not to automatically flush all messages on the - * pipeline's bus when going from READY to NULL state. Please see - * gst_pipeline_set_auto_flush_bus() for more information on this option. - * - * Since: 0.10.4 - **/ + /** + * GstPipeline:auto-flush-bus: + * + * Whether or not to automatically flush all messages on the + * pipeline's bus when going from READY to NULL state. Please see + * gst_pipeline_set_auto_flush_bus() for more information on this option. + * + * Since: 0.10.4 + **/ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_AUTO_FLUSH_BUS, g_param_spec_boolean ("auto-flush-bus", "Auto Flush Bus", "Whether to automatically flush the pipeline's bus when going " @@ -189,14 +239,15 @@ gst_pipeline_init (GTypeInstance * instance, gpointer g_class) GstBus *bus; pipeline->priv = GST_PIPELINE_GET_PRIVATE (pipeline); - pipeline->priv->auto_flush_bus = DEFAULT_AUTO_FLUSH_BUS; + /* set default property values */ + pipeline->priv->auto_flush_bus = DEFAULT_AUTO_FLUSH_BUS; pipeline->delay = DEFAULT_DELAY; + /* create and set a default bus */ bus = gst_bus_new (); gst_element_set_bus (GST_ELEMENT_CAST (pipeline), bus); GST_DEBUG_OBJECT (pipeline, "set bus %" GST_PTR_FORMAT " on pipeline", bus); - gst_object_unref (bus); } @@ -207,6 +258,7 @@ gst_pipeline_dispose (GObject * object) GST_CAT_DEBUG_OBJECT (GST_CAT_REFCOUNTING, pipeline, "dispose"); + /* clear and unref any fixed clock */ gst_object_replace ((GstObject **) & pipeline->fixed_clock, NULL); G_OBJECT_CLASS (parent_class)->dispose (object); @@ -221,10 +273,10 @@ gst_pipeline_set_property (GObject * object, guint prop_id, GST_OBJECT_LOCK (pipeline); switch (prop_id) { case PROP_DELAY: - pipeline->delay = g_value_get_uint64 (value); + gst_pipeline_set_delay (pipeline, g_value_get_uint64 (value)); break; case PROP_AUTO_FLUSH_BUS: - pipeline->priv->auto_flush_bus = g_value_get_boolean (value); + gst_pipeline_set_auto_flush_bus (pipeline, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -242,10 +294,10 @@ gst_pipeline_get_property (GObject * object, guint prop_id, GST_OBJECT_LOCK (pipeline); switch (prop_id) { case PROP_DELAY: - g_value_set_uint64 (value, pipeline->delay); + g_value_set_uint64 (value, gst_pipeline_get_delay (pipeline)); break; case PROP_AUTO_FLUSH_BUS: - g_value_set_boolean (value, pipeline->priv->auto_flush_bus); + g_value_set_boolean (value, gst_pipeline_get_auto_flush_bus (pipeline)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -254,6 +306,16 @@ gst_pipeline_get_property (GObject * object, guint prop_id, GST_OBJECT_UNLOCK (pipeline); } +/* default pipeline seeking code: + * + * If the pipeline is PLAYING and a flushing seek is done, set + * the pipeline to PAUSED before doing the seek. + * + * A flushing seek also resets the stream time to 0 so that when + * we go back to PLAYING after the seek, the base_time is recalculated + * and redistributed to the elements. + * + */ static gboolean do_pipeline_seek (GstElement * element, GstEvent * event) { @@ -263,10 +325,12 @@ do_pipeline_seek (GstElement * element, GstEvent * event) gboolean was_playing = FALSE; gboolean res; + /* we are only interested in the FLUSH flag of the seek event. */ gst_event_parse_seek (event, &rate, NULL, &flags, NULL, NULL, NULL, NULL); flush = flags & GST_SEEK_FLAG_FLUSH; + /* if flushing seek, get the current state */ if (flush) { GstState state; @@ -276,34 +340,39 @@ do_pipeline_seek (GstElement * element, GstEvent * event) was_playing = state == GST_STATE_PLAYING; if (was_playing) { + /* and PAUSE when the pipeline was PLAYING, we don't need + * to wait for the state change to complete since we are going + * to flush out any preroll sample anyway */ gst_element_set_state (element, GST_STATE_PAUSED); } } + /* let parent class implement the seek behaviour */ res = GST_ELEMENT_CLASS (parent_class)->send_event (element, event); - if (flush && res) { + /* if flushing seek restore previous state */ + if (flush) { gboolean need_reset; GST_OBJECT_LOCK (element); need_reset = GST_PIPELINE (element)->stream_time != GST_CLOCK_TIME_NONE; GST_OBJECT_UNLOCK (element); - /* need to reset the stream time to 0 after a flushing seek, unless the user - explicitly disabled this behavior by setting stream time to NONE */ - if (need_reset) + /* need to reset the stream time to 0 after a successfull flushing seek, + * unless the user explicitly disabled this behavior by setting stream + * time to NONE */ + if (need_reset && res) gst_pipeline_set_new_stream_time (GST_PIPELINE (element), 0); if (was_playing) - /* and continue playing */ + /* and continue playing, this might return ASYNC in which case the + * application can wait for the PREROLL to complete after the seek. + */ gst_element_set_state (element, GST_STATE_PLAYING); } return res; } -/* sending a seek event on the pipeline pauses the pipeline if it - * was playing. - */ static gboolean gst_pipeline_send_event (GstElement * element, GstEvent * event) { @@ -312,9 +381,11 @@ gst_pipeline_send_event (GstElement * element, GstEvent * event) switch (event_type) { case GST_EVENT_SEEK: + /* do the default seek handling */ res = do_pipeline_seek (element, event); break; default: + /* else parent implements the defaults */ res = GST_ELEMENT_CLASS (parent_class)->send_event (element, event); break; } @@ -375,11 +446,14 @@ gst_pipeline_change_state (GstElement * element, GstStateChange transition) GST_OBJECT_UNLOCK (element); if (new_clock) { - /* now distribute the clock (which could be NULL I guess) */ + /* now distribute the clock (which could be NULL). If some + * element refuses the clock, this will return FALSE and + * we effectively fail the state change. */ if (!gst_element_set_clock (element, clock)) goto invalid_clock; - /* if we selected a new clock, let the app know about it */ + /* if we selected and distributed a new clock, let the app + * know about it */ gst_element_post_message (element, gst_message_new_new_clock (GST_OBJECT_CAST (element), clock)); } @@ -403,6 +477,7 @@ gst_pipeline_change_state (GstElement * element, GstStateChange transition) } break; case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + break; case GST_STATE_CHANGE_PAUSED_TO_READY: case GST_STATE_CHANGE_READY_TO_NULL: break; @@ -417,6 +492,8 @@ gst_pipeline_change_state (GstElement * element, GstStateChange transition) { gboolean need_reset; + /* only reset the stream time when the application did not + * specify a stream time explicitly */ GST_OBJECT_LOCK (element); need_reset = pipeline->stream_time != GST_CLOCK_TIME_NONE; GST_OBJECT_UNLOCK (element); @@ -467,8 +544,11 @@ gst_pipeline_change_state (GstElement * element, GstStateChange transition) } return result; + /* ERRORS */ invalid_clock: { + /* we generate this error when the selected clock was not + * accepted by some element */ GST_ELEMENT_ERROR (pipeline, CORE, CLOCK, (_("Selected clock cannot be used in pipeline.")), ("Pipeline cannot operate with selected clock")); @@ -480,11 +560,11 @@ invalid_clock: /** * gst_pipeline_get_bus: - * @pipeline: the pipeline + * @pipeline: a #GstPipeline * - * Gets the #GstBus of this pipeline. + * Gets the #GstBus of @pipeline. * - * Returns: a GstBus + * Returns: a #GstBus, unref after usage. * * MT safe. */ @@ -496,11 +576,11 @@ gst_pipeline_get_bus (GstPipeline * pipeline) /** * gst_pipeline_set_new_stream_time: - * @pipeline: the pipeline + * @pipeline: a #GstPipeline * @time: the new stream time to set * - * Set the new stream time of the pipeline. The stream time is used to - * set the base time on the elements (see @gst_element_set_base_time()) + * Set the new stream time of @pipeline to @time. The stream time is used to + * set the base time on the elements (see gst_element_set_base_time()) * in the PAUSED->PLAYING state transition. * * Setting @time to #GST_CLOCK_TIME_NONE will disable the pipeline's management @@ -529,14 +609,18 @@ gst_pipeline_set_new_stream_time (GstPipeline * pipeline, GstClockTime time) /** * gst_pipeline_get_last_stream_time: - * @pipeline: the pipeline + * @pipeline: a #GstPipeline * - * Gets the last stream time of the pipeline. If the pipeline is PLAYING, - * the returned time is the stream time used to configure the elements - * in the PAUSED->PLAYING state. If the pipeline is PAUSED, the returned - * time is the stream time when the pipeline was paused. + * Gets the last stream time of @pipeline. If the pipeline is PLAYING, + * the returned time is the stream time used to configure the element's + * base time in the PAUSED->PLAYING state. If the pipeline is PAUSED, the + * returned time is the stream time when the pipeline was paused. * - * Returns: a GstClockTime + * This function returns #GST_CLOCK_TIME_NONE if the pipeline was + * configured to not handle the management of the element's base time + * (see gst_pipeline_set_new_stream_time()). + * + * Returns: a #GstClockTime. * * MT safe. */ @@ -571,6 +655,7 @@ gst_pipeline_provide_clock_func (GstElement * element) clock, clock ? GST_STR_NULL (GST_OBJECT_NAME (clock)) : "-"); } else { GST_OBJECT_UNLOCK (pipeline); + /* let the parent bin select a clock */ clock = GST_ELEMENT_CLASS (parent_class)-> provide_clock (GST_ELEMENT (pipeline)); @@ -590,11 +675,11 @@ gst_pipeline_provide_clock_func (GstElement * element) /** * gst_pipeline_get_clock: - * @pipeline: the pipeline + * @pipeline: a #GstPipeline * - * Gets the current clock used by the pipeline. + * Gets the current clock used by @pipeline. * - * Returns: a GstClock + * Returns: a #GstClock, unref after usage. */ GstClock * gst_pipeline_get_clock (GstPipeline * pipeline) @@ -607,13 +692,16 @@ gst_pipeline_get_clock (GstPipeline * pipeline) /** * gst_pipeline_use_clock: - * @pipeline: the pipeline + * @pipeline: a #GstPipeline * @clock: the clock to use * - * Force the pipeline to use the given clock. The pipeline will + * Force @pipeline to use the given @clock. The pipeline will * always use the given clock even if new clock providers are added * to this pipeline. * + * If @clock is NULL all clocking will be disabled which will make + * the pipeline run as fast as possible. + * * MT safe. */ void @@ -634,13 +722,14 @@ gst_pipeline_use_clock (GstPipeline * pipeline, GstClock * clock) /** * gst_pipeline_set_clock: - * @pipeline: the pipeline + * @pipeline: a #GstPipeline * @clock: the clock to set * - * Set the clock for the pipeline. The clock will be distributed + * Set the clock for @pipeline. The clock will be distributed * to all the elements managed by the pipeline. * - * Returns: TRUE if the clock could be set on the pipeline. + * Returns: TRUE if the clock could be set on the pipeline. FALSE if + * some element did not accept the clock. * * MT safe. */ @@ -656,9 +745,14 @@ gst_pipeline_set_clock (GstPipeline * pipeline, GstClock * clock) /** * gst_pipeline_auto_clock: - * @pipeline: the pipeline + * @pipeline: a #GstPipeline * - * Let the pipeline select a clock automatically. + * Let @pipeline select a clock automatically. This is the default + * behaviour. + * + * Use this function if you previous forced a fixed clock with + * gst_pipeline_use_clock() and want to restore the default + * pipeline clock selection algorithm. * * MT safe. */ @@ -677,6 +771,59 @@ gst_pipeline_auto_clock (GstPipeline * pipeline) GST_CAT_DEBUG (GST_CAT_CLOCK, "pipeline using automatic clock"); } +/** + * gst_pipeline_set_delay: + * @pipeline: a #GstPipeline + * @delay: the delay + * + * Set the expected delay needed for all elements to perform the + * PAUSED to PLAYING state change. @delay will be added to the + * base time of the elements so that they wait an additional @delay + * amount of time before starting to process buffers. + * + * This option is used for tuning purposes and should normally not be + * used. + * + * MT safe. + * + * Since: 0.10.5 + */ +void +gst_pipeline_set_delay (GstPipeline * pipeline, GstClockTime delay) +{ + g_return_if_fail (GST_IS_PIPELINE (pipeline)); + + GST_OBJECT_LOCK (pipeline); + pipeline->delay = delay; + GST_OBJECT_UNLOCK (pipeline); +} + +/** + * gst_pipeline_get_delay: + * @pipeline: a #GstPipeline + * + * Get the configured delay (see gst_pipeline_set_delay()). + * + * Returns: The configured delay. + * + * MT safe. + * + * Since: 0.10.5 + */ +GstClockTime +gst_pipeline_get_delay (GstPipeline * pipeline) +{ + GstClockTime res; + + g_return_val_if_fail (GST_IS_PIPELINE (pipeline), GST_CLOCK_TIME_NONE); + + GST_OBJECT_LOCK (pipeline); + res = pipeline->delay; + GST_OBJECT_UNLOCK (pipeline); + + return res; +} + /** * gst_pipeline_set_auto_flush_bus: * @pipeline: a #GstPipeline @@ -685,12 +832,16 @@ gst_pipeline_auto_clock (GstPipeline * pipeline) * * Usually, when a pipeline goes from READY to NULL state, it automatically * flushes all pending messages on the bus, which is done for refcounting - * purposes, to break circular references. This means that applications - * that update state using (async) bus messages (e.g. do certain things when a - * pipeline goes from PAUSED to READY) might not get to see messages when the - * pipeline is shut down, because they might be flushed before they can be - * dispatched in the main thread. This behaviour can be disabled using this - * function. + * purposes, to break circular references. + * + * This means that applications that update state using (async) bus messages + * (e.g. do certain things when a pipeline goes from PAUSED to READY) might + * not get to see messages when the pipeline is shut down, because they might + * be flushed before they can be dispatched in the main thread. This behaviour + * can be disabled using this function. + * + * It is important that all messages on the bus are handled when the + * automatic flushing is disabled else memory leaks will be introduced. * * MT safe. * @@ -710,6 +861,9 @@ gst_pipeline_set_auto_flush_bus (GstPipeline * pipeline, gboolean auto_flush) * gst_pipeline_get_auto_flush_bus: * @pipeline: a #GstPipeline * + * Check if @pipeline will automatically flush messages when going to + * the NULL state. + * * Returns: whether the pipeline will automatically flush its bus when * going from READY to NULL state or not. * diff --git a/gst/gstpipeline.h b/gst/gstpipeline.h index 6fcbf38dcb..5355a04aa3 100644 --- a/gst/gstpipeline.h +++ b/gst/gstpipeline.h @@ -72,6 +72,7 @@ struct _GstPipeline { /*< private >*/ GstPipelinePrivate *priv; + gpointer _gst_reserved[GST_PADDING-1]; }; @@ -95,6 +96,9 @@ gboolean gst_pipeline_set_clock (GstPipeline *pipeline, GstClock GstClock* gst_pipeline_get_clock (GstPipeline *pipeline); 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_auto_flush_bus (GstPipeline *pipeline, gboolean auto_flush); gboolean gst_pipeline_get_auto_flush_bus (GstPipeline *pipeline); diff --git a/gst/gstsegment.c b/gst/gstsegment.c index e2f987d6e1..2cb761d8c4 100644 --- a/gst/gstsegment.c +++ b/gst/gstsegment.c @@ -64,7 +64,7 @@ * If the cur_type was different from GST_SEEK_TYPE_NONE, playback continues from * the last_pos position, possibly with updated flags or rate. * - * For elements that want to us #GstSegment to track the playback region, use + * For elements that want to use #GstSegment to track the playback region, use * gst_segment_set_newsegment() to update the segment fields with the information from * the newsegment event. The gst_segment_clip() method can be used to check and clip * the media data to the segment boundaries. @@ -77,7 +77,7 @@ * gst_segment_to_stream_time() can be used to convert a timestamp and the segment * info to stream time (which is always between 0 and the duration of the stream). * - * Last reviewed on 2005-12-12 (0.10.0) + * Last reviewed on 2006-03-12 (0.10.5) */ static GstSegment * @@ -174,7 +174,7 @@ gst_segment_init (GstSegment * segment, GstFormat format) * used by elements that perform seeking and know the total duration of the * segment. * - * This field should be set to allow seeking request relative to the + * This field should be set to allow seeking requests relative to the * duration. */ void @@ -198,6 +198,9 @@ gst_segment_set_duration (GstSegment * segment, GstFormat format, * @position: the position * * Set the last observed stop position in the segment to @position. + * + * This field should be set to allow seeking requests relative to the + * current playing position. */ void gst_segment_set_last_stop (GstSegment * segment, GstFormat format, @@ -223,8 +226,7 @@ gst_segment_set_last_stop (GstSegment * segment, GstFormat format, * @cur: the seek start value * @stop_type: the seek method * @stop: the seek stop value - * @update: boolean holding whether an update the current segment is - * needed. + * @update: boolean holding whether start or stop were updated. * * Update the segment structure with the field values of a seek event. * @@ -450,11 +452,12 @@ gst_segment_to_stream_time (GstSegment * segment, GstFormat format, * @position: the position in the segment * * Translate @position to the total running time using the currently configured - * segment. + * and previously accumulated segments. * * This function is typically used by elements that need to synchronize to the * global clock in a pipeline. The runnning time is a constantly increasing value - * starting from 0. + * starting from 0. When gst_segment_init() is called, this value will reset to + * 0. * * Returns: the position as the total running time. */ @@ -491,8 +494,16 @@ gst_segment_to_running_time (GstSegment * segment, GstFormat format, * Clip the given @start and @stop values to the segment boundaries given * in @segment. * - * Returns: TRUE if the given @start and @stop times fall partially in - * @segment, FALSE if the values are completely outside of the segment. + * If the function returns FALSE, @start and @stop are known to fall + * outside of @segment and @clip_start and @clip_stop are not updated. + * + * When the function returns TRUE, @clip_start and @clip_stop will be + * updated. If @clip_start or @clip_stop are different from @start or @stop + * respectively, the region fell partially in the segment. + * + * Returns: TRUE if the given @start and @stop times fall partially or + * completely in @segment, FALSE if the values are completely outside + * of the segment. */ gboolean gst_segment_clip (GstSegment * segment, GstFormat format, gint64 start,