GStreamer Plugin Writer's Guide (0.8.10) | ||
---|---|---|
<<< Previous | Next >>> |
Sinks are output elements that, opposite to sources, have no source pads and one or more (usually one) sink pad. They can be sound card outputs, disk writers, etc. This chapter will discuss the basic implementation of sink elements.
Except for corner cases, sink elements will be _chain
()-based elements. The concept of such elements has
been discussed before in detail, so that will be skipped here. What
is very important in sink elements, specifically in real-time audio
and video sources (such as osssink
or
ximagesink
), is event handling in the
_chain ()-function, because most elements rely
on EOS-handling of the sink element, and because A/V synchronization
can only be perfect if the element takes this into account.
How to achieve synchronization between streams depends on whether you're a clock-providing or a clock-receiving element. If you're the clock provider, you can do with time whatever you want. Correct handling would mean that you check whether the end of the previous buffer (if any) and the start of the current buffer are the same. If so, there's no gap between the two and you can continue playing right away. If there is a gap, then you'll need to wait for your clock to reach that time. How to do that depends on the element type. In the case of audio output elements, you would output silence for a while. In the case of video, you would show background color. In case of subtitles, show no subtitles at all.
In the case that the provided clock and the received clock are not the same (or in the case where your element provides no clock, which is the same), you simply wait for the clock to reach the timestamp of the current buffer and then you handle the data in it.
A simple data handling function would look like this:
static void gst_my_sink_chain (GstPad *pad, GstData *data) { GstMySink *sink = GST_MY_SINK (gst_pad_get_parent (pad)); GstBuffer *buf; GstClockTime time; /* only needed if the element is GST_EVENT_AWARE */ if (GST_IS_EVENT (data)) { GstEvent *event = GST_EVENT (data); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: [ if your element provides a clock, disable (inactivate) it here ] /* pass-through */ default: /* the default handler handles discontinuities, even if your * element provides a clock! */ gst_pad_event_default (pad, event); break; } return; } buf = GST_BUFFER (data); if (GST_BUFFER_TIME_IS_VALID (buf)) time = GST_BUFFER_TIMESTAMP (buf); else time = sink->expected_next_time; /* Synchronization - the property is only useful in case the * element has the option of not syncing. So it is not useful * for hardware-sync (clock-providing) elements. */ if (sink->sync) { /* This check is only needed if you provide a clock. Else, * you can always execute the 'else' clause. */ if (sink->provided_clock == sink->received_clock) { /* GST_SECOND / 10 is 0,1 sec, it's an arbitrary value. The * casts are needed because else it'll be unsigned and we * won't detect negative values. */ if (llabs ((gint64) sink->expected_next_time - (gint64) time) > (GST_SECOND / 10)) { /* so are we ahead or behind? */ if (time > sink->expected_time) { /* we need to wait a while... In case of audio, output * silence. In case of video, output background color. * In case of subtitles, display nothing. */ [..] } else { /* Drop data. */ [..] } } } else { /* You could do more sophisticated things here, but we'll * keep it simple for the purpose of the example. */ gst_element_wait (GST_ELEMENT (sink), time); } } /* And now handle the data. */ [..] } |
<<< Previous | Home | Next >>> |
Using special memory | Up | Special memory |