| INTERFACES & ELEMENTS |
| --------------------- |
| |
| 1) Introduction |
| =============== |
| Interfaces are descriptions on how to handle an object, without actually |
| implementing the object. This allows for multiple objects to be instantiated |
| based on this interface. Each of them can then be handled equally by an |
| application. |
| Glib, apparently (unchecked), has a way of creating interfaces, probably |
| by means of a class struct without actually defining the object. The object, |
| then, does not define a class and these two add up. Benjamin knows more |
| about interfaces, I didn't study interfaces & glib too deeply, yet. I know |
| them just from Java. |
| Interfaces are cool! It allows for some sort of random element creation |
| without needing to link to the implementation. This is similar to how |
| GStreamer currently handles media plugins. GStreamer itself could be seen |
| as an interface too, in that respect. |
| |
| 2) So why do we need interfaces? |
| ================================ |
| Because GStreamer doesn't handle it all. GStreamer in itself is a media |
| framework for streams of data from one element to the next. There's lots |
| of things that's media-related, but not handled in this description. |
| Several examples will probably clarify this: think of the Xvideo output |
| plugin. We can create an overlay here (Xv-based), and we currently control |
| this X-connection using glib properties. However, what property name is |
| associated with what control? And does it work the same as v4lsrc's |
| overlay image control? |
| The same goes for a mixer, for image control, audio control, and probably |
| a lot more. The general idea is simple: *this needs to be documented*. |
| But properties aren't all - they simply cannot do this all. Some things |
| cannot be described in a simple one-argument property thing. Of course, |
| we could give a pointer to a struct as argument, but that's merely a hack |
| and requires both plugin and app to know the ABI of the struct. This |
| kills the whole idea of making the plugin independent of the app. |
| In short: we want interfaces for this. |
| |
| 3) How to integrate an interface in GStreamer |
| ============================================= |
| Let us start with some starting point: an interface is associated |
| with an element. It is a feature exported by that specific element, |
| not by a pipeline or anything more complex. Pipelines are already |
| handled just fine by GStreamer (or you wouldn't be reading all |
| this). |
| Obviously, a pipeline can be a fallback for an interface. Imagine |
| that we're looking for an audio sink that exposes a mixer, but our |
| fakesink audio output doesn't ("I wonder why"). We could then create |
| a pipeline with the volume element in it to "fake" a mixer. Ideally, |
| the volume element would implement a mixer interface itself. |
| |
| How are we going to do that in programmatic way? We currently use |
| properties. Their huge advantage is that we do not need to care |
| about adding new functions or whatever. Their disadvantage is that |
| they're limited to one argument. Anything more complex requires |
| app/plugin knowledge about the shared data, and that defeats the |
| point of them: to have no dependency on each other. This could be |
| solved partially by using action signals, but that makes the whole |
| picture quite complex (since you use multiple methods for doing one |
| simple thing). Also, they are quite slow compared to functions |
| because of the table lookups. In short: it'd work, but I'm not in |
| facour of it... |
| OK, so an element exposes interfaces. This allows us to think of |
| the idea of embedding interfaces (dynamically, of course) in the |
| GstElement object. Think of an object being able to register an |
| indefinate number of interfaces per object instance, and a client |
| application could then enumerate interfaces and instantiate one. |
| Glib gives us GInterface for this purpose. The disadvantage of |
| this is that it's on a per-class basis, not a per-instance basis. |
| This is a problem in case of elements where it depends on several |
| properties whether it supports an interface or not. This can be |
| solved by simply making one generic virtual function "supported ()" |
| in a generic derived object of GInterface (GstInterface?). |
| |
| GstInterface is then a generic thing that is inherited by specific |
| interfaces (see examples). Obviously, the client will need to know |
| about the ABI/API of this struct, but that'll happen either way. |
| Surely, there needs to binary linkage, but I don't consider that a |
| bad thing. It does improve performance compared to action signals! |
| |
| So an element contains interfaces. But where are these interfaces |
| described? And who creates them? I suggest that we do that just as |
| we handle gstvideo and gstaudio right now (these libs do *nothing* |
| useful currently, so this'd make them a lot more interesting). |
| These interfaces inherit from GstInterface. The functions that |
| are needed, can be provided through a class object. The element is |
| then responsible for storing variables and so on. gstvideo/audio |
| provides wrapper functions for the class functions. That's also how |
| glib suggest us to use GInterfaces. |
| |
| Plugin and application then handle and retrieve interfaces as |
| documented in the glib documentation, which is available at: |
| http://www.gnome.org/~mathieu/gobject/main.html |
| |
| So the most important part left is to document the interfaces |
| and make sure all elements exporting them work equally. For this, |
| I'll give two examples. |
| |
| 4) Examples |
| =========== |
| |
| /* This small extra virtual function is here to provide an |
| * interface functionality on a per-instance basis rather |
| * than a per-class basis, which is the case for glib. |
| */ |
| typedef struct _GstInterfaceClass { |
| GTypeInterface parent; |
| |
| /* virtual functions */ |
| gboolean (* supported) (GstInterface *iface); |
| } GstInterfaceClass; |
| |
| There would probably be a convenience function that checks |
| a specific interface's implementation (glib allows for this) |
| and checks for ->supported () to be set and to return TRUE: |
| |
| gboolean |
| gst_element_implements_interface (GstElement *element, |
| GType iface_type) |
| { |
| if (G_TYPE_CHECK_INSTANCE_TYPE (G_OBJECT (element), |
| type)) { |
| GstInterface *iface; |
| GstInterfaceClass *ifclass; |
| |
| iface = G_TYPE_CHECK_INSTANCE_CAST (G_OBJECT (element), |
| type, GstInterface) |
| ifclass = GST_INTERFACE_GET_CLASS (iface); |
| |
| if (ifclass->supported != NULL && |
| ifclass->supported (iface) == TRUE) { |
| return TRUE; |
| } |
| } |
| |
| return FALSE; |
| } |
| |
| Let's now add some functions so we can abuse this in case/check |
| functions. |
| |
| GstInterface * |
| gst_interface_cast (gpointer from, |
| GType type) |
| { |
| GstInterface *iface; |
| |
| /* check cast, give warning+fail if it's invalid */ |
| if (!(iface = G_TYPE_CHECK_INSTANCE_CAST (G_OBJECT (element), |
| type, GstInterface))) { |
| return NULL; |
| } |
| |
| /* if we're an element, take care that this interface |
| * is actually implemented */ |
| if (GST_IS_ELEMENT (from)) { |
| gboolean interface_is_implemented = |
| gst_element_implements_interface (GST_ELEMENT (from), |
| type); |
| g_return_val_if_fail (interface_is_implemented == TRUE, NULL); |
| } |
| |
| return iface; |
| } |
| |
| gboolean |
| gst_interface_check (gpointer from, |
| GType type) |
| { |
| GstInterface *iface; |
| |
| /* check cast, return FALSE if it fails, don't give a warning... */ |
| if (!G_TYPE_CHECK_INSTANCE_CAST (from, type, |
| GstInterface)) { |
| return FALSE; |
| } |
| |
| iface = G_TYPE_CHECK_INSTANCE_CAST (G_OBJECT (element), |
| type, GstInterface); |
| |
| /* now, if we're an element (or derivative), is this thing |
| * actually implemented for real? */ |
| if (GST_IS_ELEMENT (from)) { |
| if (!gst_element_implements_interface (GST_ELEMENT (from), |
| type)) { |
| return FALSE; |
| } |
| } |
| |
| return TRUE; |
| } |
| |
| #define GST_INTERFACE_CHECK_INSTANCE_CAST(obj, type, cast_t) \ |
| ((cast_t *) gst_interface_cast ((obj), (type)) |
| #define GST_INTERFACE_CHECK_INSTANCE_TYPE(obj, type) \ |
| (gst_interface_check ((obj), (type)) |
| |
| We could use this in the GST_IS_... () macros. For example, the |
| macros GST_IS_MIXER () and GST_MIXER () would then look like this: |
| |
| /* Note that this is a non-standard macro, and with a reason! */ |
| #define GST_MIXER(obj) \ |
| (GST_INTERFACE_CHECK_INSTANCE_CAST ((obj), \ |
| GST_TYPE_MIXER, |
| GstMixer)) |
| #define GST_IS_MIXER(obj) \ |
| (GST_INTERFACE_CHECK_INSTANCE_TYPE ((obj), \ |
| GST_TYPE_MIXER)) |
| |
| So the application would just tread it with the known macro, and |
| everything would look extremely simple to the end user. |
| |
| 4a) mixer |
| --------- |
| A mixer is a way of controlling volume and input/output channels. |
| This doesn't mean that you control which channel is the subwoofer, |
| all that is supposed to be done automatically. It is really meant |
| as a way of representing system-level volumes and such. It could |
| also be used to turn on/off certain outputs or inputs. |
| As you've noticed, I'm not only talking about output, but also |
| input. Indeed, I want both osssrc *and* osssink to export the |
| same mixer interface! Or at least a very similar one. Volume |
| control works the same for both. You could say that osssrc should |
| enumerate the input channels (such as microphone, line-in). Of |
| course, osssink should not. Or maybe it should, not sure... Maybe, |
| we'd need a parent osselement which implements all mixer channels. |
| And alsa* would surely implement the same interface. |
| |
| /* This is confusing naming... (i.e. FIXME) |
| * A channel is referred to both as the number of simultaneous |
| * sound streams the input can handle as well as the in-/output |
| * itself |
| */ |
| |
| #define GST_MIXER_CHANNEL_INPUT (1<<0) |
| #define GST_MIXER_CHANNEL_OUTPUT (1<<1) |
| #define GST_MIXER_CHANNEL_MUTE (1<<2) |
| #define GST_MIXER_CHANNEL_RECORD (1<<3) |
| |
| typedef struct _GstMixerChannel { |
| gchar *label; |
| gint current_num_channels, |
| max_num_channels, |
| flags; |
| } GstMixerChannel; |
| |
| typedef struct _GstMixerClass { |
| GTypeInterface klass; |
| |
| /* virtual functions */ |
| GList * (* list_channels) (GstMixer *mixer); |
| |
| void (* set_volume) (GstMixer *mixer, |
| GstMixerChannel *channel, |
| gint *volumes); |
| void (* get_volume) (GstMixer *mixer, |
| GstMixerChannel *channel, |
| gint *volumes); |
| |
| void (* set_mute) (GstMixer *mixer, |
| GstMixerChannel *channel, |
| gboolean mute); |
| void (* set_record) (GstMixer *mixer, |
| GstMixerChannel *channel, |
| gboolean record); |
| } GstMixerClass; |
| |
| libgstmixer.la/so provides wrapper functions for each of the |
| class' virtual functions. Possibly also some macros for |
| GST_MIXER_CHANNEL_HAS_FLAG () or _get_channel (). |
| |
| The rest is done automatically, as described in the already- |
| mentioned glib documentation for GInterface. This includes |
| things like the base_init () function of the GstMixerClass, |
| which fills all the virtual functions for the mixer, and the |
| actual function implementations. The mixer, basically, operates |
| as an element on its own. It gets the file descriptor from |
| the interface->element (every oss... is a osscommon, etc.). |
| |
| 4b) overlay |
| ----------- |
| Overlay is used in both in- and output, too. Think of v4lsrc, |
| v4l2src, v4lmjpegsrc, xvideosink - all overlays. But where do |
| we position the overlay window? Control of this can be done at |
| various levels: locational control (over the server, asynchronous) |
| or XID control (but that makes you depend on X and limits the |
| ability to broaden it over to non-X elements such as fbsink). |
| |
| However, simplicity *is* an issue here. Do we really care about |
| overlay? In the end, users will have to link against either FB |
| or X anyway, so we might want to create separate interfaces for |
| both. On the other hand, we want to be general too... This is a |
| decision that we need to make as early as possible in this process. |
| For now, I propose making X- and FB-based interfaces. |
| |
| Let's assume that we take X as a basis. Then, overlay becomes as |
| simple as one function. Possible extendible by providing inputs |
| (like in the mixer) and norms, although that only applies to |
| input-to-analog, not to-digital... Others simply return NULL. |
| |
| typedef struct _GstOverlayClass { |
| GTypeInterface klass; |
| |
| /* virtual functions */ |
| void (* set_xwindowid) (GstOverlay *overlay, |
| XID xid); |
| } GstOverlayClass; |
| |
| That's all! It would look similar for FB & co. |
| |
| 4c) user input |
| -------------- |
| And yes, user input could be an interface too. Even better, it |
| should definitely be. And wasn't this one of our key issues for |
| 0.8.0? |
| |
| No code here. Go implement it, lazy ass! |
| |
| General ways of thinking: input can come from a plugin, or from |
| the application (we don't have modules for joystick input et all). |
| However, plugins handling input (such as dvdsrc) need to be able |
| to handle each. So we get both input-to-application as well as |
| input-from-application APIs. |
| |
| 5) Status of this document |
| ========================== |
| The interfaces are implemented, more (for metadata, framebuffer- |
| overlay, video balancing (brightness), user input etc. are all |
| pending. |
| |
| 6) Copyright and blabla |
| ======================= |
| (c) Ronald Bultje, 2003 <rbultje@ronald.bitfreak.net> under the |
| terms of the GNU Free Documentation License. See http://www.gnu.org/ |
| for details. |
| |
| And no, I'm not for hire. ;). |