GStreamer Plugin Writer's Guide (0.8.5.2) | ||
---|---|---|
<<< Previous | Writing a Source | Next >>> |
The above example does not provide any timing info, but will suffice
for elementary data sources such as a file source or network data
source element. Things become slightly more complicated, but still
very simple, if we create artificial video or audio data sources,
such as a video test image source or an artificial audio source (e.g.
sinesrc
or silence
).
It will become more complicated if we want the element to be a
realtime capture source, such as a video4linux source (for reading
video frames from a TV card) or an ALSA source (for reading data
from soundcards supported by an ALSA-driver). Here, we will need to
make the element aware of timing and clocking.
Timestamps can essentially be generated from all the information given above without any difficulty. We could add a very small amount of code to generate perfectly timestamped buffers from our _get ()-function:
static void gst_my_source_init (GstMySource *src) { [..] src->total_bytes = 0; } static GstData * gst_my_source_get (GstPad *pad) { GstMySource *src = GST_MY_SOURCE (gst_pad_get_parent (pad)); GstBuffer *buf; GstFormat fmt = GST_FORMAT_TIME; [..] GST_BUFFER_DURATION (buf) = GST_BUFFER_SIZE (buf) * (GST_SECOND / (44100 * 2)); GST_BUFFER_TIMESTAMP (buf) = src->total_bytes * (GST_SECOND / (44100 * 2)); src->total_bytes += GST_BUFFER_SIZE (buf); return GST_DATA (buf); } static GstStateReturn gst_my_source_change_state (GstElement *element) { GstMySource *src = GST_MY_SOURCE (element); switch (GST_STATE_PENDING (element)) { case GT_STATE_PAUSED_TO_READY: src->total_bytes = 0; break; default: break; } if (GST_ELEMENT_CLASS (parent_class)->change_state) return GST_ELEMENT_CLASS (parent_class)->change_state (element); return GST_STATE_SUCCESS; } |
That wasn't too hard. Now, let's assume real-time elements. Those
can either have hardware-timing, in which case we can rely on backends
to provide sync for us (in which case you probably want to provide a
clock), or we will have to emulate that internally (e.g. to acquire
sync in artificial data elements such as sinesrc
).
Let's first look at the second option (software sync). The first option
(hardware sync + providing a clock) does not require any special code
with respect to timing, and the clocking section already explained how
to provide a clock.
enum { ARG_0, [..] ARG_SYNC, [..] }; static void gst_my_source_class_init (GstMySourceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); [..] g_object_class_install_property (object_class, ARG_SYNC, g_param_spec_boolean ("sync", "Sync", "Synchronize to clock", FALSE, G_PARAM_READWRITE)); [..] } static void gst_my_source_init (GstMySource *src) { [..] src->sync = FALSE; } static void gst_my_source_get (GstPad *pad) { GstMySource *src = GST_MY_SOURCE (gst_pad_get_parent (pad)); GstBuffer *buf; [..] if (src->sync) { /* wait on clock */ gst_element_wait (GST_ELEMENT (src), GST_BUFFER_TIMESTAMP (buf)); } return GST_DATA (buf); } static void gst_my_source_get_property (GObject *object, guint prop_id, GParamSpec *pspec, GValue *value) { GstMySource *src = GST_MY_SOURCE (gst_pad_get_parent (pad)); switch (prop_id) { [..] case ARG_SYNC: g_value_set_boolean (value, src->sync); break; [..] } } static void gst_my_source_get_property (GObject *object, guint prop_id, GParamSpec *pspec, const GValue *value) { GstMySource *src = GST_MY_SOURCE (gst_pad_get_parent (pad)); switch (prop_id) { [..] case ARG_SYNC: src->sync = g_value_get_boolean (value); break; [..] } } |
Most of this is GObject wrapping code. The actual code to do software-sync (in the _get ()-function) is relatively small.
<<< Previous | Home | Next >>> |
Events, querying and converting | Up | Using special memory |