+2005-05-06 Wim Taymans <wim@fluendo.com>
+
+ * docs/design/part-element-sink.txt:
+ * docs/design/part-element-source.txt:
+ * gst/base/gstbasesink.c: (gst_basesink_class_init),
+ (gst_basesink_event), (gst_basesink_activate):
+ * gst/base/gstbasesink.h:
+ * gst/base/gstbasesrc.c: (gst_basesrc_init), (gst_basesrc_unlock),
+ (gst_basesrc_activate):
+ * gst/base/gstbasesrc.h:
+ * gst/gstelement.c: (gst_element_pads_activate):
+ Some more documentation.
+ Fixed scheduling decision in _pads_activate().
+
2005-05-05 Andy Wingo <wingo@pobox.com>
* check/pipelines/simple_launch_lines.c (test_2_elements): "Fix"
--- /dev/null
+Sink elements
+-------------
+
+Sink elements consume data. They normally have no source pads.
+
+typical sink elements include:
+
+ - audio/video renderers
+ - network sinks
+ - filesinks
+
+Sinks are harder to construct than other element types as they are
+treated specially by the GStreamer core.
+
+
--- /dev/null
+Source elements
+---------------
+
+A source element is an element that provides data to the pipeline. It
+does typically not have any sink (input) pads.
+
+Typical source elements include:
+
+ - file readers
+ - network elements
+ - capture elements (video/audio/...)
+ - generators (signals/video/audio/...)
+
+A source element can operate in three ways:
+
+ - it is fully seekable, this means that random access can be performed
+ on it in an efficient way. (a file reader,...). This also typically
+ means that the source is not live.
+
+ - data can be obtained from it with a variable size. This means that
+ the source can give N bytes of data. An example is an audio source.
+ A video source always provides the same amount of data (one video
+ frame). Note that this is not a fully seekable source.
+
+ - it is a live source, this means that data arrives when it is ready.
+ An example of this is a video or network source.
+
+When writing a source, one has to look at how the source can operate to
+decide on the scheduling methods to implement on the source.
+
+ - fully seekable sources implement a getrange function on the source pad.
+
+ - sources that can give N bytes but cannot do seeking also implement a
+ getrange function but state that they cannot do random access.
+
+ - sources that are purely live sources implement a task to push out
+ data.
+
+Any source that has a getrange function must also implement a push based
+scheduling mode. In this mode the source starts a task that gets N bytes
+and pushes them out. Whenever possible, the peer element will select the
+getrange based scheduling method of the source, though.
+
+A source with a getrange function must activate itself in the pad activate
+function. This is needed because the downstream peer element will decide
+and activate the source element in its state change function before the
+source's state change function is called.
+
+
+Source base classes
+-------------------
+
+GstBaseSource:
+
+ This base class provides an implementation of a random access source and
+ is very well suited for file reader like sources.
+
+
+
+
+
+
+
+
+
+
+
LAST_SIGNAL
};
+/* FIXME, need to figure out a better way to handle the pull mode */
#define DEFAULT_SIZE 1024
#define DEFAULT_HAS_LOOP FALSE
#define DEFAULT_HAS_CHAIN TRUE
g_param_spec_boolean ("has-chain", "has-chain",
"Enable chain-based operation", DEFAULT_HAS_CHAIN,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ /* FIXME, this next value should be configured using an event from the
+ * upstream element */
g_object_class_install_property (G_OBJECT_CLASS (klass),
PROP_PREROLL_QUEUE_LEN,
g_param_spec_uint ("preroll-queue-len", "preroll-queue-len",
GST_STREAM_LOCK (pad);
+ /* EOS also finishes the preroll */
gst_basesink_finish_preroll (basesink, pad, NULL);
GST_LOCK (basesink);
{
gboolean result = FALSE;
GstBaseSink *basesink;
+ GstBaseSinkClass *bclass;
basesink = GST_BASESINK (GST_OBJECT_PARENT (pad));
+ bclass = GST_BASESINK_GET_CLASS (basesink);
switch (mode) {
case GST_ACTIVATE_PUSH:
}
GST_UNLOCK (basesink);
+ /* unlock any subclasses */
+ if (bclass->unlock)
+ bclass->unlock (basesink);
+
/* unlock preroll */
GST_PREROLL_LOCK (pad);
GST_PREROLL_SIGNAL (pad);
typedef struct _GstBaseSink GstBaseSink;
typedef struct _GstBaseSinkClass GstBaseSinkClass;
+/* a base class for implementing chain based sinks
+ *
+ * Preroll, EOS, state changes are all handled.
+ */
struct _GstBaseSink {
GstElement element;
GstPad *sinkpad;
GstActivateMode pad_mode;
- GQueue *preroll_queue; /* with PREROLL_LOCK */
- gint preroll_queue_max_len; /* with PREROLL_LOCK */
+ /*< protected >*/ /* with PREROLL_LOCK */
+ GQueue *preroll_queue;
+ gint preroll_queue_max_len;
guint64 offset;
gboolean has_loop;
struct _GstBaseSinkClass {
GstElementClass parent_class;
+ /* get caps from subclass */
GstCaps* (*get_caps) (GstBaseSink *sink);
+ /* notify subclass of new caps */
gboolean (*set_caps) (GstBaseSink *sink, GstCaps *caps);
+ /* allocate a new buffer with given caps */
GstBuffer* (*buffer_alloc) (GstBaseSink *sink, guint64 offset, guint size,
GstCaps *caps);
+ /* get the start and end times for syncing on this buffer */
void (*get_times) (GstBaseSink *sink, GstBuffer *buffer,
GstClockTime *start, GstClockTime *end);
+ /* unlock any pending access to the resource. subclasses should unlock
+ * any function ASAP. */
+ gboolean (*unlock) (GstBaseSink *sink);
+
+ /* notify subclass of event, preroll buffer or real buffer */
gboolean (*event) (GstBaseSink *sink, GstEvent *event);
GstFlowReturn (*preroll) (GstBaseSink *sink, GstBuffer *buffer);
GstFlowReturn (*render) (GstBaseSink *sink, GstBuffer *buffer);
basesrc->segment_start = -1;
basesrc->segment_end = -1;
basesrc->blocksize = DEFAULT_BLOCKSIZE;
+ basesrc->clock_id = NULL;
GST_FLAG_UNSET (basesrc, GST_BASESRC_STARTED);
}
GstBaseSrcClass *bclass;
gboolean result = FALSE;
+ /* unblock whatever the subclass is doing */
bclass = GST_BASESRC_GET_CLASS (basesrc);
if (bclass->unlock)
result = bclass->unlock (basesrc);
+ /* and unblock the clock as well, if any */
+ GST_LOCK (basesrc);
+ if (basesrc->clock_id) {
+ gst_clock_id_unschedule (basesrc->clock_id);
+ }
+ GST_UNLOCK (basesrc);
+
return result;
}
break;
case GST_ACTIVATE_NONE:
/* step 1, unblock clock sync (if any) */
+ gst_basesrc_unlock (basesrc);
/* step 2, make sure streaming finishes */
GST_STREAM_LOCK (pad);
GST_BASESRC_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 2
} GstFileSrcFlags;
-
+/* base class for random access sources
+ *
+ * This class is mostly usefull for elements that do byte based
+ * access to a random access resource, like files.
+ *
+ * Seeking, flushing, scheduling and sync is all handled by this
+ * base class.
+ */
typedef struct _GstBaseSrc GstBaseSrc;
typedef struct _GstBaseSrcClass GstBaseSrcClass;
GstPad *srcpad;
- gint blocksize;
+ /*< protected >*/ /* with LOCK */
+ gint blocksize; /* size of buffers when operating push based */
+ gboolean has_loop; /* some scheduling properties */
+ gboolean has_getrange;
+ gboolean seekable;
+ gboolean random_access;
+
+ GstClockID clock_id; /* for syncing */
+ GstClockTime end_time;
- gint64 segment_start;
+ /* with STREAM_LOCK */
+ gint64 segment_start; /* start and end positions for seeking */
gint64 segment_end;
gboolean segment_loop;
- gboolean has_loop;
- gboolean has_getrange;
-
- gboolean seekable;
- guint64 offset;
- guint64 size;
+ guint64 offset; /* current offset in the resource */
+ guint64 size; /* total size of the resource */
};
struct _GstBaseSrcClass {
GstElementClass parent_class;
+ /* get caps from subclass */
GstCaps* (*get_caps) (GstBaseSrc *src);
+ /* notify the subclass of new caps */
gboolean (*set_caps) (GstBaseSrc *src, GstCaps *caps);
+ /* start and stop processing, ideal for opening/closing the resource */
gboolean (*start) (GstBaseSrc *src);
gboolean (*stop) (GstBaseSrc *src);
+ /* given a buffer, return start and stop time when it should be pushed
+ * out. The base class will sync on the clock using these times. */
void (*get_times) (GstBaseSrc *src, GstBuffer *buffer,
GstClockTime *start, GstClockTime *end);
+ /* get the total size of the resource in bytes */
gboolean (*get_size) (GstBaseSrc *src, guint64 *size);
+ /* check if the resource is seekable */
gboolean (*is_seekable) (GstBaseSrc *src);
+ /* unlock any pending access to the resource. subclasses should unlock
+ * any function ASAP. */
gboolean (*unlock) (GstBaseSrc *src);
+ /* notify subclasses of an event */
gboolean (*event) (GstBaseSrc *src, GstEvent *event);
+ /* ask the subclass to create a buffer */
GstFlowReturn (*create) (GstBaseSrc *src, guint64 offset, guint size,
GstBuffer **buf);
};
/* If the pad is a sink with loop and the peer has a get function,
* we can activate the sinkpad, FIXME, logic is reversed as
* check_pull_range() checks the peer of the given pad. */
- if ((GST_PAD_IS_SINK (pad) && pad_get && peer_loop) ||
- (GST_PAD_IS_SRC (pad) && peer_get && pad_loop)) {
+ if ((GST_PAD_IS_SINK (pad) && pad_get && pad_loop) ||
+ (GST_PAD_IS_SRC (pad) && peer_get && peer_loop)) {
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
"%sactivating pad %s pull mode", (active ? "" : "(de)"),
GST_OBJECT_NAME (pad));
LAST_SIGNAL
};
+/* FIXME, need to figure out a better way to handle the pull mode */
#define DEFAULT_SIZE 1024
#define DEFAULT_HAS_LOOP FALSE
#define DEFAULT_HAS_CHAIN TRUE
g_param_spec_boolean ("has-chain", "has-chain",
"Enable chain-based operation", DEFAULT_HAS_CHAIN,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ /* FIXME, this next value should be configured using an event from the
+ * upstream element */
g_object_class_install_property (G_OBJECT_CLASS (klass),
PROP_PREROLL_QUEUE_LEN,
g_param_spec_uint ("preroll-queue-len", "preroll-queue-len",
GST_STREAM_LOCK (pad);
+ /* EOS also finishes the preroll */
gst_basesink_finish_preroll (basesink, pad, NULL);
GST_LOCK (basesink);
{
gboolean result = FALSE;
GstBaseSink *basesink;
+ GstBaseSinkClass *bclass;
basesink = GST_BASESINK (GST_OBJECT_PARENT (pad));
+ bclass = GST_BASESINK_GET_CLASS (basesink);
switch (mode) {
case GST_ACTIVATE_PUSH:
}
GST_UNLOCK (basesink);
+ /* unlock any subclasses */
+ if (bclass->unlock)
+ bclass->unlock (basesink);
+
/* unlock preroll */
GST_PREROLL_LOCK (pad);
GST_PREROLL_SIGNAL (pad);
typedef struct _GstBaseSink GstBaseSink;
typedef struct _GstBaseSinkClass GstBaseSinkClass;
+/* a base class for implementing chain based sinks
+ *
+ * Preroll, EOS, state changes are all handled.
+ */
struct _GstBaseSink {
GstElement element;
GstPad *sinkpad;
GstActivateMode pad_mode;
- GQueue *preroll_queue; /* with PREROLL_LOCK */
- gint preroll_queue_max_len; /* with PREROLL_LOCK */
+ /*< protected >*/ /* with PREROLL_LOCK */
+ GQueue *preroll_queue;
+ gint preroll_queue_max_len;
guint64 offset;
gboolean has_loop;
struct _GstBaseSinkClass {
GstElementClass parent_class;
+ /* get caps from subclass */
GstCaps* (*get_caps) (GstBaseSink *sink);
+ /* notify subclass of new caps */
gboolean (*set_caps) (GstBaseSink *sink, GstCaps *caps);
+ /* allocate a new buffer with given caps */
GstBuffer* (*buffer_alloc) (GstBaseSink *sink, guint64 offset, guint size,
GstCaps *caps);
+ /* get the start and end times for syncing on this buffer */
void (*get_times) (GstBaseSink *sink, GstBuffer *buffer,
GstClockTime *start, GstClockTime *end);
+ /* unlock any pending access to the resource. subclasses should unlock
+ * any function ASAP. */
+ gboolean (*unlock) (GstBaseSink *sink);
+
+ /* notify subclass of event, preroll buffer or real buffer */
gboolean (*event) (GstBaseSink *sink, GstEvent *event);
GstFlowReturn (*preroll) (GstBaseSink *sink, GstBuffer *buffer);
GstFlowReturn (*render) (GstBaseSink *sink, GstBuffer *buffer);
basesrc->segment_start = -1;
basesrc->segment_end = -1;
basesrc->blocksize = DEFAULT_BLOCKSIZE;
+ basesrc->clock_id = NULL;
GST_FLAG_UNSET (basesrc, GST_BASESRC_STARTED);
}
GstBaseSrcClass *bclass;
gboolean result = FALSE;
+ /* unblock whatever the subclass is doing */
bclass = GST_BASESRC_GET_CLASS (basesrc);
if (bclass->unlock)
result = bclass->unlock (basesrc);
+ /* and unblock the clock as well, if any */
+ GST_LOCK (basesrc);
+ if (basesrc->clock_id) {
+ gst_clock_id_unschedule (basesrc->clock_id);
+ }
+ GST_UNLOCK (basesrc);
+
return result;
}
break;
case GST_ACTIVATE_NONE:
/* step 1, unblock clock sync (if any) */
+ gst_basesrc_unlock (basesrc);
/* step 2, make sure streaming finishes */
GST_STREAM_LOCK (pad);
GST_BASESRC_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 2
} GstFileSrcFlags;
-
+/* base class for random access sources
+ *
+ * This class is mostly usefull for elements that do byte based
+ * access to a random access resource, like files.
+ *
+ * Seeking, flushing, scheduling and sync is all handled by this
+ * base class.
+ */
typedef struct _GstBaseSrc GstBaseSrc;
typedef struct _GstBaseSrcClass GstBaseSrcClass;
GstPad *srcpad;
- gint blocksize;
+ /*< protected >*/ /* with LOCK */
+ gint blocksize; /* size of buffers when operating push based */
+ gboolean has_loop; /* some scheduling properties */
+ gboolean has_getrange;
+ gboolean seekable;
+ gboolean random_access;
+
+ GstClockID clock_id; /* for syncing */
+ GstClockTime end_time;
- gint64 segment_start;
+ /* with STREAM_LOCK */
+ gint64 segment_start; /* start and end positions for seeking */
gint64 segment_end;
gboolean segment_loop;
- gboolean has_loop;
- gboolean has_getrange;
-
- gboolean seekable;
- guint64 offset;
- guint64 size;
+ guint64 offset; /* current offset in the resource */
+ guint64 size; /* total size of the resource */
};
struct _GstBaseSrcClass {
GstElementClass parent_class;
+ /* get caps from subclass */
GstCaps* (*get_caps) (GstBaseSrc *src);
+ /* notify the subclass of new caps */
gboolean (*set_caps) (GstBaseSrc *src, GstCaps *caps);
+ /* start and stop processing, ideal for opening/closing the resource */
gboolean (*start) (GstBaseSrc *src);
gboolean (*stop) (GstBaseSrc *src);
+ /* given a buffer, return start and stop time when it should be pushed
+ * out. The base class will sync on the clock using these times. */
void (*get_times) (GstBaseSrc *src, GstBuffer *buffer,
GstClockTime *start, GstClockTime *end);
+ /* get the total size of the resource in bytes */
gboolean (*get_size) (GstBaseSrc *src, guint64 *size);
+ /* check if the resource is seekable */
gboolean (*is_seekable) (GstBaseSrc *src);
+ /* unlock any pending access to the resource. subclasses should unlock
+ * any function ASAP. */
gboolean (*unlock) (GstBaseSrc *src);
+ /* notify subclasses of an event */
gboolean (*event) (GstBaseSrc *src, GstEvent *event);
+ /* ask the subclass to create a buffer */
GstFlowReturn (*create) (GstBaseSrc *src, guint64 offset, guint size,
GstBuffer **buf);
};