mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-24 09:10:36 +00:00
Add GInterface
Original commit message from CVS: Add GInterface
This commit is contained in:
parent
b79680d0b2
commit
8ff69a6cc8
1 changed files with 49 additions and 62 deletions
|
@ -47,7 +47,7 @@ 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
|
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
|
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,
|
a pipeline with the volume element in it to "fake" a mixer. Ideally,
|
||||||
the volume element would implement a mixer itself.
|
the volume element would implement a mixer interface itself.
|
||||||
|
|
||||||
How are we going to do that in programmatic way? We currently use
|
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
|
properties. Their huge advantage is that we do not need to care
|
||||||
|
@ -65,16 +65,12 @@ the idea of embedding interfaces (dynamically, of course) in the
|
||||||
GstElement object. Think of an object being able to register an
|
GstElement object. Think of an object being able to register an
|
||||||
indefinate number of interfaces per object instance, and a client
|
indefinate number of interfaces per object instance, and a client
|
||||||
application could then enumerate interfaces and instantiate one.
|
application could then enumerate interfaces and instantiate one.
|
||||||
The API would then look like this:
|
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.
|
||||||
void gst_element_register_interface (GstElement *element,
|
This is a problem in case of elements where it depends on several
|
||||||
const gchar *name,
|
properties whether it supports an interface or not. This can be
|
||||||
GstInterfaceFunc func);
|
solved by simply making one generic virtual function "supported ()"
|
||||||
|
in a generic derived object of GInterface (GstInterface?).
|
||||||
const GList *gst_element_list_interfaces (GstElement *element);
|
|
||||||
|
|
||||||
GstInterface *gst_element_get_interface (GstElement *element,
|
|
||||||
const gchar *name);
|
|
||||||
|
|
||||||
GstInterface is then a generic thing that is inherited by specific
|
GstInterface is then a generic thing that is inherited by specific
|
||||||
interfaces (see examples). Obviously, the client will need to know
|
interfaces (see examples). Obviously, the client will need to know
|
||||||
|
@ -89,19 +85,12 @@ useful currently, so this'd make them a lot more interesting).
|
||||||
These interfaces inherit from GstInterface. The functions that
|
These interfaces inherit from GstInterface. The functions that
|
||||||
are needed, can be provided through a class object. The element is
|
are needed, can be provided through a class object. The element is
|
||||||
then responsible for storing variables and so on. gstvideo/audio
|
then responsible for storing variables and so on. gstvideo/audio
|
||||||
provides wrapper functions for the class functions.
|
provides wrapper functions for the class functions. That's also how
|
||||||
|
glib suggest us to use GInterfaces.
|
||||||
|
|
||||||
For the plugin, it's then as simple as can be. The class_init
|
Plugin and application then handle and retrieve interfaces as
|
||||||
function sets the virtual functions in the interface class object,
|
documented in the glib documentation, which is available at:
|
||||||
and the instance_init function registers the object per created
|
http://www.gnome.org/~mathieu/gobject/main.html
|
||||||
element. The get_interface() handler refs this interface and
|
|
||||||
returns it. The application unrefs it when it's done. The
|
|
||||||
appropriate functions will be called by the application when it
|
|
||||||
thinks it needs to. Perfectly simple!
|
|
||||||
|
|
||||||
For applictions, it's even simpler. Request an interface and use
|
|
||||||
it as documented. When you're done, unref it. It's just like
|
|
||||||
elements: simple!
|
|
||||||
|
|
||||||
So the most important part left is to document the interfaces
|
So the most important part left is to document the interfaces
|
||||||
and make sure all elements exporting them work equally. For this,
|
and make sure all elements exporting them work equally. For this,
|
||||||
|
@ -111,13 +100,41 @@ I'll give two examples.
|
||||||
===========
|
===========
|
||||||
|
|
||||||
typedef struct _GstInterface {
|
typedef struct _GstInterface {
|
||||||
GObject object;
|
/* dummy */
|
||||||
} GstInterface;
|
} GstInterface;
|
||||||
|
|
||||||
typedef struct _GstInterfaceClass {
|
typedef struct _GstInterfaceClass {
|
||||||
GObjectClass klass;
|
GTypeInterface parent;
|
||||||
|
|
||||||
|
gboolean (* supported) (GstInterface *iface);
|
||||||
} GstInterfaceClass;
|
} 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;
|
||||||
|
}
|
||||||
|
|
||||||
4a) mixer
|
4a) mixer
|
||||||
---------
|
---------
|
||||||
A mixer is a way of controlling volume and input/output channels.
|
A mixer is a way of controlling volume and input/output channels.
|
||||||
|
@ -186,50 +203,20 @@ typedef struct _GstOssMixerClass {
|
||||||
|
|
||||||
[..]
|
[..]
|
||||||
|
|
||||||
static void
|
|
||||||
gst_ossmixer_class_init (GstOssMixerClass *klass)
|
|
||||||
{
|
|
||||||
GstMixerClass *mix_klass = (GstMixerClass *) klass;
|
|
||||||
|
|
||||||
[.. set virtual functions to their oss/mixer counterparts here ..]
|
|
||||||
}
|
|
||||||
|
|
||||||
[..]
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_osssrc_init (GstOssSrc *osssrc)
|
gst_osssrc_init (GstOssSrc *osssrc)
|
||||||
{
|
{
|
||||||
|
GstOssMixer *mixer = GST_OSS_MIXER (osssrc);
|
||||||
[..]
|
[..]
|
||||||
gst_element_register_interface (GST_ELEMENT (osssrc),
|
mixer->element = GST_ELEMENT (osssrc);
|
||||||
"mixer",
|
|
||||||
gst_osssrc_get_interface);
|
|
||||||
[..]
|
[..]
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstInterface *
|
The rest is done automatically, as described in the already-
|
||||||
gst_osssrc_get_interface (GstElement *element,
|
mentioned glib documentation for GInterface.
|
||||||
const gchar *name)
|
|
||||||
{
|
|
||||||
GstOssMixer *mixer;
|
|
||||||
|
|
||||||
g_assert (strcmp (name, "mixer") == 0);
|
We could add a pointer to the file descriptor in the
|
||||||
|
osssrc/osssink, too, and we'd have full access to the device.
|
||||||
mixer = g_object_new (GST_TYPE_OSS_MIXER, NULL);
|
|
||||||
mixer->element = element;
|
|
||||||
[..]
|
|
||||||
|
|
||||||
return (GstInterface *) mixer;
|
|
||||||
}
|
|
||||||
|
|
||||||
And yes, that's quite a piece of code, but you didn't expect
|
|
||||||
that we could make a mixer in five lines of code, did you?
|
|
||||||
However, applications now *can*!
|
|
||||||
|
|
||||||
There might be some refcounting issues here: get_interface ()
|
|
||||||
should ref () the element, and we should set a mixer dispose
|
|
||||||
handler to unref () it again. Then, too, we could add a pointer
|
|
||||||
to the file descriptor in the osssrc/osssink, too, and we'd
|
|
||||||
have full access to the device.
|
|
||||||
However, that's implementation. Let's first worry about general
|
However, that's implementation. Let's first worry about general
|
||||||
design.
|
design.
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue