<chapter id="chapter-advanced-interfaces">
  <title>Interfaces</title>
  <para>
    Previously, in the chapter <xref linkend="chapter-building-args"/>, we have
    introduced the concept of GObject properties of controlling an element's
    behaviour. This is very powerful, but it has two big disadvantages:
    first of all, it is too generic, and second, it isn't dynamic.
  </para>
  <para>
    The first disadvantage is related to the customizability of the end-user
    interface that will be built to control the element. Some properties are
    more important than others. Some integer properties are better shown in a
    spin-button widget, whereas others would be better represented by a slider
    widget. Such things are not possible because the UI has no actual meaning
    in the application. A UI widget that represents a bitrate property is the
    same as a UI widget that represents the size of a video, as long as both
    are of the same <classname>GParamSpec</classname> type. Another problem,
    is that things like parameter grouping, function grouping, or parameter
    coupling are not
    really possible.
  </para>
  <para>
    The second problem with parameters are that they are not dynamic. In
    many cases, the allowed values for a property are not fixed, but depend
    on things that can only be detected at runtime. The names of inputs for
    a TV card in a video4linux source element, for example, can only be
    retrieved from the kernel driver when we've opened the device; this only
    happens when the element goes into the READY state. This means that we
    cannot create an enum property type to show this to the user.
  </para>
  <para>
    The solution to those problems is to create very specialized types of
    controls for certain often-used controls. We use the concept of interfaces
    to achieve this. The basis of this all is the glib
    <classname>GTypeInterface</classname> type. For each case where we think
    it's useful, we've created interfaces which can be implemented by elements
    at their own will. 
  </para>
  <para>
    One important note: interfaces do <emphasis>not</emphasis> replace
    properties. Rather, interfaces should be built <emphasis>next to</emphasis>
    properties. There are two important reasons for this. First of all, 
    properties can be more easily introspected. Second, properties can be
    specified on the commandline (<filename>gst-launch</filename>).
  </para>

  <sect1 id="section-iface-general" xreflabel="How to Implement Interfaces">
    <title>How to Implement Interfaces</title>
    <para>
      Implementing interfaces is initiated in the <function>_get_type ()</function>
      of your element. You can register one or more interfaces after having
      registered the type itself. Some interfaces have dependencies on other
      interfaces or can only be registered by certain types of elements. You
      will be notified of doing that wrongly when using the element: it will
      quit with failed assertions, which will explain what went wrong.
      If it does, you need to register support for <emphasis>that</emphasis>
      interface before registering support for the interface that you're
      wanting to support. The example below explains how to add support for a
      simple interface with no further dependencies.
    </para>
    <programlisting>
static void	gst_my_filter_some_interface_init	(GstSomeInterface *iface);

GType
gst_my_filter_get_type (void)
{
  static GType my_filter_type = 0;
                                                                                
  if (!my_filter_type) {
    static const GTypeInfo my_filter_info = {
      sizeof (GstMyFilterClass),
      NULL,
      NULL,
      (GClassInitFunc) gst_my_filter_class_init,
      NULL,
      NULL,
      sizeof (GstMyFilter),
      0,
      (GInstanceInitFunc) gst_my_filter_init
    };
    static const GInterfaceInfo some_interface_info = {
      (GInterfaceInitFunc) gst_my_filter_some_interface_init,
      NULL,
      NULL
    };

    my_filter_type =
	g_type_register_static (GST_TYPE_ELEMENT,
				"GstMyFilter",
				&amp;my_filter_info, 0);
    g_type_add_interface_static (my_filter_type,
				 GST_TYPE_SOME_INTERFACE,
                                 &amp;some_interface_info);
  }

  return my_filter_type;
}

static void
gst_my_filter_some_interface_init (GstSomeInterface *iface)
{
  /* here, you would set virtual function pointers in the interface */
}
    </programlisting>
    <para>
      Or more conveniently:
    </para>
    <programlisting>
static void	gst_my_filter_some_interface_init	(GstSomeInterface *iface);

G_DEFINE_TYPE_WITH_CODE (GstMyFilter, gst_my_filter,GST_TYPE_ELEMENT,
     G_IMPLEMENT_INTERFACE (GST_TYPE_SOME_INTERFACE,
            gst_my_filter_some_interface_init));

    </programlisting>
  </sect1>

  <sect1 id="section-iface-uri" xreflabel="URI interface">
    <title>URI interface</title>
    <para>
      WRITEME
    </para>
  </sect1>

  <sect1 id="section-iface-colorbalance" xreflabel="Color Balance Interface">
    <title>Color Balance Interface</title>
    <para>
      WRITEME
    </para>
  </sect1>

  <sect1 id="section-iface-xoverlay" xreflabel="Video Overlay Interface">
    <title>Video Overlay Interface</title>
    <para>
      The #GstVideoOverlay interface is used for 2 main purposes :
      <itemizedlist>
        <listitem>
          <para>
      To get a grab on the Window where the video sink element is going to render.
      This is achieved by either being informed about the Window identifier that
      the video sink element generated, or by forcing the video sink element to use
      a specific Window identifier for rendering.
          </para>
        </listitem>
        <listitem>
          <para>
      To force a redrawing of the latest video frame the video sink element
      displayed on the Window. Indeed if the #GstPipeline is in #GST_STATE_PAUSED
      state, moving the Window around will damage its content. Application
      developers will want to handle the Expose events themselves and force the
      video sink element to refresh the Window's content.
          </para>
        </listitem>
      </itemizedlist>
    </para>
    <para>
      A plugin drawing video output in a video window will need to have that
      window at one stage or another. Passive mode simply means that no window
      has been given to the plugin before that stage, so the plugin created the
      window by itself. In that case the plugin is responsible of destroying
      that window when it's not needed any more and it has to tell the
      applications that a window has been created so that the application can
      use it. This is done using the <classname>have-window-handle</classname>
      message that can be posted from the plugin with the
      <function>gst_video_overlay_got_window_handle</function> method.
    </para>
    <para>
      As you probably guessed already active mode just means sending a video
      window to the plugin so that video output goes there. This is done using
      the <function>gst_video_overlay_set_window_handle</function> method.
    </para>
    <para>
      It is possible to switch from one mode to another at any moment, so the
      plugin implementing this interface has to handle all cases. There are only
      2 methods that plugins writers have to implement and they most probably
      look like that :
    </para>
    <programlisting><![CDATA[
static void
gst_my_filter_set_window_handle (GstVideoOverlay *overlay, guintptr handle)
{
  GstMyFilter *my_filter = GST_MY_FILTER (overlay);

  if (my_filter->window)
    gst_my_filter_destroy_window (my_filter->window);
    
  my_filter->window = handle;
}

static void
gst_my_filter_xoverlay_init (GstVideoOverlayClass *iface)
{
  iface->set_window_handle = gst_my_filter_set_window_handle;
}
    ]]></programlisting>
    <para>
      You will also need to use the interface methods to post messages when 
      needed such as when receiving a CAPS event where you will know the video
      geometry and maybe create the window.
    </para>
    <programlisting><![CDATA[
static MyFilterWindow *
gst_my_filter_window_create (GstMyFilter *my_filter, gint width, gint height)
{
  MyFilterWindow *window = g_new (MyFilterWindow, 1);
  ...
  gst_video_overlay_got_window_handle (GST_VIDEO_OVERLAY (my_filter), window->win);
}

/* called from the event handler for CAPS events */
static gboolean
gst_my_filter_sink_set_caps (GstMyFilter *my_filter, GstCaps *caps)
{
  gint width, height;
  gboolean ret;
  ...
  ret = gst_structure_get_int (structure, "width", &width);
  ret &= gst_structure_get_int (structure, "height", &height);
  if (!ret) return FALSE;

  gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (my_filter));
  
  if (!my_filter->window)
    my_filter->window = gst_my_filter_create_window (my_filter, width, height);

  ...
}
    ]]></programlisting>
  </sect1>

  <sect1 id="section-iface-navigation" xreflabel="Navigation Interface">
    <title>Navigation Interface</title>
    <para>
      WRITEME
    </para>
  </sect1>
</chapter>
