GStreamer Plugin Writer's Guide (0.8.3.2) | ||
---|---|---|
<<< Previous | How a loopfunc works | Next >>> |
A second type of elements that wants to be loop-based, are the so-called bytestream-elements. Until now, we've only dealt with elements that receive of pull full buffers of a random size from other elements. Often, however, it is wanted to have control over the stream at a byte-level, such as in stream parsers or demuxers. It is possible to manually pull buffers and merge them until a certain size; it is easier, however, to use bytestream, which wraps this behaviour.
Bytestream-using elements are ususally stream parsers or demuxers. For now, we will take a parser as an example. Demuxers require some more magic that will be dealt with later in this guide: the chapter called Request and Sometimes pads. The goal of this parser will be to parse a text-file and to push each line of text as a separate buffer over its source pad.
static void gst_my_filter_loopfunc (GstElement *element) { GstMyFilter *filter = GST_MY_FILTER (element); gint n, num; guint8 *data; for (n = 0; ; n++) { num = gst_bytestream_peek_bytes (filter->bs, &data, n + 1); if (num != n + 1) { GstEvent *event = NULL; guint remaining; gst_bytestream_get_status (filter->bs, &remaining, &event); if (event) { if (GST_EVENT_TYPE (event) == GST_EVENT_EOS)) { /* end-of-file */ gst_pad_push (filter->srcpad, GST_DATA (event)); gst_element_set_eos (element); return; } gst_event_unref (event); } /* failed to read - throw error and bail out */ gst_element_error (element, STREAM, READ, (NULL), (NULL)); return; } /* check if the last character is a newline */ if (data[n] == '\n') { GstBuffer *buf = gst_buffer_new_and_alloc (n + 1); /* read the line of text without newline - then flush the newline */ gst_bytestream_peek_data (filter->bs, &data, n); memcpy (GST_BUFFER_DATA (buf), data, n); GST_BUFFER_DATA (buf)[n] = '\0'; gst_bytestream_flush_fast (filter->bs, n + 1); g_print ("Pushing '%s'\n", GST_BUFFER_DATA (buf)); gst_pad_push (filter->srcpad, GST_DATA (buf)); return; } } } static void gst_my_filter_change_state (GstElement *element) { GstMyFilter *filter = GST_MY_FILTER (element); switch (GST_STATE_TRANSITION (element)) { case GST_STATE_READY_TO_PAUSED: filter->bs = gst_bytestream_new (filter->sinkpad); break; case GST_STATE_PAUSED_TO_READY: gst_bytestream_destroy (filter->bs); break; default: break; } if (GST_ELEMENT_CLASS (parent_class)->change_state) return GST_ELEMENT_CLASS (parent_class)->change_state (element); return GST_STATE_SUCCESS; } |
In the above example, you'll notice how bytestream handles buffering of data for you. The result is that you can handle the same data multiple times. Event handling in bytestream is currently sort of wacky, but it works quite well. The one big disadvantage of bytestream is that it requires the element to be loop-based. Long-term, we hope to have a chain-based usable version of bytestream, too.
<<< Previous | Home | Next >>> |
How a loopfunc works | Up | Adding a second output |