1 <chapter id="chapter-advanced-interfaces">
2 <title>Interfaces</title>
4 Previously, in the chapter <xref linkend="chapter-building-args"/>, we have
5 introduced the concept of GObject properties of controlling an element's
6 behaviour. This is very powerful, but it has two big disadvantages:
7 first of all, it is too generic, and second, it isn't dynamic.
10 The first disadvantage is related to the customizability of the end-user
11 interface that will be built to control the element. Some properties are
12 more important than others. Some integer properties are better shown in a
13 spin-button widget, whereas others would be better represented by a slider
14 widget. Such things are not possible because the UI has no actual meaning
15 in the application. A UI widget that represents a bitrate property is the
16 same as a UI widget that represents the size of a video, as long as both
17 are of the same <classname>GParamSpec</classname> type. Another problem,
18 is that things like parameter grouping, function grouping, or parameter
23 The second problem with parameters are that they are not dynamic. In
24 many cases, the allowed values for a property are not fixed, but depend
25 on things that can only be detected at runtime. The names of inputs for
26 a TV card in a video4linux source element, for example, can only be
27 retrieved from the kernel driver when we've opened the device; this only
28 happens when the element goes into the READY state. This means that we
29 cannot create an enum property type to show this to the user.
32 The solution to those problems is to create very specialized types of
33 controls for certain often-used controls. We use the concept of interfaces
34 to achieve this. The basis of this all is the glib
35 <classname>GTypeInterface</classname> type. For each case where we think
36 it's useful, we've created interfaces which can be implemented by elements
37 at their own will. We've also created a small extension to
38 <classname>GTypeInterface</classname> (which is static itself, too) which
39 allows us to query for interface availability based on runtime properties.
40 This extension is called <ulink type="http"
41 url="../../gstreamer/html/GstImplementsInterface.html"><classname>
42 GstImplementsInterface</classname></ulink>.
45 One important note: interfaces do <emphasis>not</emphasis> replace
46 properties. Rather, interfaces should be built <emphasis>next to</emphasis>
47 properties. There are two important reasons for this. First of all,
49 can be saved in XML files. Second, properties can be specified on the
50 commandline (<filename>gst-launch</filename>).
53 <sect1 id="section-iface-general" xreflabel="How to Implement Interfaces">
54 <title>How to Implement Interfaces</title>
56 Implementing interfaces is initiated in the <function>_get_type ()</function>
57 of your element. You can register one or more interfaces after having
58 registered the type itself. Some interfaces have dependencies on other
59 interfaces or can only be registered by certain types of elements. You
60 will be notified of doing that wrongly when using the element: it will
61 quit with failed assertions, which will explain what went wrong. In the
62 case of GStreamer, the only dependency that <emphasis>some</emphasis>
63 interfaces have is <ulink type="http"
64 url="../../gstreamer/html/GstImplementsInterface.html"><classname>
65 GstImplementsInterface</classname></ulink>. Per
66 interface, we will indicate clearly when it depends on this extension.
67 If it does, you need to register support for <emphasis>that</emphasis>
68 interface before registering support for the interface that you're
69 wanting to support. The example below explains how to add support for a
70 simple interface with no further dependencies. For a small explanation
71 on <ulink type="http" url="../../gstreamer/html/GstImplementsInterface.html">
72 <classname>GstImplementsInterface</classname></ulink>, see the next section
73 about the mixer interface: <xref linkend="section-iface-mixer"/>.
76 static void gst_my_filter_some_interface_init (GstSomeInterface *iface);
79 gst_my_filter_get_type (void)
81 static GType my_filter_type = 0;
83 if (!my_filter_type) {
84 static const GTypeInfo my_filter_info = {
85 sizeof (GstMyFilterClass),
86 (GBaseInitFunc) gst_my_filter_base_init,
88 (GClassInitFunc) gst_my_filter_class_init,
93 (GInstanceInitFunc) gst_my_filter_init
95 static const GInterfaceInfo some_interface_info = {
96 (GInterfaceInitFunc) gst_my_filter_some_interface_init,
102 g_type_register_static (GST_TYPE_MY_FILTER,
104 &my_filter_info, 0);
105 g_type_add_interface_static (my_filter_type,
106 GST_TYPE_SOME_INTERFACE,
107 &some_interface_info);
110 return my_filter_type;
114 gst_my_filter_some_interface_init (GstSomeInterface *iface)
116 /* here, you would set virtual function pointers in the interface */
121 <sect1 id="section-iface-uri" xreflabel="URI interface">
122 <title>URI interface</title>
128 <sect1 id="section-iface-mixer" xreflabel="Mixer Interface">
129 <title>Mixer Interface</title>
131 The goal of the mixer interface is to provide a simple yet powerful API
132 to applications for audio hardware mixer/volume control. Most soundcards
133 have hardware mixers, where volume can be changed, they can be muted,
134 inputs can be modified to mix their content into what will be read from
135 the device by applications (in our case: audio source plugins). The
136 mixer interface is the way to control those. The mixer interface can
137 also be used for volume control in software (e.g. the <quote>volume</quote>
138 element). The end goal of this interface is to allow development of
139 hardware volume control applications and for the control of audio volume
140 and input/output settings.
143 The mixer interface requires the <ulink type="http"
144 url="../../gstreamer/html/GstImplementsInterface.html"><classname>
145 GstImplementsInterface</classname></ulink>
146 interface to be implemented by the element. The example below will
147 feature both, so it serves as an example for the <ulink type="http"
148 url="../../gstreamer/html/GstImplementsInterface.html"><classname>
149 GstImplementsInterface</classname></ulink>, too. In this
150 interface, it is required to set a function pointer for the <function>
151 supported ()</function> function.
152 If you don't, this function will always return FALSE (default
153 implementation) and the mixer interface implementation will not work. For
154 the mixer interface, the only required function is
155 <function>list_tracks ()</function>. All other function pointers in the
156 mixer interface are optional, although it is strongly recommended to set
157 function pointers for at least the <function>get_volume ()</function> and
158 <function>set_volume ()</function> functions. The API reference for this
159 interface documents the goal of each function, so we will limit ourselves
160 to the implementation here.
163 The following example shows a mixer implementation for a software N-to-1
164 element. It does not show the actual process of stream mixing, that is
165 far too complicated for this guide.
168 #include <gst/mixer/mixer.h>
170 typedef struct _GstMyFilter {
176 static void gst_my_filter_implements_interface_init (GstImplementsInterfaceClass *iface);
177 static void gst_my_filter_mixer_interface_init (GstMixerClass *iface);
180 gst_my_filter_get_type (void)
183 static const GInterfaceInfo implements_interface_info = {
184 (GInterfaceInitFunc) gst_my_filter_implements_interface_init,
188 static const GInterfaceInfo mixer_interface_info = {
189 (GInterfaceInitFunc) gst_my_filter_mixer_interface_init,
194 g_type_add_interface_static (my_filter_type,
195 GST_TYPE_IMPLEMENTS_INTERFACE,
196 &implements_interface_info);
197 g_type_add_interface_static (my_filter_type,
199 &mixer_interface_info);
204 gst_my_filter_init (GstMyFilter *filter)
206 GstMixerTrack *track = NULL;
208 filter->volume = 100;
209 filter->tracks = NULL;
210 track = g_object_new (GST_TYPE_MIXER_TRACK, NULL);
211 track->label = g_strdup ("MyTrack");
212 track->num_channels = 1;
213 track->min_volume = 0;
214 track->max_volume = 100;
215 track->flags = GST_MIXER_TRACK_SOFTWARE;
216 filter->tracks = g_list_append (filter->tracks, track);
220 gst_my_filter_interface_supported (GstImplementsInterface *iface,
223 g_return_val_if_fail (iface_type == GST_TYPE_MIXER, FALSE);
225 /* for the sake of this example, we'll always support it. However, normally,
226 * you would check whether the device you've opened supports mixers. */
231 gst_my_filter_implements_interface_init (GstImplementsInterfaceClass *iface)
233 iface->supported = gst_my_filter_interface_supported;
237 * This function returns the list of support tracks (inputs, outputs)
238 * on this element instance. Elements usually build this list during
239 * _init () or when going from NULL to READY.
243 gst_my_filter_mixer_list_tracks (GstMixer *mixer)
245 GstMyFilter *filter = GST_MY_FILTER (mixer);
247 return filter->tracks;
251 * Set volume. volumes is an array of size track->num_channels, and
252 * each value in the array gives the wanted volume for one channel
257 gst_my_filter_mixer_set_volume (GstMixer *mixer,
258 GstMixerTrack *track,
261 GstMyFilter *filter = GST_MY_FILTER (mixer);
263 filter->volume = volumes[0];
265 g_print ("Volume set to %d\n", filter->volume);
269 gst_my_filter_mixer_get_volume (GstMixer *mixer,
270 GstMixerTrack *track,
273 GstMyFilter *filter = GST_MY_FILTER (mixer);
275 volumes[0] = filter->volume;
279 gst_my_filter_mixer_interface_init (GstMixerClass *iface)
281 /* the mixer interface requires a definition of the mixer type:
282 * hardware or software? */
283 GST_MIXER_TYPE (iface) = GST_MIXER_SOFTWARE;
285 /* virtual function pointers */
286 iface->list_tracks = gst_my_filter_mixer_list_tracks;
287 iface->set_volume = gst_my_filter_mixer_set_volume;
288 iface->get_volume = gst_my_filter_mixer_get_volume;
292 The mixer interface is very audio-centric. However, with the software
293 flag set, the mixer can be used to mix any kind of stream in a N-to-1
294 element to join (not aggregate!) streams together into one output stream.
295 Conceptually, that's called mixing too. You can always use the element
296 factory's <quote>category</quote> to indicate type of your element. In
297 a software element that mixes random streams, you would not be required
298 to implement the <function>_get_volume ()</function> or
299 <function>_set_volume ()</function> functions. Rather, you would only
300 implement the <function>_set_record ()</function> to enable or disable
301 tracks in the output stream. to make sure that a mixer-implementing
302 element is of a certain type, check the element factory's category.
306 <sect1 id="section-iface-tuner" xreflabel="Tuner Interface">
307 <title>Tuner Interface</title>
309 As opposed to the mixer interface, that's used to join together N streams
310 into one output stream by mixing all streams together, the tuner
311 interface is used in N-to-1 elements too, but instead of mixing the input
312 streams, it will select one stream and push the data of that stream to
313 the output stream. It will discard the data of all other streams. There
314 is a flag that indicates whether this is a software-tuner (in which case
315 it is a pure software implementation, with N sink pads and 1 source pad)
316 or a hardware-tuner, in which case it only has one source pad, and the
317 whole stream selection process is done in hardware. The software case can
318 be used in elements such as <emphasis>switch</emphasis>. The hardware
319 case can be used in elements with channel selection, such as video source
320 elements (v4lsrc, v4l2src, etc.). If you need a specific element type,
321 use the element factory's <quote>category</quote> to make sure that the
322 element is of the type that you need. Note that the interface itself is
323 highly analog-video-centric.
326 This interface requires the <ulink type="http"
327 url="../../gstreamer/html/GstImplementsInterface.html"><classname>
328 GstImplementsInterface</classname></ulink>
329 interface to work correctly.
332 The following example shows how to implement the tuner interface in an
333 element. It does not show the actual process of stream selection, that
334 is irrelevant for this section.
337 #include <gst/tuner/tuner.h>
339 typedef struct _GstMyFilter {
345 static void gst_my_filter_implements_interface_init (GstImplementsInterfaceClass *iface);
346 static void gst_my_filter_tuner_interface_init (GstTunerClass *iface);
349 gst_my_filter_get_type (void)
352 static const GInterfaceInfo implements_interface_info = {
353 (GInterfaceInitFunc) gst_my_filter_implements_interface_init,
357 static const GInterfaceInfo tuner_interface_info = {
358 (GInterfaceInitFunc) gst_my_filter_tuner_interface_init,
363 g_type_add_interface_static (my_filter_type,
364 GST_TYPE_IMPLEMENTS_INTERFACE,
365 &implements_interface_info);
366 g_type_add_interface_static (my_filter_type,
368 &tuner_interface_info);
373 gst_my_filter_init (GstMyFilter *filter)
375 GstTunerChannel *channel = NULL;
377 filter->active_input = 0;
378 filter->channels = NULL;
379 channel = g_object_new (GST_TYPE_TUNER_CHANNEL, NULL);
380 channel->label = g_strdup ("MyChannel");
381 channel->flags = GST_TUNER_CHANNEL_INPUT;
382 filter->channels = g_list_append (filter->channels, channel);
386 gst_my_filter_interface_supported (GstImplementsInterface *iface,
389 g_return_val_if_fail (iface_type == GST_TYPE_TUNER, FALSE);
391 /* for the sake of this example, we'll always support it. However, normally,
392 * you would check whether the device you've opened supports tuning. */
397 gst_my_filter_implements_interface_init (GstImplementsInterfaceClass *iface)
399 iface->supported = gst_my_filter_interface_supported;
403 gst_my_filter_tuner_list_channels (GstTuner *tuner)
405 GstMyFilter *filter = GST_MY_FILTER (tuner);
407 return filter->channels;
410 static GstTunerChannel *
411 gst_my_filter_tuner_get_channel (GstTuner *tuner)
413 GstMyFilter *filter = GST_MY_FILTER (tuner);
415 return g_list_nth_data (filter->channels,
416 filter->active_input);
420 gst_my_filter_tuner_set_channel (GstTuner *tuner,
421 GstTunerChannel *channel)
423 GstMyFilter *filter = GST_MY_FILTER (tuner);
425 filter->active_input = g_list_index (filter->channels, channel);
426 g_assert (filter->active_input >= 0);
430 gst_my_filter_tuner_interface_init (GstTunerClass *iface)
432 iface->list_channels = gst_my_filter_tuner_list_channels;
433 iface->get_channel = gst_my_filter_tuner_get_channel;
434 iface->set_channel = gst_my_filter_tuner_set_channel;
438 As said, the tuner interface is very analog video-centric. It features
439 functions for selecting an input or output, and on inputs, it features
440 selection of a tuning frequency if the channel supports frequency-tuning
441 on that input. Likewise, it allows signal-strength-acquiring if the input
442 supports that. Frequency tuning can be used for radio or cable-TV tuning.
443 Signal-strength is an indication of the signal and can be used for
444 visual feedback to the user or for autodetection. Next to that, it also
445 features norm selection, which is only useful for analog video elements.
449 <sect1 id="section-iface-colorbalance" xreflabel="Color Balance Interface">
450 <title>Color Balance Interface</title>
456 <sect1 id="section-iface-propprobe" xreflabel="Property Probe Interface">
457 <title>Property Probe Interface</title>
459 Property probing is a generic solution to the problem that properties'
460 value lists in an enumeration are static. We've shown enumerations in
461 <xref linkend="chapter-building-args"/>. Property probing tries to accomplish
462 a goal similar to enumeration lists: to have a limited, explicit list of
463 allowed values for a property. There are two differences between
464 enumeration lists and probing. Firstly, enumerations only allow strings
465 as values; property probing works for any value type. Secondly, the
466 contents of a probed list of allowed values may change during the life
467 of an element. The contents of an enumeration list are static. Currently,
468 property probing is being used for detection of devices (e.g. for OSS
469 elements, Video4linux elements, etc.). It could - in theory - be used
470 for any property, though.
473 Property probing stores the list of allowed (or recommended) values in a
474 <classname>GValueArray</classname> and returns that to the user.
475 <symbol>NULL</symbol> is a valid return value, too. The process of
476 property probing is separated over two virtual functions: one for probing
477 the property to create a <classname>GValueArray</classname>, and one to
478 retrieve the current <classname>GValueArray</classname>. Those two are
479 separated because probing might take a long time (several seconds). Also,
480 this simplifies interface implementation in elements. For the application,
481 there are functions that wrap those two. For more information on this,
482 have a look at the API reference for the
483 <!-- FIXME: add link, but this is in ./gst-plugins/gst-libs/gst/propertyprobe/propertyprobe.c-->
484 <classname>GstPropertyProbe</classname> interface.
487 Below is a example of property probing for the audio filter element; it
488 will probe for allowed values for the <quote>silent</quote> property.
489 Indeed, this value is a <type>gboolean</type> so it doesn't
490 make much sense. Then again, it's only an example.
493 #include <gst/propertyprobe/propertyprobe.h>
495 static void gst_my_filter_probe_interface_init (GstPropertyProbeInterface *iface);
498 gst_my_filter_get_type (void)
501 static const GInterfaceInfo probe_interface_info = {
502 (GInterfaceInitFunc) gst_my_filter_probe_interface_init,
507 g_type_add_interface_static (my_filter_type,
508 GST_TYPE_PROPERTY_PROBE,
509 &probe_interface_info);
514 gst_my_filter_probe_get_properties (GstPropertyProbe *probe)
516 GObjectClass *klass = G_OBJECT_GET_CLASS (probe);
517 static GList *props = NULL;
522 pspec = g_object_class_find_property (klass, "silent");
523 props = g_list_append (props, pspec);
530 gst_my_filter_probe_needs_probe (GstPropertyProbe *probe,
532 const GParamSpec *pspec)
534 gboolean res = FALSE;
541 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
549 gst_my_filter_probe_probe_property (GstPropertyProbe *probe,
551 const GParamSpec *pspec)
555 /* don't need to do much here... */
558 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
564 gst_my_filter_get_silent_values (GstMyFilter *filter)
566 GValueArray *array = g_value_array_new (2);
567 GValue value = { 0 };
569 g_value_init (&value, G_TYPE_BOOLEAN);
572 g_value_set_boolean (&value, TRUE);
573 g_value_array_append (array, &value);
576 g_value_set_boolean (&value, FALSE);
577 g_value_array_append (array, &value);
579 g_value_unset (&value);
585 gst_my_filter_probe_get_values (GstPropertyProbe *probe,
587 const GParamSpec *pspec)
589 GstMyFilter *filter = GST_MY_FILTER (probe);
590 GValueArray *array = NULL;
594 array = gst_my_filter_get_silent_values (filter);
597 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
605 gst_my_filter_probe_interface_init (GstPropertyProbeInterface *iface)
607 iface->get_properties = gst_my_filter_probe_get_properties;
608 iface->needs_probe = gst_my_filter_probe_needs_probe;
609 iface->probe_property = gst_my_filter_probe_probe_property;
610 iface->get_values = gst_my_filter_probe_get_values;
614 You don't need to support any functions for getting or setting values.
615 All that is handled via the standard <classname>GObject</classname>
616 <function>_set_property ()</function> and <function>_get_property ()</function>
621 <sect1 id="section-iface-xoverlay" xreflabel="X Overlay Interface">
622 <title>X Overlay Interface</title>
624 An X Overlay is basically a video output in a XFree86 drawable. Elements
625 implementing this interface will draw video in a X11 window. Through this
626 interface, applications will be proposed 2 different modes to work with
627 a plugin implementing it. The first mode is a passive mode where the plugin
628 owns, creates and destroys the X11 window. The second mode is an active
629 mode where the application handles the X11 window creation and then tell
630 the plugin where it should output video. Let's get a bit deeper in those
634 A plugin drawing video output in a X11 window will need to have that
635 window at one stage or another. Passive mode simply means that no window
636 has been given to the plugin before that stage, so the plugin created the
637 window by itself. In that case the plugin is responsible of destroying
638 that window when it's not needed any more and it has to tell the
639 applications that a window has been created so that the application can
640 use it. This is done using the <classname>have_xwindow_id</classname>
641 signal that can be emitted from the plugin with the
642 <function>gst_x_overlay_got_xwindow_id</function> method.
645 As you probably guessed already active mode just means sending a X11
646 window to the plugin so that video output goes there. This is done using
647 the <function>gst_x_overlay_set_xwindow_id</function> method.
650 It is possible to switch from one mode to another at any moment, so the
651 plugin implementing this interface has to handle all cases. There are only
652 2 methods that plugins writers have to implement and they most probably
655 <programlisting><![CDATA[
657 gst_my_filter_set_xwindow_id (GstXOverlay *overlay, XID xwindow_id)
659 GstMyFilter *my_filter = GST_MY_FILTER (overlay);
661 if (my_filter->window)
662 gst_my_filter_destroy_window (my_filter->window);
664 my_filter->window = xwindow_id;
668 gst_my_filter_get_desired_size (GstXOverlay *overlay,
669 guint *width, guint *height)
671 GstMyFilter *my_filter = GST_MY_FILTER (overlay);
673 *width = my_filter->width;
674 *height = my_filter->height;
678 gst_my_filter_xoverlay_init (GstXOverlayClass *iface)
680 iface->set_xwindow_id = gst_my_filter_set_xwindow_id;
681 iface->get_desired_size = gst_my_filter_get_desired_size;
685 You will also need to use the interface methods to fire signals when
686 needed such as in the pad link function where you will know the video
687 geometry and maybe create the window.
689 <programlisting><![CDATA[
690 static MyFilterWindow *
691 gst_my_filter_window_create (GstMyFilter *my_filter, gint width, gint height)
693 MyFilterWindow *window = g_new (MyFilterWindow, 1);
695 gst_x_overlay_got_xwindow_id (GST_X_OVERLAY (my_filter), window->win);
698 static GstPadLinkReturn
699 gst_my_filter_sink_link (GstPad *pad, const GstCaps *caps)
701 GstMyFilter *my_filter = GST_MY_FILTER (overlay);
705 ret = gst_structure_get_int (structure, "width", &width);
706 ret &= gst_structure_get_int (structure, "height", &height);
707 if (!ret) return GST_PAD_LINK_REFUSED;
709 if (!my_filter->window)
710 my_filter->window = gst_my_filter_create_window (my_filter, width, height);
712 gst_x_overlay_got_desired_size (GST_X_OVERLAY (my_filter),
719 <sect1 id="section-iface-navigation" xreflabel="Navigation Interface">
720 <title>Navigation Interface</title>