2005-07-18 Wim Taymans <wim@fluendo.com>
+ * docs/design/part-dynamic.txt:
+ * docs/design/part-events.txt:
+ * docs/design/part-seeking.txt:
+ Some more docs in the works.
+
+ * gst/base/gstbasetransform.c: (gst_base_transform_transform_caps),
+ (gst_base_transform_getcaps), (gst_base_transform_configure_caps),
+ (gst_base_transform_setcaps), (gst_base_transform_get_size),
+ (gst_base_transform_buffer_alloc), (gst_base_transform_event),
+ (gst_base_transform_handle_buffer),
+ (gst_base_transform_sink_activate_push),
+ (gst_base_transform_src_activate_pull),
+ (gst_base_transform_set_passthrough),
+ (gst_base_transform_is_passthrough):
+ Refcounting fixes.
+
+ * gst/gstbus.c: (gst_bus_source_dispatch), (gst_bus_poll):
+ Cleanups.
+
+ * gst/gstevent.c: (gst_event_finalize):
+ Set SRC to NULL.
+
+ * gst/gstutils.c: (gst_element_unlink),
+ (gst_pad_get_parent_element), (gst_pad_proxy_getcaps),
+ (gst_pad_proxy_setcaps):
+ * gst/gstutils.h:
+ Add _get_parent_element() to get a pads parent as an element.
+
+2005-07-18 Wim Taymans <wim@fluendo.com>
+
* check/gst/gstbin.c: (GST_START_TEST):
Remove bogus test.
--- /dev/null
+Dynamic pipelines
+-----------------
+
+This document describes many use cases for dynamically constructing and
+manipulating a running or paused pipeline and the features provided by
+GStreamer.
6) start stopped tasks and unlock the STREAM_LOCK, dataflow will continue
now from the new position.
+More information about the different seek types can be found in
+part-seeking.txt.
+
SIZE
----
--- /dev/null
+Seeking
+-------
+
+Seeking in GStreamer means configuring the pipeline for playback of the
+media between a certain start and stop time.
+
+Different kinds of seeking exist:
+
+ - immeditate seeking with low latency (FLUSH seek)
+ - seeking without flush, playback will start from the new
+ position after all the queues are emptied with old data.
+ - segment seeking with and without FLUSH, this can be used to
+ implement seamless looping or NLE functionality.
+
+Seeking can be performed in different formats such as time, frames
+or samples.
+
+Seeking can be performed to an absolute position or relative to the
+current playback position.
+
+For seeking to work reliably, all plugins in the pipeline need to follow
+the well-defined rules in this document.
+
+Non segment seeking will make the pipeline emit EOS when the configured
+playback range has been played.
+
+Segment seeking will not emit an EOS at the end of the range but will
+post a SEGMENT_STOP message on the bus. This message is posted by the
+earliest element in the pipeline, typically a demuxer. After receiving
+the message, the application can reconnect the pipeline or issue other
+seek events in the pipeline.
+
+
+Generating seeking events
+-------------------------
+
+
+
+
+
+The different kinds of seeking methods and their internal workings are
+described below.
+
+
+FLUSH seeking
+-------------
+
+This is the most common way of performing a seek in a playback application.
+The application issues a seek on the pipeline and the new media is immediatly
+played after the seek calls returns.
+
+
+seeking without FLUSH
+---------------------
+
+This seek type is typically performed after issuing segment seeks to finish
+the playback of the pipeline.
+
+
+segment seeking with FLUSH
+--------------------------
+
+This seek is typically performed when starting seamless looping.
+
+
+segment seeking without FLUSH
+-----------------------------
+
+This seek is typically performed when continuing seamless looping.
+
GstPad *otherpad;
GstCaps *caps;
- trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad));
+ trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
done:
GST_DEBUG ("returning %" GST_PTR_FORMAT, caps);
+ gst_object_unref (trans);
+
return caps;
}
GstCaps *othercaps = NULL;
gboolean ret = TRUE;
- trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad));
+ trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
if (othercaps)
gst_caps_unref (othercaps);
+ gst_object_unref (trans);
+
return ret;
/* ERRORS */
gboolean ret = FALSE;
gboolean unlock;
- trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad));
+ trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
if (bclass->event)
if (unlock)
GST_STREAM_UNLOCK (pad);
+ gst_object_unref (trans);
+
return ret;
}
GstBaseTransform *trans;
GstBaseTransformClass *bclass;
- trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad));
+ trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
if (active) {
if (bclass->start)
result = bclass->start (trans);
}
+ gst_object_unref (trans);
return result;
}
GstBaseTransform *trans;
GstBaseTransformClass *bclass;
- trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad));
+ trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
result = gst_pad_activate_pull (trans->sinkpad, active);
if (result && bclass->start)
result &= bclass->start (trans);
}
+ gst_object_unref (trans);
return result;
}
GstBusSource *bsource = (GstBusSource *) source;
GstMessage *message;
gboolean needs_pop = TRUE;
+ GstBus *bus;
+
+ g_return_val_if_fail (bsource != NULL, FALSE);
- g_return_val_if_fail (GST_IS_BUS (bsource->bus), FALSE);
+ bus = bsource->bus;
- message = gst_bus_peek (bsource->bus);
+ g_return_val_if_fail (GST_IS_BUS (bus), FALSE);
+
+ message = gst_bus_peek (bus);
GST_DEBUG ("have message %p", message);
g_return_val_if_fail (message != NULL, TRUE);
- if (!handler) {
- g_warning ("GstBus watch dispatched without callback\n"
- "You must call g_source_connect().");
- return FALSE;
- }
+ if (!handler)
+ goto no_handler;
GST_DEBUG ("calling dispatch with %p", message);
- needs_pop = handler (bsource->bus, message, user_data);
+ needs_pop = handler (bus, message, user_data);
GST_DEBUG ("handler returns %d", needs_pop);
if (needs_pop) {
- message = gst_bus_pop (bsource->bus);
+ message = gst_bus_pop (bus);
if (message) {
gst_message_unref (message);
} else {
GST_DEBUG ("handler requested pop but no message on the bus");
}
}
-
return TRUE;
+
+no_handler:
+ {
+ g_warning ("GstBus watch dispatched without callback\n"
+ "You must call g_source_connect().");
+ return FALSE;
+ }
}
static void
* specify a maximum time to poll with the @timeout parameter. If @timeout is
* negative, this function will block indefinitely.
*
+ * This function will enter the default mainloop while polling.
+ *
* Returns: The type of the message that was received, or GST_MESSAGE_UNKNOWN if
* the poll timed out. The message will remain in the bus queue; you will need
* to gst_bus_pop() it off before entering gst_bus_poll() again.
GstMessageType
gst_bus_poll (GstBus * bus, GstMessageType events, GstClockTimeDiff timeout)
{
- GstBusPollData *poll_data;
+ GstBusPollData poll_data;
GstMessageType ret;
guint id;
- poll_data = g_new0 (GstBusPollData, 1);
if (timeout >= 0)
- poll_data->timeout_id = g_timeout_add (timeout / GST_MSECOND,
- (GSourceFunc) poll_timeout, poll_data);
- poll_data->loop = g_main_loop_new (NULL, FALSE);
- poll_data->events = events;
- poll_data->revent = GST_MESSAGE_UNKNOWN;
-
- id = gst_bus_add_watch (bus, (GstBusHandler) poll_handler, poll_data);
- g_main_loop_run (poll_data->loop);
+ poll_data.timeout_id = g_timeout_add (timeout / GST_MSECOND,
+ (GSourceFunc) poll_timeout, &poll_data);
+ else
+ poll_data.timeout_id = 0;
+
+ poll_data.loop = g_main_loop_new (NULL, FALSE);
+ poll_data.events = events;
+ poll_data.revent = GST_MESSAGE_UNKNOWN;
+
+ id = gst_bus_add_watch (bus, (GstBusHandler) poll_handler, &poll_data);
+ g_main_loop_run (poll_data.loop);
g_source_remove (id);
- ret = poll_data->revent;
+ ret = poll_data.revent;
- if (poll_data->timeout_id)
- g_source_remove (poll_data->timeout_id);
- g_main_loop_unref (poll_data->loop);
- g_free (poll_data);
+ if (poll_data.timeout_id)
+ g_source_remove (poll_data.timeout_id);
+ g_main_loop_unref (poll_data.loop);
return ret;
}
if (GST_EVENT_SRC (event)) {
gst_object_unref (GST_EVENT_SRC (event));
+ GST_EVENT_SRC (event) = NULL;
}
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_TAG:
/* see if the pad is connected and is really a pad
* of dest */
if (peerpad) {
- GstElement *peerelem = gst_pad_get_parent (peerpad);
+ GstElement *peerelem;
+
+ peerelem = gst_pad_get_parent_element (peerpad);
if (peerelem == dest) {
gst_pad_unlink (pad, peerpad);
}
/**
+ * gst_pad_get_parent_element:
+ * @pad: a pad
+ *
+ * Gets the parent of @pad, cast to a #GstElement. If a @pad has no parent or
+ * its parent is not an element, return NULL.
+ *
+ * Returns: The parent of the pad. The caller has a reference on the parent, so
+ * unref when you're finished with it.
+ *
+ * MT safe.
+ */
+GstElement *
+gst_pad_get_parent_element (GstPad * pad)
+{
+ GstObject *p;
+
+ g_return_val_if_fail (GST_IS_PAD (pad), NULL);
+
+ p = gst_object_get_parent (GST_OBJECT_CAST (pad));
+
+ if (p && !GST_IS_ELEMENT (p)) {
+ gst_object_unref (p);
+ p = NULL;
+ }
+ return GST_ELEMENT_CAST (p);
+}
+
+/**
* gst_object_default_error:
* @object: a #GObject that signalled the error.
* @orig: the #GstObject that initiated the error.
GST_DEBUG ("proxying getcaps for %s:%s", GST_DEBUG_PAD_NAME (pad));
- element = gst_pad_get_parent (pad);
+ element = gst_pad_get_parent_element (pad);
if (element == NULL)
return NULL;
GST_DEBUG ("proxying pad link for %s:%s", GST_DEBUG_PAD_NAME (pad));
- element = gst_pad_get_parent (pad);
+ element = gst_pad_get_parent_element (pad);
iter = gst_element_iterate_pads (element);
GstCaps* gst_pad_proxy_getcaps (GstPad * pad);
gboolean gst_pad_proxy_setcaps (GstPad * pad, GstCaps * caps);
+GstElement* gst_pad_get_parent_element (GstPad *pad);
+
/* util query functions */
gboolean gst_pad_query_position (GstPad *pad, GstFormat *format,
gint64 *cur, gint64 *end);
GstPad *otherpad;
GstCaps *caps;
- trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad));
+ trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
done:
GST_DEBUG ("returning %" GST_PTR_FORMAT, caps);
+ gst_object_unref (trans);
+
return caps;
}
GstCaps *othercaps = NULL;
gboolean ret = TRUE;
- trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad));
+ trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
if (othercaps)
gst_caps_unref (othercaps);
+ gst_object_unref (trans);
+
return ret;
/* ERRORS */
gboolean ret = FALSE;
gboolean unlock;
- trans = GST_BASE_TRANSFORM (GST_PAD_PARENT (pad));
+ trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
if (bclass->event)
if (unlock)
GST_STREAM_UNLOCK (pad);
+ gst_object_unref (trans);
+
return ret;
}
GstBaseTransform *trans;
GstBaseTransformClass *bclass;
- trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad));
+ trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
if (active) {
if (bclass->start)
result = bclass->start (trans);
}
+ gst_object_unref (trans);
return result;
}
GstBaseTransform *trans;
GstBaseTransformClass *bclass;
- trans = GST_BASE_TRANSFORM (GST_OBJECT_PARENT (pad));
+ trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
result = gst_pad_activate_pull (trans->sinkpad, active);
if (result && bclass->start)
result &= bclass->start (trans);
}
+ gst_object_unref (trans);
return result;
}