Merge branch 'master' into 0.11
authorSebastian Dröge <sebastian.droege@collabora.co.uk>
Fri, 2 Mar 2012 09:00:55 +0000 (10:00 +0100)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Fri, 2 Mar 2012 09:00:55 +0000 (10:00 +0100)
Conflicts:
NEWS
RELEASE
configure.ac
docs/plugins/gst-plugins-base-plugins.args
docs/plugins/gst-plugins-base-plugins.hierarchy
docs/plugins/gst-plugins-base-plugins.interfaces
docs/plugins/inspect/plugin-adder.xml
docs/plugins/inspect/plugin-alsa.xml
docs/plugins/inspect/plugin-app.xml
docs/plugins/inspect/plugin-audioconvert.xml
docs/plugins/inspect/plugin-audiorate.xml
docs/plugins/inspect/plugin-audioresample.xml
docs/plugins/inspect/plugin-audiotestsrc.xml
docs/plugins/inspect/plugin-cdparanoia.xml
docs/plugins/inspect/plugin-encoding.xml
docs/plugins/inspect/plugin-ffmpegcolorspace.xml
docs/plugins/inspect/plugin-gdp.xml
docs/plugins/inspect/plugin-gio.xml
docs/plugins/inspect/plugin-gnomevfs.xml
docs/plugins/inspect/plugin-libvisual.xml
docs/plugins/inspect/plugin-ogg.xml
docs/plugins/inspect/plugin-pango.xml
docs/plugins/inspect/plugin-playback.xml
docs/plugins/inspect/plugin-subparse.xml
docs/plugins/inspect/plugin-tcp.xml
docs/plugins/inspect/plugin-theora.xml
docs/plugins/inspect/plugin-typefindfunctions.xml
docs/plugins/inspect/plugin-uridecodebin.xml
docs/plugins/inspect/plugin-videorate.xml
docs/plugins/inspect/plugin-videoscale.xml
docs/plugins/inspect/plugin-videotestsrc.xml
docs/plugins/inspect/plugin-volume.xml
docs/plugins/inspect/plugin-vorbis.xml
docs/plugins/inspect/plugin-ximagesink.xml
docs/plugins/inspect/plugin-xvimagesink.xml
gst-libs/gst/app/gstappsink.c
gst-libs/gst/audio/mixer.c
gst-libs/gst/audio/mixer.h
gst-libs/gst/tag/gstxmptag.c
gst-libs/gst/video/colorbalance.c
gst-libs/gst/video/colorbalance.h
gst/adder/gstadder.c
gst/playback/gstplaybasebin.c
gst/playback/gstplaybin2.c
gst/playback/gstplaysink.c
gst/videoscale/gstvideoscale.c
tests/check/elements/videoscale.c
tests/examples/seek/seek.c
tests/examples/v4l/probe.c
win32/common/_stdint.h
win32/common/audio-enumtypes.c
win32/common/config.h

25 files changed:
1  2 
ext/alsa/gstalsadeviceprobe.c
ext/theora/gsttheoraenc.c
ext/theora/gsttheoraparse.c
gst-libs/gst/app/gstappsink.c
gst-libs/gst/audio/mixer.c
gst-libs/gst/audio/mixer.h
gst-libs/gst/audio/mixerutils.c
gst-libs/gst/interfaces/navigation.h
gst-libs/gst/tag/gstxmptag.c
gst-libs/gst/video/colorbalance.c
gst-libs/gst/video/colorbalance.h
gst/adder/gstadder.c
gst/adder/gstadder.h
gst/playback/gstplay-enum.h
gst/playback/gstplaybin2.c
gst/playback/gstplaysink.c
gst/videoscale/gstvideoscale.c
sys/xvimage/xvimagesink.c
tests/check/elements/adder.c
tests/check/elements/alsa.c
tests/check/elements/playbin.c
tests/check/elements/videoscale.c
tests/examples/seek/seek.c
tests/icles/test-colorkey.c
win32/common/config.h

Simple merge
Simple merge
Simple merge
@@@ -158,12 -158,17 +158,13 @@@ static gboolean gst_app_sink_unlock_sto
  static gboolean gst_app_sink_start (GstBaseSink * psink);
  static gboolean gst_app_sink_stop (GstBaseSink * psink);
  static gboolean gst_app_sink_event (GstBaseSink * sink, GstEvent * event);
+ static gboolean gst_app_sink_query (GstBaseSink * bsink, GstQuery * query);
  static GstFlowReturn gst_app_sink_preroll (GstBaseSink * psink,
      GstBuffer * buffer);
 -static GstFlowReturn gst_app_sink_render_common (GstBaseSink * psink,
 -    GstMiniObject * data, gboolean is_list);
  static GstFlowReturn gst_app_sink_render (GstBaseSink * psink,
      GstBuffer * buffer);
 -static GstFlowReturn gst_app_sink_render_list (GstBaseSink * psink,
 -    GstBufferList * list);
 -static GstCaps *gst_app_sink_getcaps (GstBaseSink * psink);
 -static GstMiniObject *gst_app_sink_pull_object (GstAppSink * appsink);
 +static gboolean gst_app_sink_setcaps (GstBaseSink * sink, GstCaps * caps);
 +static GstCaps *gst_app_sink_getcaps (GstBaseSink * psink, GstCaps * filter);
  
  static guint gst_app_sink_signals[LAST_SIGNAL] = { 0 };
  
@@@ -335,11 -435,13 +336,12 @@@ gst_app_sink_class_init (GstAppSinkClas
    basesink_class->event = gst_app_sink_event;
    basesink_class->preroll = gst_app_sink_preroll;
    basesink_class->render = gst_app_sink_render;
 -  basesink_class->render_list = gst_app_sink_render_list;
    basesink_class->get_caps = gst_app_sink_getcaps;
 +  basesink_class->set_caps = gst_app_sink_setcaps;
+   basesink_class->query = gst_app_sink_query;
  
    klass->pull_preroll = gst_app_sink_pull_preroll;
 -  klass->pull_buffer = gst_app_sink_pull_buffer;
 -  klass->pull_buffer_list = gst_app_sink_pull_buffer_list;
 +  klass->pull_sample = gst_app_sink_pull_sample;
  
    g_type_class_add_private (klass, sizeof (GstAppSinkPrivate));
  }
@@@ -774,6 -877,79 +776,30 @@@ gst_app_sink_getcaps (GstBaseSink * psi
    return caps;
  }
  
 -static GstMiniObject *
 -gst_app_sink_pull_object (GstAppSink * appsink)
 -{
 -  GstMiniObject *obj = NULL;
 -  GstAppSinkPrivate *priv;
 -
 -  g_return_val_if_fail (GST_IS_APP_SINK (appsink), NULL);
 -
 -  priv = appsink->priv;
 -
 -  g_mutex_lock (priv->mutex);
 -
 -  while (TRUE) {
 -    GST_DEBUG_OBJECT (appsink, "trying to grab a buffer/list");
 -    if (!priv->started)
 -      goto not_started;
 -
 -    if (!g_queue_is_empty (priv->queue))
 -      break;
 -
 -    if (priv->is_eos)
 -      goto eos;
 -
 -    /* nothing to return, wait */
 -    GST_DEBUG_OBJECT (appsink, "waiting for a buffer/list");
 -    g_cond_wait (priv->cond, priv->mutex);
 -  }
 -  obj = g_queue_pop_head (priv->queue);
 -  GST_DEBUG_OBJECT (appsink, "we have a buffer/list %p", obj);
 -  g_cond_signal (priv->cond);
 -  g_mutex_unlock (priv->mutex);
 -
 -  return obj;
 -
 -  /* special conditions */
 -eos:
 -  {
 -    GST_DEBUG_OBJECT (appsink, "we are EOS, return NULL");
 -    g_mutex_unlock (priv->mutex);
 -    return NULL;
 -  }
 -not_started:
 -  {
 -    GST_DEBUG_OBJECT (appsink, "we are stopped, return NULL");
 -    g_mutex_unlock (priv->mutex);
 -    return NULL;
 -  }
 -}
 -
+ static gboolean
+ gst_app_sink_query (GstBaseSink * bsink, GstQuery * query)
+ {
+   gboolean ret;
+   switch (GST_QUERY_TYPE (query)) {
+     case GST_QUERY_SEEKING:{
+       GstFormat fmt;
+       /* we don't supporting seeking */
+       gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
+       gst_query_set_seeking (query, fmt, FALSE, 0, -1);
+       ret = TRUE;
+       break;
+     }
+     default:
+       ret = GST_BASE_SINK_CLASS (parent_class)->query (bsink, query);
+       break;
+   }
+   return ret;
+ }
  /* external API */
  
  /**
@@@ -81,18 -94,58 +81,17 @@@ gst_mixer_get_type (void
  }
  
  static void
 -gst_mixer_class_init (GstMixerClass * klass)
 +gst_mixer_class_init (GstMixerInterface * iface)
  {
-   iface->mixer_type = GST_MIXER_SOFTWARE;
 -#ifndef GST_DISABLE_DEPRECATED
 -  static gboolean initialized = FALSE;
 -
 -  /* signals (deprecated) */
 -  if (!initialized) {
 -    gst_mixer_signals[SIGNAL_RECORD_TOGGLED] =
 -        g_signal_new ("record-toggled",
 -        GST_TYPE_MIXER, G_SIGNAL_RUN_LAST,
 -        G_STRUCT_OFFSET (GstMixerClass, record_toggled),
 -        NULL, NULL,
 -        gst_interfaces_marshal_VOID__OBJECT_BOOLEAN, G_TYPE_NONE, 2,
 -        GST_TYPE_MIXER_TRACK, G_TYPE_BOOLEAN);
 -    gst_mixer_signals[SIGNAL_MUTE_TOGGLED] =
 -        g_signal_new ("mute-toggled",
 -        GST_TYPE_MIXER, G_SIGNAL_RUN_LAST,
 -        G_STRUCT_OFFSET (GstMixerClass, mute_toggled),
 -        NULL, NULL,
 -        gst_interfaces_marshal_VOID__OBJECT_BOOLEAN, G_TYPE_NONE, 2,
 -        GST_TYPE_MIXER_TRACK, G_TYPE_BOOLEAN);
 -    gst_mixer_signals[SIGNAL_VOLUME_CHANGED] =
 -        g_signal_new ("volume-changed",
 -        GST_TYPE_MIXER, G_SIGNAL_RUN_LAST,
 -        G_STRUCT_OFFSET (GstMixerClass, volume_changed),
 -        NULL, NULL,
 -        gst_interfaces_marshal_VOID__OBJECT_POINTER, G_TYPE_NONE, 2,
 -        GST_TYPE_MIXER_TRACK, G_TYPE_POINTER);
 -    gst_mixer_signals[SIGNAL_OPTION_CHANGED] =
 -        g_signal_new ("option-changed",
 -        GST_TYPE_MIXER, G_SIGNAL_RUN_LAST,
 -        G_STRUCT_OFFSET (GstMixerClass, option_changed),
 -        NULL, NULL,
 -        gst_interfaces_marshal_VOID__OBJECT_STRING, G_TYPE_NONE, 2,
 -        GST_TYPE_MIXER_OPTIONS, G_TYPE_STRING);
 -
 -    initialized = TRUE;
 -  }
 -#endif
 -
 -#ifndef GST_REMOVE_DEPRECATED
 -  klass->mixer_type = GST_MIXER_SOFTWARE;
 -#endif
--
    /* default virtual functions */
 -  klass->list_tracks = NULL;
 -  klass->set_volume = NULL;
 -  klass->get_volume = NULL;
 -  klass->set_mute = NULL;
 -  klass->set_record = NULL;
 -  klass->set_option = NULL;
 -  klass->get_option = NULL;
++  iface->get_mixer_type = NULL;
 +  iface->list_tracks = NULL;
 +  iface->set_volume = NULL;
 +  iface->get_volume = NULL;
 +  iface->set_mute = NULL;
 +  iface->set_record = NULL;
 +  iface->set_option = NULL;
 +  iface->get_option = NULL;
  }
  
  /**
@@@ -302,9 -355,16 +301,10 @@@ gst_mixer_get_option (GstMixer * mixer
  GstMixerType
  gst_mixer_get_mixer_type (GstMixer * mixer)
  {
 -  GstMixerClass *klass = GST_MIXER_GET_CLASS (mixer);
 +  GstMixerInterface *iface = GST_MIXER_GET_INTERFACE (mixer);
  
-   return iface->mixer_type;
 -  if (klass->get_mixer_type)
 -    return klass->get_mixer_type (mixer);
 -
 -#ifndef GST_REMOVE_DEPRECATED
 -  return klass->mixer_type;
 -#else
 -  g_return_if_reached (GST_MIXER_TYPE_SOFTWARE);
 -#endif
++  g_return_val_if_fail (iface->get_mixer_type != NULL, GST_MIXER_SOFTWARE);
++  return iface->get_mixer_type (mixer);
  }
  
  /**
@@@ -31,16 -32,20 +31,14 @@@ G_BEGIN_DECL
  #define GST_TYPE_MIXER \
    (gst_mixer_get_type ())
  #define GST_MIXER(obj) \
 -  (GST_IMPLEMENTS_INTERFACE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MIXER, GstMixer))
 -#define GST_MIXER_CLASS(klass) \
 -  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_MIXER, GstMixerClass))
 +  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MIXER, GstMixer))
  #define GST_IS_MIXER(obj) \
 -  (GST_IMPLEMENTS_INTERFACE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MIXER))
 -#define GST_IS_MIXER_CLASS(klass) \
 -  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MIXER))
 -#define GST_MIXER_GET_CLASS(inst) \
 -  (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_MIXER, GstMixerClass))
 -
 -#define GST_MIXER_TYPE(klass) (klass->mixer_type)
 +  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MIXER))
 +#define GST_MIXER_GET_INTERFACE(inst) \
 +  (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_MIXER, GstMixerInterface))
  
- #define GST_MIXER_TYPE(iface) (iface->mixer_type)
  typedef struct _GstMixer GstMixer;
 -typedef struct _GstMixerClass GstMixerClass;
 +typedef struct _GstMixerInterface GstMixerInterface;
  
  /**
   * GstMixerType:
@@@ -109,11 -114,14 +107,9 @@@ typedef enu
    GST_MIXER_FLAG_GROUPING            = (1<<2),
  } GstMixerFlags;
  
 -struct _GstMixerClass {
 -  GTypeInterface klass;
 -
 -/* FIXME 0.11: Remove this */
 -#ifndef GST_REMOVE_DEPRECATED
 -  GstMixerType mixer_type;
 -#endif
 +struct _GstMixerInterface {
 +  GTypeInterface iface;
  
-   GstMixerType mixer_type;
    /* virtual functions */
    const GList *  (* list_tracks)   (GstMixer      *mixer);
  
    void           (* set_record)    (GstMixer      *mixer,
                                      GstMixerTrack *track,
                                      gboolean       record);
 -#ifndef GST_DISABLE_DEPRECATED
 -  /* signals (deprecated) */
 -  void (* mute_toggled)   (GstMixer      *mixer,
 -                           GstMixerTrack *channel,
 -                           gboolean       mute);
 -  void (* record_toggled) (GstMixer      *mixer,
 -                           GstMixerTrack *channel,
 -                           gboolean       record);
 -  void (* volume_changed) (GstMixer      *mixer,
 -                           GstMixerTrack *channel,
 -                           gint          *volumes);
 -#else
 -  gpointer padding1[3];
 -#endif /* not GST_DISABLE_DEPRECATED */
 -
 -  void          (* set_option)     (GstMixer      *mixer,
 +  void           (* set_option)    (GstMixer      *mixer,
                                      GstMixerOptions *opts,
                                      gchar         *value);
 -  const gchar * (* get_option)     (GstMixer      *mixer,
 +  const gchar *  (* get_option)    (GstMixer      *mixer,
                                      GstMixerOptions *opts);
  
 -#ifndef GST_DISABLE_DEPRECATED
 -  void (* option_changed) (GstMixer      *mixer,
 -                           GstMixerOptions *opts,
 -                           gchar   *option);
 -#else
 -  gpointer padding2;
 -#endif /* not GST_DISABLE_DEPRECATED */
 -
    GstMixerFlags (* get_mixer_flags) (GstMixer *mixer);
 -
 -  /*< private >*/
 -  gpointer _gst_reserved[GST_PADDING-2];
+   GstMixerType  (* get_mixer_type)  (GstMixer *mixer);
  };
  
  GType           gst_mixer_get_type      (void);
Simple merge
@@@ -41,13 -41,13 +41,13 @@@ typedef struct _GstNavigationInterface 
  
  /**
   * GstNavigationInterface:
 - * @g_iface: the parent interface
 + * @iface: the parent interface
   * @send_event: sending a navigation event
   *
-  * Color-balance interface.
+  * Navigation interface.
   */
  struct _GstNavigationInterface {
 -  GTypeInterface g_iface;
 +  GTypeInterface iface;
  
    /* virtual functions */
    void (*send_event) (GstNavigation *navigation, GstStructure *structure);
Simple merge
@@@ -105,13 -102,15 +105,12 @@@ gst_color_balance_class_init (GstColorB
  
      initialized = TRUE;
    }
 -#ifndef GST_REMOVE_DEPRECATED
 -  klass->balance_type = GST_COLOR_BALANCE_SOFTWARE;
 -#endif
  
-   iface->balance_type = GST_COLOR_BALANCE_SOFTWARE;
    /* default virtual functions */
 -  klass->list_channels = NULL;
 -  klass->set_value = NULL;
 -  klass->get_value = NULL;
 -  klass->get_balance_type = NULL;
 +  iface->list_channels = NULL;
 +  iface->set_value = NULL;
 +  iface->get_value = NULL;
++  iface->get_balance_type = NULL;
  }
  
  /**
@@@ -213,9 -212,16 +212,12 @@@ gst_color_balance_get_balance_type (Gst
    g_return_val_if_fail (GST_IS_COLOR_BALANCE (balance),
        GST_COLOR_BALANCE_SOFTWARE);
  
 -  klass = GST_COLOR_BALANCE_GET_CLASS (balance);
 +  iface = GST_COLOR_BALANCE_GET_INTERFACE (balance);
  
-   return iface->balance_type;
 -  if (klass->get_balance_type)
 -    return klass->get_balance_type (balance);
++  g_return_val_if_fail (iface->get_balance_type != NULL,
++      GST_COLOR_BALANCE_SOFTWARE);
 -#ifndef GST_REMOVE_DEPRECATED
 -  return klass->balance_type;
 -#else
 -  g_return_val_if_reached (GST_COLOR_BALANCE_SOFTWARE);
 -#endif
++  return iface->get_balance_type (balance);
  }
  
  /**
@@@ -30,16 -31,22 +30,14 @@@ G_BEGIN_DECL
  #define GST_TYPE_COLOR_BALANCE \
    (gst_color_balance_get_type ())
  #define GST_COLOR_BALANCE(obj) \
 -  (GST_IMPLEMENTS_INTERFACE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_COLOR_BALANCE, \
 -                                                 GstColorBalance))
 -#define GST_COLOR_BALANCE_CLASS(klass) \
 -  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_COLOR_BALANCE, \
 -                            GstColorBalanceClass))
 +  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_COLOR_BALANCE, GstColorBalance))
  #define GST_IS_COLOR_BALANCE(obj) \
 -  (GST_IMPLEMENTS_INTERFACE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_COLOR_BALANCE))
 -#define GST_IS_COLOR_BALANCE_CLASS(klass) \
 -  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_COLOR_BALANCE))
 -#define GST_COLOR_BALANCE_GET_CLASS(inst) \
 -  (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_COLOR_BALANCE, GstColorBalanceClass))
 -
 -#define GST_COLOR_BALANCE_TYPE(klass) (klass->balance_type)
 +  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_COLOR_BALANCE))
 +#define GST_COLOR_BALANCE_GET_INTERFACE(inst) \
 +  (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_COLOR_BALANCE, GstColorBalanceInterface))
  
- #define GST_COLOR_BALANCE_TYPE(iface) (iface->balance_type)
  typedef struct _GstColorBalance GstColorBalance;
 -typedef struct _GstColorBalanceClass GstColorBalanceClass;
 +typedef struct _GstColorBalanceInterface GstColorBalanceInterface;
  
  /**
   * GstColorBalanceType:
@@@ -70,11 -77,14 +68,9 @@@ typedef enu
   *
   * Color-balance interface.
   */
 -struct _GstColorBalanceClass {
 -  GTypeInterface klass;
 -
 -/* FIXME 0.11: Remove this */
 -#ifndef GST_REMOVE_DEPRECATED
 -  GstColorBalanceType balance_type;
 -#endif
 +struct _GstColorBalanceInterface {
 +  GTypeInterface iface;
  
-   GstColorBalanceType balance_type;
    /* virtual functions */
    const GList * (* list_channels) (GstColorBalance        *balance);
  
                                     gint                    value);
    gint          (* get_value)     (GstColorBalance        *balance,
                                     GstColorBalanceChannel *channel);
++  GstColorBalanceType (*get_balance_type)  (GstColorBalance *balance);
  
    /* signals */
    void (* value_changed) (GstColorBalance        *balance,
                            GstColorBalanceChannel *channel,
                            gint                    value);
 -  GstColorBalanceType (*get_balance_type)  (GstColorBalance *balance);
 -
+   /*< private >*/
+   gpointer _gst_reserved[GST_PADDING-1];
  };
  
  GType   gst_color_balance_get_type      (void);
@@@ -108,19 -129,14 +108,19 @@@ static void gst_adder_set_property (GOb
  static void gst_adder_get_property (GObject * object, guint prop_id,
      GValue * value, GParamSpec * pspec);
  
 -static gboolean gst_adder_setcaps (GstPad * pad, GstCaps * caps);
 -static gboolean gst_adder_query (GstPad * pad, GstQuery * query);
 -static gboolean gst_adder_src_event (GstPad * pad, GstEvent * event);
 +static gboolean gst_adder_setcaps (GstAdder * adder, GstPad * pad,
 +    GstCaps * caps);
 +static gboolean gst_adder_src_query (GstPad * pad, GstObject * parent,
 +    GstQuery * query);
 +static gboolean gst_adder_sink_query (GstPad * pad, GstObject * parent,
 +    GstQuery * query);
 +static gboolean gst_adder_src_event (GstPad * pad, GstObject * parent,
 +    GstEvent * event);
- static gboolean gst_adder_sink_event (GstPad * pad, GstObject * parent,
-     GstEvent * event);
+ static gboolean gst_adder_sink_event (GstCollectPads2 * pads,
+     GstCollectData2 * pad, GstEvent * event, gpointer user_data);
  
  static GstPad *gst_adder_request_new_pad (GstElement * element,
 -    GstPadTemplate * temp, const gchar * unused);
 +    GstPadTemplate * temp, const gchar * unused, const GstCaps * caps);
  static void gst_adder_release_pad (GstElement * element, GstPad * pad);
  
  static GstStateChangeReturn gst_adder_change_state (GstElement * element,
@@@ -763,67 -746,76 +763,75 @@@ done
  }
  
  static gboolean
- gst_adder_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
+ gst_adder_sink_event (GstCollectPads2 * pads, GstCollectData2 * pad,
+     GstEvent * event, gpointer user_data)
  {
-   GstAdder *adder;
-   gboolean ret = TRUE;
-   adder = GST_ADDER (parent);
+   GstAdder *adder = GST_ADDER (user_data);
+   gboolean res = FALSE;
  
-   GST_DEBUG_OBJECT (pad, "Got %s event on sink pad",
 -  GST_DEBUG_OBJECT (pad->pad, "Got %s event on sink pad from %s",
 -      GST_EVENT_TYPE_NAME (event), GST_OBJECT_NAME (GST_EVENT_SRC (event)));
++  GST_DEBUG_OBJECT (pad->pad, "Got %s event on sink pad",
 +      GST_EVENT_TYPE_NAME (event));
  
    switch (GST_EVENT_TYPE (event)) {
 -    case GST_EVENT_FLUSH_START:
 -      /* drop flush start events, as we forwarded one already when handing the
 -       * flushing seek on the sink pad */
 +    case GST_EVENT_CAPS:
 +    {
 +      GstCaps *caps;
 +
 +      gst_event_parse_caps (event, &caps);
-       ret = gst_adder_setcaps (adder, pad, caps);
++      res = gst_adder_setcaps (adder, pad->pad, caps);
        gst_event_unref (event);
 -      res = TRUE;
 +
-       goto beach;
++      break;
 +    }
++    case GST_EVENT_FLUSH_START:
++      res = gst_pad_event_default (pad->pad, GST_OBJECT (adder), event);
+       break;
      case GST_EVENT_FLUSH_STOP:
-       /* we received a flush-stop. The collect_event function will call the
-        * gst_adder_event function we have set on the GstCollectPads2, so we
-        * have control over whether the event is sent past our element.
-        * We will only forward it when flush_stop_pending is set, and we will
-        * unset it then.
+       /* we received a flush-stop. We will only forward it when
+        * flush_stop_pending is set, and we will unset it then.
         */
-       GST_COLLECT_PADS2_STREAM_LOCK (adder->collect);
-       g_atomic_int_set (&adder->new_segment_pending, TRUE);
+       if (g_atomic_int_compare_and_exchange (&adder->flush_stop_pending,
+               TRUE, FALSE)) {
+         g_atomic_int_set (&adder->new_segment_pending, TRUE);
+         GST_DEBUG_OBJECT (pad->pad, "forwarding flush stop");
+       } else {
+         gst_event_unref (event);
+         res = TRUE;
+         GST_DEBUG_OBJECT (pad->pad, "eating flush stop");
+       }
        /* Clear pending tags */
        if (adder->pending_events) {
          g_list_foreach (adder->pending_events, (GFunc) gst_event_unref, NULL);
          g_list_free (adder->pending_events);
          adder->pending_events = NULL;
        }
-       GST_COLLECT_PADS2_STREAM_UNLOCK (adder->collect);
++      res = gst_pad_event_default (pad->pad, GST_OBJECT (adder), event);
        break;
      case GST_EVENT_TAG:
-       GST_COLLECT_PADS2_STREAM_LOCK (adder->collect);
        /* collect tags here so we can push them out when we collect data */
        adder->pending_events = g_list_append (adder->pending_events, event);
-       GST_COLLECT_PADS2_STREAM_UNLOCK (adder->collect);
-       goto beach;
+       res = TRUE;
+       break;
 -    case GST_EVENT_NEWSEGMENT:
 +    case GST_EVENT_SEGMENT:
        if (g_atomic_int_compare_and_exchange (&adder->wait_for_new_segment,
                TRUE, FALSE)) {
          /* make sure we push a new segment, to inform about new basetime
           * see FIXME in gst_adder_collected() */
          g_atomic_int_set (&adder->new_segment_pending, TRUE);
        }
+       gst_event_unref (event);
+       res = TRUE;
+       break;
++    case GST_EVENT_EOS:
++      gst_event_unref (event);
++      res = TRUE;
 +      break;
      default:
++      res = gst_pad_event_default (pad->pad, GST_OBJECT (adder), event);
        break;
    }
 -  return res;
 -}
 -
 -static void
 -gst_adder_base_init (gpointer g_class)
 -{
 -  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
  
-   /* now GstCollectPads2 can take care of the rest, e.g. EOS */
-   ret = adder->collect_event (pad, parent, event);
- beach:
-   return ret;
 -  gst_element_class_add_static_pad_template (gstelement_class,
 -      &gst_adder_src_template);
 -  gst_element_class_add_static_pad_template (gstelement_class,
 -      &gst_adder_sink_template);
 -  gst_element_class_set_details_simple (gstelement_class, "Adder",
 -      "Generic/Audio",
 -      "Add N audio channels together",
 -      "Thomas Vander Stichele <thomas at apestaart dot org>");
++  return res;
  }
  
  static void
@@@ -989,15 -979,11 +997,9 @@@ gst_adder_request_new_pad (GstElement 
    GST_DEBUG_OBJECT (adder, "request new pad %s", name);
    g_free (name);
  
 -  gst_pad_set_getcaps_function (newpad,
 -      GST_DEBUG_FUNCPTR (gst_adder_sink_getcaps));
 -  gst_pad_set_setcaps_function (newpad, GST_DEBUG_FUNCPTR (gst_adder_setcaps));
 +  gst_pad_set_query_function (newpad, GST_DEBUG_FUNCPTR (gst_adder_sink_query));
    gst_collect_pads2_add_pad (adder->collect, newpad, sizeof (GstCollectData2));
  
-   /* FIXME: hacked way to override/extend the event function of
-    * GstCollectPads2; because it sets its own event function giving the
-    * element no access to events */
-   adder->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (newpad);
-   gst_pad_set_event_function (newpad, GST_DEBUG_FUNCPTR (gst_adder_sink_event));
    /* takes ownership of the pad */
    if (!gst_element_add_pad (GST_ELEMENT (adder), newpad))
      goto could_not_add;
@@@ -1292,32 -1275,7 +1294,6 @@@ eos
    }
  }
  
- static gboolean
- gst_adder_event (GstCollectPads2 * pads, GstCollectData2 * pad,
-     GstEvent * event, gpointer user_data)
- {
-   GstAdder *adder = GST_ADDER (user_data);
-   if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
-     if (g_atomic_int_compare_and_exchange (&adder->flush_stop_pending,
-             TRUE, FALSE)) {
-       return gst_pad_event_default (pad->pad, GST_OBJECT (user_data), event);
-     } else {
-       gst_event_unref (event);
-       return TRUE;
-     }
-   } else {
-     if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT ||
-         GST_EVENT_TYPE (event) == GST_EVENT_CAPS ||
-         GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
-       gst_event_unref (event);
-       return TRUE;
-     } else {
-       return gst_pad_event_default (pad->pad, GST_OBJECT (user_data), event);
-     }
-   }
- }
--
  static GstStateChangeReturn
  gst_adder_change_state (GstElement * element, GstStateChange transition)
  {
@@@ -65,8 -82,11 +65,7 @@@ struct _GstAdder 
    gint64          offset;
  
    /* sink event handling */
--  GstPadEventFunction  collect_event;
    GstSegment      segment;
 -  guint64         segment_start, segment_end;
 -  gdouble         segment_rate;
    volatile gboolean new_segment_pending;
    volatile gboolean wait_for_new_segment;
    /* src event handling */
Simple merge
   * <title>Embedding the video window in your application</title>
   * By default, playbin (or rather the video sinks used) will create their own
   * window. Applications will usually want to force output to a window of their
-- * own, however. This can be done using the #GstXOverlay interface, which most
++ * own, however. This can be done using the #GstVideoOverlay interface, which most
   * video sinks implement. See the documentation there for more details.
   * </refsect2>
   * <refsect2>
  
  #include <gst/gst-i18n-plugin.h>
  #include <gst/pbutils/pbutils.h>
 -#include <gst/interfaces/streamvolume.h>
 -#include <gst/interfaces/xoverlay.h>
 +#include <gst/audio/streamvolume.h>
++#include <gst/video/videooverlay.h>
+ #include <gst/interfaces/navigation.h>
 -#include <gst/interfaces/colorbalance.h>
 -
++#include <gst/video/colorbalance.h>
  #include "gstplay-enum.h"
  #include "gstplay-marshal.h"
  #include "gstplayback.h"
  #include "gstplaysink.h"
  #include "gstsubtitleoverlay.h"
--
  #include "gst/glib-compat-private.h"
--
  GST_DEBUG_CATEGORY_STATIC (gst_play_bin_debug);
  #define GST_CAT_DEFAULT gst_play_bin_debug
  
@@@ -580,6 -583,15 +580,12 @@@ if (id) 
    id = 0;                                \
  }
  
 -static void gst_play_bin_implements_interface_init (gpointer g_iface,
 -    gpointer g_iface_data);
 -static void gst_play_bin_xoverlay_init (gpointer g_iface,
 -    gpointer g_iface_data);
++static void gst_play_bin_overlay_init (gpointer g_iface, gpointer g_iface_data);
+ static void gst_play_bin_navigation_init (gpointer g_iface,
+     gpointer g_iface_data);
+ static void gst_play_bin_colorbalance_init (gpointer g_iface,
+     gpointer g_iface_data);
  static GType
  gst_play_bin_get_type (void)
  {
      static const GInterfaceInfo svol_info = {
        NULL, NULL, NULL
      };
 -    static const GInterfaceInfo xov_info = {
 -      gst_play_bin_xoverlay_init,
++    static const GInterfaceInfo ov_info = {
++      gst_play_bin_overlay_init,
+       NULL, NULL
+     };
+     static const GInterfaceInfo nav_info = {
+       gst_play_bin_navigation_init,
+       NULL, NULL
+     };
+     static const GInterfaceInfo col_info = {
+       gst_play_bin_colorbalance_init,
+       NULL, NULL
+     };
  
      gst_play_bin_type = g_type_register_static (GST_TYPE_PIPELINE,
 -        "GstPlayBin2", &gst_play_bin_info, 0);
 +        "GstPlayBin", &gst_play_bin_info, 0);
  
 -    g_type_add_interface_static (gst_play_bin_type,
 -        GST_TYPE_IMPLEMENTS_INTERFACE, &impl_info);
      g_type_add_interface_static (gst_play_bin_type, GST_TYPE_STREAM_VOLUME,
          &svol_info);
 -    g_type_add_interface_static (gst_play_bin_type, GST_TYPE_X_OVERLAY,
 -        &xov_info);
++    g_type_add_interface_static (gst_play_bin_type, GST_TYPE_VIDEO_OVERLAY,
++        &ov_info);
+     g_type_add_interface_static (gst_play_bin_type, GST_TYPE_NAVIGATION,
+         &nav_info);
+     g_type_add_interface_static (gst_play_bin_type, GST_TYPE_COLOR_BALANCE,
+         &col_info);
    }
  
    return gst_play_bin_type;
@@@ -1257,10 -1299,11 +1288,11 @@@ gst_play_bin_init (GstPlayBin * playbin
    init_group (playbin, &playbin->groups[1]);
  
    /* first filter out the interesting element factories */
 -  playbin->elements_lock = g_mutex_new ();
 +  g_mutex_init (&playbin->elements_lock);
  
    /* add sink */
-   playbin->playsink = g_object_new (GST_TYPE_PLAY_SINK, NULL);
+   playbin->playsink =
+       g_object_new (GST_TYPE_PLAY_SINK, "name", "playsink", NULL);
    gst_bin_add (GST_BIN_CAST (playbin), GST_ELEMENT_CAST (playbin->playsink));
    gst_play_sink_set_flags (playbin->playsink, DEFAULT_FLAGS);
    /* Connect to notify::volume and notify::mute signals for proxying */
@@@ -4026,6 -4065,137 +4060,121 @@@ failure
    }
  }
  
 -gst_play_bin_xoverlay_expose (GstXOverlay * overlay)
+ static void
 -  gst_x_overlay_expose (GST_X_OVERLAY (playbin->playsink));
++gst_play_bin_overlay_expose (GstVideoOverlay * overlay)
+ {
+   GstPlayBin *playbin = GST_PLAY_BIN (overlay);
 -gst_play_bin_xoverlay_handle_events (GstXOverlay * overlay,
++  gst_video_overlay_expose (GST_VIDEO_OVERLAY (playbin->playsink));
+ }
+ static void
 -  gst_x_overlay_handle_events (GST_X_OVERLAY (playbin->playsink),
++gst_play_bin_overlay_handle_events (GstVideoOverlay * overlay,
+     gboolean handle_events)
+ {
+   GstPlayBin *playbin = GST_PLAY_BIN (overlay);
 -gst_play_bin_xoverlay_set_render_rectangle (GstXOverlay * overlay, gint x,
++  gst_video_overlay_handle_events (GST_VIDEO_OVERLAY (playbin->playsink),
+       handle_events);
+ }
+ static void
 -  gst_x_overlay_set_render_rectangle (GST_X_OVERLAY (playbin->playsink), x, y,
 -      width, height);
++gst_play_bin_overlay_set_render_rectangle (GstVideoOverlay * overlay, gint x,
+     gint y, gint width, gint height)
+ {
+   GstPlayBin *playbin = GST_PLAY_BIN (overlay);
 -gst_play_bin_xoverlay_set_window_handle (GstXOverlay * overlay, guintptr handle)
++  gst_video_overlay_set_render_rectangle (GST_VIDEO_OVERLAY (playbin->playsink),
++      x, y, width, height);
+ }
+ static void
 -  gst_x_overlay_set_window_handle (GST_X_OVERLAY (playbin->playsink), handle);
 -}
 -
 -static void
 -gst_play_bin_xoverlay_init (gpointer g_iface, gpointer g_iface_data)
 -{
 -  GstXOverlayClass *iface = (GstXOverlayClass *) g_iface;
 -  iface->expose = gst_play_bin_xoverlay_expose;
 -  iface->handle_events = gst_play_bin_xoverlay_handle_events;
 -  iface->set_render_rectangle = gst_play_bin_xoverlay_set_render_rectangle;
 -  iface->set_window_handle = gst_play_bin_xoverlay_set_window_handle;
 -}
 -
 -static gboolean
 -gst_play_bin_implements_interface_supported (GstImplementsInterface * iface,
 -    GType type)
 -{
 -  if (type == GST_TYPE_X_OVERLAY || type == GST_TYPE_STREAM_VOLUME ||
 -      type == GST_TYPE_NAVIGATION || type == GST_TYPE_COLOR_BALANCE)
 -    return TRUE;
 -  else
 -    return FALSE;
++gst_play_bin_overlay_set_window_handle (GstVideoOverlay * overlay,
++    guintptr handle)
+ {
+   GstPlayBin *playbin = GST_PLAY_BIN (overlay);
 -gst_play_bin_implements_interface_init (gpointer g_iface, gpointer g_iface_data)
++  gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (playbin->playsink),
++      handle);
+ }
+ static void
 -  GstImplementsInterfaceClass *iface = (GstImplementsInterfaceClass *) g_iface;
 -  iface->supported = gst_play_bin_implements_interface_supported;
++gst_play_bin_overlay_init (gpointer g_iface, gpointer g_iface_data)
+ {
 -  GstColorBalanceClass *iface = (GstColorBalanceClass *) g_iface;
++  GstVideoOverlayInterface *iface = (GstVideoOverlayInterface *) g_iface;
++  iface->expose = gst_play_bin_overlay_expose;
++  iface->handle_events = gst_play_bin_overlay_handle_events;
++  iface->set_render_rectangle = gst_play_bin_overlay_set_render_rectangle;
++  iface->set_window_handle = gst_play_bin_overlay_set_window_handle;
+ }
+ static void
+ gst_play_bin_navigation_send_event (GstNavigation * navigation,
+     GstStructure * structure)
+ {
+   GstPlayBin *playbin = GST_PLAY_BIN (navigation);
+   gst_navigation_send_event (GST_NAVIGATION (playbin->playsink), structure);
+ }
+ static void
+ gst_play_bin_navigation_init (gpointer g_iface, gpointer g_iface_data)
+ {
+   GstNavigationInterface *iface = (GstNavigationInterface *) g_iface;
+   iface->send_event = gst_play_bin_navigation_send_event;
+ }
+ static const GList *
+ gst_play_bin_colorbalance_list_channels (GstColorBalance * balance)
+ {
+   GstPlayBin *playbin = GST_PLAY_BIN (balance);
+   return
+       gst_color_balance_list_channels (GST_COLOR_BALANCE (playbin->playsink));
+ }
+ static void
+ gst_play_bin_colorbalance_set_value (GstColorBalance * balance,
+     GstColorBalanceChannel * channel, gint value)
+ {
+   GstPlayBin *playbin = GST_PLAY_BIN (balance);
+   gst_color_balance_set_value (GST_COLOR_BALANCE (playbin->playsink), channel,
+       value);
+ }
+ static gint
+ gst_play_bin_colorbalance_get_value (GstColorBalance * balance,
+     GstColorBalanceChannel * channel)
+ {
+   GstPlayBin *playbin = GST_PLAY_BIN (balance);
+   return gst_color_balance_get_value (GST_COLOR_BALANCE (playbin->playsink),
+       channel);
+ }
+ static GstColorBalanceType
+ gst_play_bin_colorbalance_get_balance_type (GstColorBalance * balance)
+ {
+   GstPlayBin *playbin = GST_PLAY_BIN (balance);
+   return
+       gst_color_balance_get_balance_type (GST_COLOR_BALANCE
+       (playbin->playsink));
+ }
+ static void
+ gst_play_bin_colorbalance_init (gpointer g_iface, gpointer g_iface_data)
+ {
++  GstColorBalanceInterface *iface = (GstColorBalanceInterface *) g_iface;
+   iface->list_channels = gst_play_bin_colorbalance_list_channels;
+   iface->set_value = gst_play_bin_colorbalance_set_value;
+   iface->get_value = gst_play_bin_colorbalance_get_value;
+   iface->get_balance_type = gst_play_bin_colorbalance_get_balance_type;
+ }
  gboolean
  gst_play_bin2_plugin_init (GstPlugin * plugin)
  {
  #include <gst/gst-i18n-plugin.h>
  #include <gst/pbutils/pbutils.h>
  #include <gst/video/video.h>
 -#include <gst/interfaces/streamvolume.h>
 -#include <gst/interfaces/colorbalance.h>
 -#include <gst/interfaces/xoverlay.h>
++#include <gst/audio/streamvolume.h>
++#include <gst/video/colorbalance.h>
++#include <gst/video/videooverlay.h>
+ #include <gst/interfaces/navigation.h>
  
  #include "gstplaysink.h"
  #include "gststreamsynchronizer.h"
@@@ -202,6 -207,20 +206,20 @@@ struct _GstPlaySin
    gboolean volume_changed;      /* volume/mute changed while no audiochain */
    gboolean mute_changed;        /* ... has been created yet */
    gint64 av_offset;
 -  /* xoverlay proxy interface */
 -  GstXOverlay *xoverlay_element;        /* protected with LOCK */
 -  gboolean xoverlay_handle_set;
 -  guintptr xoverlay_handle;
 -  gboolean xoverlay_render_rectangle_set;
 -  gint xoverlay_x, xoverlay_y, xoverlay_width, xoverlay_height;
 -  gboolean xoverlay_handle_events_set;
 -  gboolean xoverlay_handle_events;
++  /* videooverlay proxy interface */
++  GstVideoOverlay *overlay_element;     /* protected with LOCK */
++  gboolean overlay_handle_set;
++  guintptr overlay_handle;
++  gboolean overlay_render_rectangle_set;
++  gint overlay_x, overlay_y, overlay_width, overlay_height;
++  gboolean overlay_handle_events_set;
++  gboolean overlay_handle_events;
+   /* colorbalance proxy interface */
+   GstColorBalance *colorbalance_element;
+   GList *colorbalance_channels; /* CONTRAST, BRIGHTNESS, HUE, SATURATION */
+   gint colorbalance_values[4];
  };
  
  struct _GstPlaySinkClass
@@@ -324,7 -343,47 +342,40 @@@ gst_play_marshal_SAMPLE__BOXED (GClosur
  
  /* static guint gst_play_sink_signals[LAST_SIGNAL] = { 0 }; */
  
- G_DEFINE_TYPE (GstPlaySink, gst_play_sink, GST_TYPE_BIN);
 -static void gst_play_sink_implements_interface_init (gpointer g_iface,
 -    gpointer g_iface_data);
 -static void gst_play_sink_xoverlay_init (gpointer g_iface,
++static void gst_play_sink_overlay_init (gpointer g_iface,
+     gpointer g_iface_data);
+ static void gst_play_sink_navigation_init (gpointer g_iface,
+     gpointer g_iface_data);
+ static void gst_play_sink_colorbalance_init (gpointer g_iface,
+     gpointer g_iface_data);
+ static void
+ _do_init (GType type)
+ {
 -  static const GInterfaceInfo impl_info = {
 -    gst_play_sink_implements_interface_init,
 -    NULL, NULL
 -  };
+   static const GInterfaceInfo svol_info = {
+     NULL, NULL, NULL
+   };
 -  static const GInterfaceInfo xov_info = {
 -    gst_play_sink_xoverlay_init,
++  static const GInterfaceInfo ov_info = {
++    gst_play_sink_overlay_init,
+     NULL, NULL
+   };
+   static const GInterfaceInfo nav_info = {
+     gst_play_sink_navigation_init,
+     NULL, NULL
+   };
+   static const GInterfaceInfo col_info = {
+     gst_play_sink_colorbalance_init,
+     NULL, NULL
+   };
 -  g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE, &impl_info);
+   g_type_add_interface_static (type, GST_TYPE_STREAM_VOLUME, &svol_info);
 -  g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &xov_info);
++  g_type_add_interface_static (type, GST_TYPE_VIDEO_OVERLAY, &ov_info);
+   g_type_add_interface_static (type, GST_TYPE_NAVIGATION, &nav_info);
+   g_type_add_interface_static (type, GST_TYPE_COLOR_BALANCE, &col_info);
+ }
+ G_DEFINE_TYPE_WITH_CODE (GstPlaySink, gst_play_sink, GST_TYPE_BIN,
+     _do_init (g_define_type_id));
  
  static void
  gst_play_sink_class_init (GstPlaySinkClass * klass)
@@@ -520,8 -583,48 +574,48 @@@ gst_play_sink_init (GstPlaySink * plays
    gst_bin_add (GST_BIN_CAST (playsink),
        GST_ELEMENT_CAST (playsink->stream_synchronizer));
  
 -  g_static_rec_mutex_init (&playsink->lock);
 -  GST_OBJECT_FLAG_SET (playsink, GST_ELEMENT_IS_SINK);
 +  g_rec_mutex_init (&playsink->lock);
 +  GST_OBJECT_FLAG_SET (playsink, GST_ELEMENT_FLAG_SINK);
+   channel =
+       GST_COLOR_BALANCE_CHANNEL (g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL,
+           NULL));
+   channel->label = g_strdup ("CONTRAST");
+   channel->min_value = -1000;
+   channel->max_value = 1000;
+   playsink->colorbalance_channels =
+       g_list_append (playsink->colorbalance_channels, channel);
+   playsink->colorbalance_values[0] = 0;
+   channel =
+       GST_COLOR_BALANCE_CHANNEL (g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL,
+           NULL));
+   channel->label = g_strdup ("BRIGHTNESS");
+   channel->min_value = -1000;
+   channel->max_value = 1000;
+   playsink->colorbalance_channels =
+       g_list_append (playsink->colorbalance_channels, channel);
+   playsink->colorbalance_values[1] = 0;
+   channel =
+       GST_COLOR_BALANCE_CHANNEL (g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL,
+           NULL));
+   channel->label = g_strdup ("HUE");
+   channel->min_value = -1000;
+   channel->max_value = 1000;
+   playsink->colorbalance_channels =
+       g_list_append (playsink->colorbalance_channels, channel);
+   playsink->colorbalance_values[2] = 0;
+   channel =
+       GST_COLOR_BALANCE_CHANNEL (g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL,
+           NULL));
+   channel->label = g_strdup ("SATURATION");
+   channel->min_value = -1000;
+   channel->max_value = 1000;
+   playsink->colorbalance_channels =
+       g_list_append (playsink->colorbalance_channels, channel);
+   playsink->colorbalance_values[3] = 0;
  }
  
  static void
@@@ -1231,6 -1343,150 +1330,149 @@@ link_failed
    }
  }
  
 -is_valid_color_balance_element (GstElement * element)
+ static gboolean
 -  GstColorBalance *bal = GST_COLOR_BALANCE (element);
++is_valid_color_balance_element (GstColorBalance * bal)
+ {
 -iterate_color_balance_elements (gpointer data, gpointer user_data)
+   gboolean have_brightness = FALSE;
+   gboolean have_contrast = FALSE;
+   gboolean have_hue = FALSE;
+   gboolean have_saturation = FALSE;
+   const GList *channels, *l;
+   channels = gst_color_balance_list_channels (bal);
+   for (l = channels; l; l = l->next) {
+     GstColorBalanceChannel *ch = l->data;
+     if (g_strrstr (ch->label, "BRIGHTNESS"))
+       have_brightness = TRUE;
+     else if (g_strrstr (ch->label, "CONTRAST"))
+       have_contrast = TRUE;
+     else if (g_strrstr (ch->label, "HUE"))
+       have_hue = TRUE;
+     else if (g_strrstr (ch->label, "SATURATION"))
+       have_saturation = TRUE;
+   }
+   return have_brightness && have_contrast && have_hue && have_saturation;
+ }
+ static void
 -  gboolean valid = is_valid_color_balance_element (data);
 -  GstColorBalance **cb_out = user_data;
++iterate_color_balance_elements (const GValue * item, gpointer user_data)
+ {
 -      *cb_out = GST_COLOR_BALANCE (gst_object_ref (data));
++  gboolean valid;
++  GstColorBalance *cb, **cb_out = user_data;
++  cb = GST_COLOR_BALANCE (g_value_get_object (item));
++  valid = is_valid_color_balance_element (cb);
+   if (valid) {
+     if (*cb_out
+         && gst_color_balance_get_balance_type (*cb_out) ==
+         GST_COLOR_BALANCE_SOFTWARE) {
+       gst_object_unref (*cb_out);
 -      *cb_out = GST_COLOR_BALANCE (gst_object_ref (data));
++      *cb_out = GST_COLOR_BALANCE (gst_object_ref (cb));
+     } else if (!*cb_out) {
 -
 -  gst_object_unref (data);
++      *cb_out = GST_COLOR_BALANCE (gst_object_ref (cb));
+     }
+   }
 -      && is_valid_color_balance_element (element))
+ }
+ static GstColorBalance *
+ find_color_balance_element (GstElement * element)
+ {
+   GstIterator *it;
+   GstColorBalance *cb = NULL;
+   if (GST_IS_COLOR_BALANCE (element)
++      && is_valid_color_balance_element (GST_COLOR_BALANCE (element)))
+     return GST_COLOR_BALANCE (gst_object_ref (element));
+   else if (!GST_IS_BIN (element))
+     return FALSE;
+   it = gst_bin_iterate_all_by_interface (GST_BIN (element),
+       GST_TYPE_COLOR_BALANCE);
+   while (gst_iterator_foreach (it, iterate_color_balance_elements,
+           &cb) == GST_ITERATOR_RESYNC)
+     gst_iterator_resync (it);
+   gst_iterator_free (it);
+   return cb;
+ }
+ static void
+ colorbalance_value_changed_cb (GstColorBalance * balance,
+     GstColorBalanceChannel * channel, gint value, GstPlaySink * playsink)
+ {
+   GList *l;
+   gint i;
+   for (i = 0, l = playsink->colorbalance_channels; l; l = l->next, i++) {
+     GstColorBalanceChannel *proxy = l->data;
+     if (g_strrstr (channel->label, proxy->label)) {
+       gdouble new_val;
+       /* Convert to [0, 1] range */
+       new_val =
+           ((gdouble) value -
+           (gdouble) channel->min_value) / ((gdouble) channel->max_value -
+           (gdouble) channel->min_value);
+       /* Convert to proxy range */
+       new_val =
+           proxy->min_value + new_val * ((gdouble) proxy->max_value -
+           (gdouble) proxy->min_value);
+       playsink->colorbalance_values[i] = (gint) (0.5 + new_val);
+       gst_color_balance_value_changed (GST_COLOR_BALANCE (playsink), proxy,
+           playsink->colorbalance_values[i]);
+       break;
+     }
+   }
+ }
+ static void
+ update_colorbalance (GstPlaySink * playsink)
+ {
+   GstColorBalance *balance = NULL;
+   GList *l;
+   gint i;
+   GST_OBJECT_LOCK (playsink);
+   if (playsink->colorbalance_element) {
+     balance =
+         GST_COLOR_BALANCE (gst_object_ref (playsink->colorbalance_element));
+   }
+   GST_OBJECT_UNLOCK (playsink);
+   if (!balance)
+     return;
+   g_signal_handlers_block_by_func (balance,
+       G_CALLBACK (colorbalance_value_changed_cb), playsink);
+   for (i = 0, l = playsink->colorbalance_channels; l; l = l->next, i++) {
+     GstColorBalanceChannel *proxy = l->data;
+     GstColorBalanceChannel *channel = NULL;
+     const GList *channels, *k;
+     channels = gst_color_balance_list_channels (balance);
+     for (k = channels; k; k = k->next) {
+       GstColorBalanceChannel *tmp = k->data;
+       if (g_strrstr (tmp->label, proxy->label)) {
+         channel = tmp;
+         break;
+       }
+     }
+     g_assert (channel);
+     gst_color_balance_set_value (balance, channel,
+         playsink->colorbalance_values[i]);
+   }
+   g_signal_handlers_unblock_by_func (balance,
+       G_CALLBACK (colorbalance_value_changed_cb), playsink);
+ }
  /* make the element (bin) that contains the elements needed to perform
   * video display.
   *
@@@ -1310,6 -1573,34 +1559,34 @@@ gen_video_chain (GstPlaySink * playsink
    gst_object_ref_sink (bin);
    gst_bin_add (bin, chain->sink);
  
 -  /* Get the XOverlay element */
++  /* Get the VideoOverlay element */
+   {
 -    GstXOverlay *xoverlay = NULL;
++    GstVideoOverlay *overlay = NULL;
+     GST_OBJECT_LOCK (playsink);
 -    if (playsink->xoverlay_element)
 -      gst_object_unref (playsink->xoverlay_element);
 -    playsink->xoverlay_element =
 -        GST_X_OVERLAY (gst_bin_get_by_interface (GST_BIN (chain->chain.bin),
 -            GST_TYPE_X_OVERLAY));
 -    if (playsink->xoverlay_element)
 -      xoverlay = GST_X_OVERLAY (gst_object_ref (playsink->xoverlay_element));
++    if (playsink->overlay_element)
++      gst_object_unref (playsink->overlay_element);
++    playsink->overlay_element =
++        GST_VIDEO_OVERLAY (gst_bin_get_by_interface (GST_BIN (chain->chain.bin),
++            GST_TYPE_VIDEO_OVERLAY));
++    if (playsink->overlay_element)
++      overlay = GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element));
+     GST_OBJECT_UNLOCK (playsink);
 -    if (xoverlay) {
 -      if (playsink->xoverlay_handle_set)
 -        gst_x_overlay_set_window_handle (xoverlay, playsink->xoverlay_handle);
 -      if (playsink->xoverlay_handle_events_set)
 -        gst_x_overlay_handle_events (xoverlay,
 -            playsink->xoverlay_handle_events);
 -      if (playsink->xoverlay_render_rectangle_set)
 -        gst_x_overlay_set_render_rectangle (xoverlay,
 -            playsink->xoverlay_x, playsink->xoverlay_y,
 -            playsink->xoverlay_width, playsink->xoverlay_height);
 -      gst_object_unref (xoverlay);
++    if (overlay) {
++      if (playsink->overlay_handle_set)
++        gst_video_overlay_set_window_handle (overlay, playsink->overlay_handle);
++      if (playsink->overlay_handle_events_set)
++        gst_video_overlay_handle_events (overlay,
++            playsink->overlay_handle_events);
++      if (playsink->overlay_render_rectangle_set)
++        gst_video_overlay_set_render_rectangle (overlay,
++            playsink->overlay_x, playsink->overlay_y,
++            playsink->overlay_width, playsink->overlay_height);
++      gst_object_unref (overlay);
+     }
+   }
    /* decouple decoder from sink, this improves playback quite a lot since the
     * decoder can continue while the sink blocks for synchronisation. We don't
     * need a lot of buffers as this consumes a lot of memory and we don't want
@@@ -1423,8 -1741,35 +1727,35 @@@ setup_video_chain (GstPlaySink * playsi
    if (ret == GST_STATE_CHANGE_FAILURE)
      return FALSE;
  
-   /* find ts-offset element */
 -  /* Get the XOverlay element */
++  /* Get the VideoOverlay element */
+   {
 -    GstXOverlay *xoverlay = NULL;
++    GstVideoOverlay *overlay = NULL;
+     GST_OBJECT_LOCK (playsink);
 -    if (playsink->xoverlay_element)
 -      gst_object_unref (playsink->xoverlay_element);
 -    playsink->xoverlay_element =
 -        GST_X_OVERLAY (gst_bin_get_by_interface (GST_BIN (chain->chain.bin),
 -            GST_TYPE_X_OVERLAY));
 -    if (playsink->xoverlay_element)
 -      xoverlay = GST_X_OVERLAY (gst_object_ref (playsink->xoverlay_element));
++    if (playsink->overlay_element)
++      gst_object_unref (playsink->overlay_element);
++    playsink->overlay_element =
++        GST_VIDEO_OVERLAY (gst_bin_get_by_interface (GST_BIN (chain->chain.bin),
++            GST_TYPE_VIDEO_OVERLAY));
++    if (playsink->overlay_element)
++      overlay = GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element));
+     GST_OBJECT_UNLOCK (playsink);
 -    if (xoverlay) {
 -      if (playsink->xoverlay_handle_set)
 -        gst_x_overlay_set_window_handle (xoverlay, playsink->xoverlay_handle);
 -      if (playsink->xoverlay_handle_events_set)
 -        gst_x_overlay_handle_events (xoverlay,
 -            playsink->xoverlay_handle_events);
 -      if (playsink->xoverlay_render_rectangle_set)
 -        gst_x_overlay_set_render_rectangle (xoverlay,
 -            playsink->xoverlay_x, playsink->xoverlay_y,
 -            playsink->xoverlay_width, playsink->xoverlay_height);
 -      gst_object_unref (xoverlay);
++    if (overlay) {
++      if (playsink->overlay_handle_set)
++        gst_video_overlay_set_window_handle (overlay, playsink->overlay_handle);
++      if (playsink->overlay_handle_events_set)
++        gst_video_overlay_handle_events (overlay,
++            playsink->overlay_handle_events);
++      if (playsink->overlay_render_rectangle_set)
++        gst_video_overlay_set_render_rectangle (overlay,
++            playsink->overlay_x, playsink->overlay_y,
++            playsink->overlay_width, playsink->overlay_height);
++      gst_object_unref (overlay);
+     }
+   }
  
+   /* find ts-offset element */
    gst_object_replace ((GstObject **) & chain->ts_offset, (GstObject *)
        gst_play_sink_find_property_sinks (playsink, chain->sink, "ts-offset",
            G_TYPE_INT64));
@@@ -2164,6 -2543,19 +2529,19 @@@ gst_play_sink_reconfigure (GstPlaySink 
      need_text = TRUE;
    }
  
 -  if (playsink->xoverlay_element)
 -    gst_object_unref (playsink->xoverlay_element);
 -  playsink->xoverlay_element = NULL;
+   GST_OBJECT_LOCK (playsink);
++  if (playsink->overlay_element)
++    gst_object_unref (playsink->overlay_element);
++  playsink->overlay_element = NULL;
+   if (playsink->colorbalance_element) {
+     g_signal_handlers_disconnect_by_func (playsink->colorbalance_element,
+         G_CALLBACK (colorbalance_value_changed_cb), playsink);
+     gst_object_unref (playsink->colorbalance_element);
+   }
+   playsink->colorbalance_element = NULL;
+   GST_OBJECT_UNLOCK (playsink);
    if (((flags & GST_PLAY_FLAG_VIDEO)
            || (flags & GST_PLAY_FLAG_NATIVE_VIDEO)) && playsink->video_pad) {
      /* we have video and we are requested to show it */
@@@ -3355,6 -3714,43 +3733,44 @@@ gst_play_sink_handle_message (GstBin * 
        GST_BIN_CLASS (gst_play_sink_parent_class)->handle_message (bin, message);
        break;
      }
 -      if (gst_structure_has_name (message->structure, "prepare-xwindow-id")) {
 -        GstXOverlay *xoverlay;
+     case GST_MESSAGE_ELEMENT:{
 -        if (playsink->xoverlay_element
 -            && GST_OBJECT_CAST (playsink->xoverlay_element) !=
++      if (gst_is_video_overlay_prepare_window_handle_message (message)) {
++        GstVideoOverlay *overlay;
+         GST_OBJECT_LOCK (playsink);
 -          gst_object_unref (playsink->xoverlay_element);
 -          playsink->xoverlay_element = NULL;
++        if (playsink->overlay_element
++            && GST_OBJECT_CAST (playsink->overlay_element) !=
+             GST_MESSAGE_SRC (message)) {
 -        if (!playsink->xoverlay_element)
 -          playsink->xoverlay_element =
 -              GST_X_OVERLAY (gst_object_ref (GST_MESSAGE_SRC (message)));
 -        xoverlay = GST_X_OVERLAY (gst_object_ref (playsink->xoverlay_element));
++          gst_object_unref (playsink->overlay_element);
++          playsink->overlay_element = NULL;
+         }
 -        if (playsink->xoverlay_handle_set)
 -          gst_x_overlay_set_window_handle (playsink->xoverlay_element,
 -              playsink->xoverlay_handle);
 -        if (playsink->xoverlay_handle_events_set)
 -          gst_x_overlay_handle_events (playsink->xoverlay_element,
 -              playsink->xoverlay_handle_events);
 -        if (playsink->xoverlay_render_rectangle_set)
 -          gst_x_overlay_set_render_rectangle (playsink->xoverlay_element,
 -              playsink->xoverlay_x, playsink->xoverlay_y,
 -              playsink->xoverlay_width, playsink->xoverlay_height);
 -
 -        gst_object_unref (xoverlay);
++        if (!playsink->overlay_element)
++          playsink->overlay_element =
++              GST_VIDEO_OVERLAY (gst_object_ref (GST_MESSAGE_SRC (message)));
++        overlay =
++            GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element));
+         GST_OBJECT_UNLOCK (playsink);
+         GST_DEBUG_OBJECT (playsink, "Got prepare-xwindow-id message");
 -        gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (playsink));
++        if (playsink->overlay_handle_set)
++          gst_video_overlay_set_window_handle (playsink->overlay_element,
++              playsink->overlay_handle);
++        if (playsink->overlay_handle_events_set)
++          gst_video_overlay_handle_events (playsink->overlay_element,
++              playsink->overlay_handle_events);
++        if (playsink->overlay_render_rectangle_set)
++          gst_video_overlay_set_render_rectangle (playsink->overlay_element,
++              playsink->overlay_x, playsink->overlay_y,
++              playsink->overlay_width, playsink->overlay_height);
++
++        gst_object_unref (overlay);
+         gst_message_unref (message);
++        gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (playsink));
+       }
+       break;
+     }
      default:
        GST_BIN_CLASS (gst_play_sink_parent_class)->handle_message (bin, message);
        break;
@@@ -3493,6 -3913,20 +3901,20 @@@ gst_play_sink_change_state (GstElement 
          gst_object_unref (playsink->videochain->ts_offset);
          playsink->videochain->ts_offset = NULL;
        }
 -      if (playsink->xoverlay_element)
 -        gst_object_unref (playsink->xoverlay_element);
 -      playsink->xoverlay_element = NULL;
+       GST_OBJECT_LOCK (playsink);
++      if (playsink->overlay_element)
++        gst_object_unref (playsink->overlay_element);
++      playsink->overlay_element = NULL;
+       if (playsink->colorbalance_element) {
+         g_signal_handlers_disconnect_by_func (playsink->colorbalance_element,
+             G_CALLBACK (colorbalance_value_changed_cb), playsink);
+         gst_object_unref (playsink->colorbalance_element);
+       }
+       playsink->colorbalance_element = NULL;
+       GST_OBJECT_UNLOCK (playsink);
        ret = GST_STATE_CHANGE_SUCCESS;
        break;
      default:
@@@ -3735,6 -4164,282 +4152,268 @@@ gst_play_sink_get_property (GObject * o
    }
  }
  
 -gst_play_sink_xoverlay_expose (GstXOverlay * overlay)
+ static void
 -  GstXOverlay *xoverlay;
++gst_play_sink_overlay_expose (GstVideoOverlay * overlay)
+ {
+   GstPlaySink *playsink = GST_PLAY_SINK (overlay);
 -  if (playsink->xoverlay_element)
 -    xoverlay = GST_X_OVERLAY (gst_object_ref (playsink->xoverlay_element));
++  GstVideoOverlay *overlay_element;
+   GST_OBJECT_LOCK (playsink);
 -    xoverlay = NULL;
++  if (playsink->overlay_element)
++    overlay_element =
++        GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element));
+   else
 -  if (xoverlay) {
 -    gst_x_overlay_expose (xoverlay);
 -    gst_object_unref (xoverlay);
++    overlay_element = NULL;
+   GST_OBJECT_UNLOCK (playsink);
 -gst_play_sink_xoverlay_handle_events (GstXOverlay * overlay,
++  if (overlay_element) {
++    gst_video_overlay_expose (overlay_element);
++    gst_object_unref (overlay_element);
+   }
+ }
+ static void
 -  GstXOverlay *xoverlay;
++gst_play_sink_overlay_handle_events (GstVideoOverlay * overlay,
+     gboolean handle_events)
+ {
+   GstPlaySink *playsink = GST_PLAY_SINK (overlay);
 -  if (playsink->xoverlay_element)
 -    xoverlay = GST_X_OVERLAY (gst_object_ref (playsink->xoverlay_element));
++  GstVideoOverlay *overlay_element;
+   GST_OBJECT_LOCK (playsink);
 -    xoverlay = NULL;
++  if (playsink->overlay_element)
++    overlay_element =
++        GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element));
+   else
 -  playsink->xoverlay_handle_events_set = TRUE;
 -  playsink->xoverlay_handle_events = handle_events;
++    overlay_element = NULL;
+   GST_OBJECT_UNLOCK (playsink);
 -  if (xoverlay) {
 -    gst_x_overlay_handle_events (xoverlay, handle_events);
 -    gst_object_unref (xoverlay);
++  playsink->overlay_handle_events_set = TRUE;
++  playsink->overlay_handle_events = handle_events;
 -gst_play_sink_xoverlay_set_render_rectangle (GstXOverlay * overlay, gint x,
++  if (overlay_element) {
++    gst_video_overlay_handle_events (overlay_element, handle_events);
++    gst_object_unref (overlay_element);
+   }
+ }
+ static void
 -  GstXOverlay *xoverlay;
++gst_play_sink_overlay_set_render_rectangle (GstVideoOverlay * overlay, gint x,
+     gint y, gint width, gint height)
+ {
+   GstPlaySink *playsink = GST_PLAY_SINK (overlay);
 -  if (playsink->xoverlay_element)
 -    xoverlay = GST_X_OVERLAY (gst_object_ref (playsink->xoverlay_element));
++  GstVideoOverlay *overlay_element;
+   GST_OBJECT_LOCK (playsink);
 -    xoverlay = NULL;
++  if (playsink->overlay_element)
++    overlay_element =
++        GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element));
+   else
 -  playsink->xoverlay_render_rectangle_set = TRUE;
 -  playsink->xoverlay_x = x;
 -  playsink->xoverlay_y = y;
 -  playsink->xoverlay_width = width;
 -  playsink->xoverlay_height = height;
++    overlay_element = NULL;
+   GST_OBJECT_UNLOCK (playsink);
 -  if (xoverlay) {
 -    gst_x_overlay_set_render_rectangle (xoverlay, x, y, width, height);
 -    gst_object_unref (xoverlay);
++  playsink->overlay_render_rectangle_set = TRUE;
++  playsink->overlay_x = x;
++  playsink->overlay_y = y;
++  playsink->overlay_width = width;
++  playsink->overlay_height = height;
 -gst_play_sink_xoverlay_set_window_handle (GstXOverlay * overlay,
++  if (overlay_element) {
++    gst_video_overlay_set_render_rectangle (overlay_element, x, y, width,
++        height);
++    gst_object_unref (overlay_element);
+   }
+ }
+ static void
 -  GstXOverlay *xoverlay;
++gst_play_sink_overlay_set_window_handle (GstVideoOverlay * overlay,
+     guintptr handle)
+ {
+   GstPlaySink *playsink = GST_PLAY_SINK (overlay);
 -  if (playsink->xoverlay_element)
 -    xoverlay = GST_X_OVERLAY (gst_object_ref (playsink->xoverlay_element));
++  GstVideoOverlay *overlay_element;
+   GST_OBJECT_LOCK (playsink);
 -    xoverlay = NULL;
++  if (playsink->overlay_element)
++    overlay_element =
++        GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element));
+   else
 -  playsink->xoverlay_handle_set = TRUE;
 -  playsink->xoverlay_handle = handle;
++    overlay_element = NULL;
+   GST_OBJECT_UNLOCK (playsink);
 -  if (xoverlay) {
 -    gst_x_overlay_set_window_handle (xoverlay, handle);
 -    gst_object_unref (xoverlay);
++  playsink->overlay_handle_set = TRUE;
++  playsink->overlay_handle = handle;
 -gst_play_sink_xoverlay_init (gpointer g_iface, gpointer g_iface_data)
 -{
 -  GstXOverlayClass *iface = (GstXOverlayClass *) g_iface;
 -  iface->expose = gst_play_sink_xoverlay_expose;
 -  iface->handle_events = gst_play_sink_xoverlay_handle_events;
 -  iface->set_render_rectangle = gst_play_sink_xoverlay_set_render_rectangle;
 -  iface->set_window_handle = gst_play_sink_xoverlay_set_window_handle;
 -}
 -
 -static gboolean
 -gst_play_sink_implements_interface_supported (GstImplementsInterface * iface,
 -    GType type)
 -{
 -  if (type == GST_TYPE_X_OVERLAY || type == GST_TYPE_STREAM_VOLUME ||
 -      type == GST_TYPE_NAVIGATION || type == GST_TYPE_COLOR_BALANCE)
 -    return TRUE;
 -  else
 -    return FALSE;
 -}
 -
 -static void
 -gst_play_sink_implements_interface_init (gpointer g_iface,
 -    gpointer g_iface_data)
++  if (overlay_element) {
++    gst_video_overlay_set_window_handle (overlay_element, handle);
++    gst_object_unref (overlay_element);
+   }
+ }
+ static void
 -  GstImplementsInterfaceClass *iface = (GstImplementsInterfaceClass *) g_iface;
 -  iface->supported = gst_play_sink_implements_interface_supported;
++gst_play_sink_overlay_init (gpointer g_iface, gpointer g_iface_data)
+ {
 -  GstColorBalanceClass *iface = (GstColorBalanceClass *) g_iface;
++  GstVideoOverlayInterface *iface = (GstVideoOverlayInterface *) g_iface;
++  iface->expose = gst_play_sink_overlay_expose;
++  iface->handle_events = gst_play_sink_overlay_handle_events;
++  iface->set_render_rectangle = gst_play_sink_overlay_set_render_rectangle;
++  iface->set_window_handle = gst_play_sink_overlay_set_window_handle;
+ }
+ static void
+ gst_play_sink_navigation_send_event (GstNavigation * navigation,
+     GstStructure * structure)
+ {
+   GstPlaySink *playsink = GST_PLAY_SINK (navigation);
+   GstBin *bin = NULL;
+   GST_PLAY_SINK_LOCK (playsink);
+   if (playsink->videochain && playsink->videochain->chain.bin)
+     bin = GST_BIN (gst_object_ref (playsink->videochain->chain.bin));
+   GST_PLAY_SINK_UNLOCK (playsink);
+   if (bin) {
+     GstElement *nav = gst_bin_get_by_interface (bin, GST_TYPE_NAVIGATION);
+     if (nav) {
+       gst_navigation_send_event (GST_NAVIGATION (nav), structure);
+       structure = NULL;
+       gst_object_unref (nav);
+     }
+     gst_object_unref (bin);
+   }
+   if (structure)
+     gst_structure_free (structure);
+ }
+ static void
+ gst_play_sink_navigation_init (gpointer g_iface, gpointer g_iface_data)
+ {
+   GstNavigationInterface *iface = (GstNavigationInterface *) g_iface;
+   iface->send_event = gst_play_sink_navigation_send_event;
+ }
+ static const GList *
+ gst_play_sink_colorbalance_list_channels (GstColorBalance * balance)
+ {
+   GstPlaySink *playsink = GST_PLAY_SINK (balance);
+   return playsink->colorbalance_channels;
+ }
+ static void
+ gst_play_sink_colorbalance_set_value (GstColorBalance * balance,
+     GstColorBalanceChannel * proxy, gint value)
+ {
+   GstPlaySink *playsink = GST_PLAY_SINK (balance);
+   GList *l;
+   gint i;
+   GstColorBalance *balance_element = NULL;
+   GST_OBJECT_LOCK (playsink);
+   if (playsink->colorbalance_element)
+     balance_element =
+         GST_COLOR_BALANCE (gst_object_ref (playsink->colorbalance_element));
+   GST_OBJECT_UNLOCK (playsink);
+   for (i = 0, l = playsink->colorbalance_channels; l; l = l->next, i++) {
+     GstColorBalanceChannel *proxy_tmp = l->data;
+     gdouble new_val;
+     if (proxy_tmp != proxy)
+       continue;
+     playsink->colorbalance_values[i] = value;
+     if (balance_element) {
+       GstColorBalanceChannel *channel = NULL;
+       const GList *channels, *k;
+       channels = gst_color_balance_list_channels (balance_element);
+       for (k = channels; k; k = k->next) {
+         GstColorBalanceChannel *tmp = l->data;
+         if (g_strrstr (tmp->label, proxy->label)) {
+           channel = tmp;
+           break;
+         }
+       }
+       g_assert (channel);
+       /* Convert to [0, 1] range */
+       new_val =
+           ((gdouble) value -
+           (gdouble) proxy->min_value) / ((gdouble) proxy->max_value -
+           (gdouble) proxy->min_value);
+       /* Convert to channel range */
+       new_val =
+           channel->min_value + new_val * ((gdouble) channel->max_value -
+           (gdouble) channel->min_value);
+       gst_color_balance_set_value (balance_element, channel,
+           (gint) (new_val + 0.5));
+       gst_object_unref (balance_element);
+     }
+     gst_color_balance_value_changed (balance, proxy, value);
+     break;
+   }
+ }
+ static gint
+ gst_play_sink_colorbalance_get_value (GstColorBalance * balance,
+     GstColorBalanceChannel * proxy)
+ {
+   GstPlaySink *playsink = GST_PLAY_SINK (balance);
+   GList *l;
+   gint i;
+   for (i = 0, l = playsink->colorbalance_channels; l; l = l->next, i++) {
+     GstColorBalanceChannel *proxy_tmp = l->data;
+     if (proxy_tmp != proxy)
+       continue;
+     return playsink->colorbalance_values[i];
+   }
+   g_return_val_if_reached (0);
+ }
+ static GstColorBalanceType
+ gst_play_sink_colorbalance_get_balance_type (GstColorBalance * balance)
+ {
+   GstPlaySink *playsink = GST_PLAY_SINK (balance);
+   GstColorBalance *balance_element = NULL;
+   GstColorBalanceType t = GST_COLOR_BALANCE_SOFTWARE;
+   GST_OBJECT_LOCK (playsink);
+   if (playsink->colorbalance_element)
+     balance_element =
+         GST_COLOR_BALANCE (gst_object_ref (playsink->colorbalance_element));
+   GST_OBJECT_UNLOCK (playsink);
+   if (balance_element) {
+     t = gst_color_balance_get_balance_type (balance_element);
+     gst_object_unref (balance_element);
+   }
+   return t;
+ }
+ static void
+ gst_play_sink_colorbalance_init (gpointer g_iface, gpointer g_iface_data)
+ {
++  GstColorBalanceInterface *iface = (GstColorBalanceInterface *) g_iface;
+   iface->list_channels = gst_play_sink_colorbalance_list_channels;
+   iface->set_value = gst_play_sink_colorbalance_set_value;
+   iface->get_value = gst_play_sink_colorbalance_get_value;
+   iface->get_balance_type = gst_play_sink_colorbalance_get_balance_type;
+ }
  
  gboolean
  gst_play_sink_plugin_init (GstPlugin * plugin)
@@@ -395,50 -424,151 +395,170 @@@ gst_video_scale_get_property (GObject 
    }
  }
  
 -  GstVideoFormat fmt;
+ #define NEAREST  (1 << GST_VIDEO_SCALE_NEAREST)
+ #define BILINEAR (1 << GST_VIDEO_SCALE_BILINEAR)
+ #define FOURTAP  (1 << GST_VIDEO_SCALE_4TAP)
+ #define LANCZOS  (1 << GST_VIDEO_SCALE_LANCZOS)
+ /* or we could just do lookups via table[format] if we could be bothered..  */
+ static const struct
+ {
+   GstVideoFormat format;
+   guint8 methods;
+ } formats_methods_table[] = {
+   {
+   GST_VIDEO_FORMAT_RGBx, NEAREST | BILINEAR | FOURTAP | LANCZOS}, {
+   GST_VIDEO_FORMAT_xRGB, NEAREST | BILINEAR | FOURTAP | LANCZOS}, {
+   GST_VIDEO_FORMAT_BGRx, NEAREST | BILINEAR | FOURTAP | LANCZOS}, {
+   GST_VIDEO_FORMAT_xBGR, NEAREST | BILINEAR | FOURTAP | LANCZOS}, {
+   GST_VIDEO_FORMAT_RGBA, NEAREST | BILINEAR | FOURTAP | LANCZOS}, {
+   GST_VIDEO_FORMAT_ARGB, NEAREST | BILINEAR | FOURTAP | LANCZOS}, {
+   GST_VIDEO_FORMAT_BGRA, NEAREST | BILINEAR | FOURTAP | LANCZOS}, {
+   GST_VIDEO_FORMAT_ABGR, NEAREST | BILINEAR | FOURTAP | LANCZOS}, {
+   GST_VIDEO_FORMAT_AYUV, NEAREST | BILINEAR | FOURTAP | LANCZOS}, {
+   GST_VIDEO_FORMAT_ARGB64, NEAREST | BILINEAR | FOURTAP | LANCZOS}, {
+   GST_VIDEO_FORMAT_AYUV64, NEAREST | BILINEAR | FOURTAP | LANCZOS}, {
+   GST_VIDEO_FORMAT_RGB, NEAREST | BILINEAR | FOURTAP}, {
+   GST_VIDEO_FORMAT_BGR, NEAREST | BILINEAR | FOURTAP}, {
+   GST_VIDEO_FORMAT_v308, NEAREST | BILINEAR | FOURTAP}, {
+   GST_VIDEO_FORMAT_YUY2, NEAREST | BILINEAR | FOURTAP}, {
+   GST_VIDEO_FORMAT_YVYU, NEAREST | BILINEAR | FOURTAP}, {
+   GST_VIDEO_FORMAT_UYVY, NEAREST | BILINEAR | FOURTAP}, {
+   GST_VIDEO_FORMAT_Y800, NEAREST | BILINEAR | FOURTAP}, {
+   GST_VIDEO_FORMAT_GRAY8, NEAREST | BILINEAR | FOURTAP}, {
+   GST_VIDEO_FORMAT_GRAY16_LE, NEAREST | BILINEAR | FOURTAP}, {
+   GST_VIDEO_FORMAT_GRAY16_BE, NEAREST | BILINEAR | FOURTAP}, {
+   GST_VIDEO_FORMAT_Y16, NEAREST | BILINEAR | FOURTAP}, {
+   GST_VIDEO_FORMAT_I420, NEAREST | BILINEAR | FOURTAP | LANCZOS}, {
+   GST_VIDEO_FORMAT_YV12, NEAREST | BILINEAR | FOURTAP | LANCZOS}, {
+   GST_VIDEO_FORMAT_Y444, NEAREST | BILINEAR | FOURTAP | LANCZOS}, {
+   GST_VIDEO_FORMAT_Y42B, NEAREST | BILINEAR | FOURTAP | LANCZOS}, {
+   GST_VIDEO_FORMAT_Y41B, NEAREST | BILINEAR | FOURTAP | LANCZOS}, {
+   GST_VIDEO_FORMAT_NV12, NEAREST | BILINEAR}, {
+   GST_VIDEO_FORMAT_RGB16, NEAREST | BILINEAR | FOURTAP}, {
+   GST_VIDEO_FORMAT_RGB15, NEAREST | BILINEAR | FOURTAP}
+ };
+ static gboolean
+ gst_video_scale_format_supported_for_method (GstVideoFormat format,
+     GstVideoScaleMethod method)
+ {
+   int i;
+   for (i = 0; i < G_N_ELEMENTS (formats_methods_table); ++i) {
+     if (formats_methods_table[i].format == format)
+       return ((formats_methods_table[i].methods & (1 << method)) != 0);
+   }
+   return FALSE;
+ }
+ static gboolean
+ gst_video_scale_transform_supported (GstVideoScale * videoscale,
+     GstVideoScaleMethod method, GstStructure * structure)
+ {
+   const GValue *val;
 -  if (!gst_video_format_parse_caps (c, &fmt, NULL, NULL)) {
++  GstVideoInfo info;
+   gboolean supported = TRUE;
+   GstStructure *s;
+   GstCaps *c;
+   /* we support these methods for all formats */
+   if (method == GST_VIDEO_SCALE_NEAREST || method == GST_VIDEO_SCALE_BILINEAR)
+     return TRUE;
+   /* we need fixed caps if we want to use gst_video_parse_caps() */
+   s = gst_structure_new (gst_structure_get_name (structure),
+       "width", G_TYPE_INT, 1, "height", G_TYPE_INT, 1, NULL);
+   if ((val = gst_structure_get_value (structure, "format"))) {
+     gst_structure_set_value (s, "format", val);
+   } else {
+     if ((val = gst_structure_get_value (structure, "endianness")))
+       gst_structure_set_value (s, "endianness", val);
+     if ((val = gst_structure_get_value (structure, "red_mask")))
+       gst_structure_set_value (s, "red_mask", val);
+     if ((val = gst_structure_get_value (structure, "blue_mask")))
+       gst_structure_set_value (s, "blue_mask", val);
+     if ((val = gst_structure_get_value (structure, "green_mask")))
+       gst_structure_set_value (s, "green_mask", val);
+     if ((val = gst_structure_get_value (structure, "alpha_mask")))
+       gst_structure_set_value (s, "alpha_mask", val);
+     if ((val = gst_structure_get_value (structure, "depth")))
+       gst_structure_set_value (s, "depth", val);
+     if ((val = gst_structure_get_value (structure, "bpp")))
+       gst_structure_set_value (s, "bpp", val);
+   }
+   c = gst_caps_new_full (s, NULL);
 -  } else if (!gst_video_scale_format_supported_for_method (fmt, method)) {
++
++  gst_video_info_init (&info);
++  if (!gst_video_info_from_caps (&info, c)) {
+     GST_ERROR_OBJECT (videoscale, "couldn't parse %" GST_PTR_FORMAT, c);
 -      method, (supported) ? "" : "not ", fmt);
++  } else if (!gst_video_scale_format_supported_for_method (info.finfo->format,
++          method)) {
+     supported = FALSE;
+   }
+   GST_LOG_OBJECT (videoscale, "method %d %ssupported for format %d",
++      method, (supported) ? "" : "not ", info.finfo->format);
+   gst_caps_unref (c);
+   return supported;
+ }
  static GstCaps *
  gst_video_scale_transform_caps (GstBaseTransform * trans,
 -    GstPadDirection direction, GstCaps * caps)
 +    GstPadDirection direction, GstCaps * caps, GstCaps * filter)
  {
+   GstVideoScale *videoscale = GST_VIDEO_SCALE (trans);
+   GstVideoScaleMethod method;
    GstCaps *ret;
    GstStructure *structure;
 -
 -  /* this function is always called with a simple caps */
 -  g_return_val_if_fail (GST_CAPS_IS_SIMPLE (caps), NULL);
 +  gint i, n;
  
    GST_DEBUG_OBJECT (trans,
        "Transforming caps %" GST_PTR_FORMAT " in direction %s", caps,
        (direction == GST_PAD_SINK) ? "sink" : "src");
  
 -  ret = gst_caps_copy (caps);
 -  structure = gst_structure_copy (gst_caps_get_structure (ret, 0));
 -
+   GST_OBJECT_LOCK (videoscale);
+   method = videoscale->method;
+   GST_OBJECT_UNLOCK (videoscale);
 -  if (!gst_video_scale_transform_supported (videoscale, method, structure))
 -    goto format_not_supported;
 +  ret = gst_caps_new_empty ();
 +  n = gst_caps_get_size (caps);
 +  for (i = 0; i < n; i++) {
 +    structure = gst_caps_get_structure (caps, i);
 +
 +    /* If this is already expressed by the existing caps
 +     * skip this structure */
 +    if (i > 0 && gst_caps_is_subset_structure (ret, structure))
 +      continue;
 +
++    if (!gst_video_scale_transform_supported (videoscale, method, structure))
++      goto format_not_supported;
++
 +    structure = gst_structure_copy (structure);
 +    gst_structure_set (structure,
 +        "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
 +        "height", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
 +
 +    /* if pixel aspect ratio, make a range of it */
 +    if (gst_structure_has_field (structure, "pixel-aspect-ratio")) {
 +      gst_structure_set (structure, "pixel-aspect-ratio",
 +          GST_TYPE_FRACTION_RANGE, 1, G_MAXINT, G_MAXINT, 1, NULL);
 +    }
 +    gst_caps_append_structure (ret, structure);
 +  }
  
 -  gst_structure_set (structure,
 -      "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
 -      "height", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
 +  if (filter) {
 +    GstCaps *intersection;
  
 -  /* if pixel aspect ratio, make a range of it */
 -  if (gst_structure_has_field (structure, "pixel-aspect-ratio")) {
 -    gst_structure_set (structure, "pixel-aspect-ratio", GST_TYPE_FRACTION_RANGE,
 -        1, G_MAXINT, G_MAXINT, 1, NULL);
 +    intersection =
 +        gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
 +    gst_caps_unref (ret);
 +    ret = intersection;
    }
 -  gst_caps_append_structure (ret, structure);
  
+ done:
    GST_DEBUG_OBJECT (trans, "returning caps: %" GST_PTR_FORMAT, ret);
  
    return ret;
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -38,14 -38,12 +38,12 @@@ videoscale_get_allowed_caps_for_method 
    GstStructure *s;
    gint i, n;
  
-   templ =
-       gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (scale),
-       "sink");
-   fail_unless (templ != NULL);
-   tmp = gst_pad_template_get_caps (templ);
-   caps = gst_caps_normalize (tmp);
-   gst_caps_unref (tmp);
+   scale = gst_element_factory_make ("videoscale", "vscale");
+   g_object_set (scale, "method", method, NULL);
+   pad = gst_element_get_static_pad (scale, "sink");
 -  caps = gst_pad_get_caps (pad);
++  caps = gst_pad_query_caps (pad, NULL);
+   gst_object_unref (pad);
+   gst_object_unref (scale);
  
    n = gst_caps_get_size (caps);
    ret = g_new0 (GstCaps *, n + 1);
@@@ -57,8 -56,6 +56,7 @@@
    }
  
    gst_caps_unref (caps);
-   gst_object_unref (scale);
 +
    return ret;
  }
  
@@@ -225,45 -219,40 +223,44 @@@ test_passthrough (int method
    while (*p) {
      GstCaps *caps = *p;
  
 -    /* skip formats that ffmpegcolorspace can't handle */
 -    if (caps_are_64bpp (caps))
 -      goto skip;
 -
 -    GST_DEBUG ("Running test for caps '%" GST_PTR_FORMAT "'"
 -        " from %dx%u to %dx%d with method %d", caps, src_width, src_height,
 -        dest_width, dest_height, method);
 -    run_test (caps, src_width, src_height,
 -        dest_width, dest_height, method,
 -        G_CALLBACK (on_src_handoff_passthrough), &src_buffers,
 -        G_CALLBACK (on_sink_handoff_passthrough), &sink_buffers);
 -
 -    fail_unless (src_buffers && sink_buffers);
 -    fail_unless_equals_int (g_list_length (src_buffers),
 -        g_list_length (sink_buffers));
 -
 -    for (l1 = src_buffers, l2 = sink_buffers; l1 && l2;
 -        l1 = l1->next, l2 = l2->next) {
 -      GstBuffer *a = l1->data;
 -      GstBuffer *b = l2->data;
 -
 -      fail_unless_equals_int (GST_BUFFER_SIZE (a), GST_BUFFER_SIZE (b));
 -      fail_unless (GST_BUFFER_DATA (a) == GST_BUFFER_DATA (b));
 -
 -      gst_buffer_unref (a);
 -      gst_buffer_unref (b);
 +    for (method = 0; method < 3; method++) {
 +      /* skip formats that videoconvert can't handle */
 +      if (caps_is_supported (caps))
 +        continue;
 +
 +      GST_DEBUG ("Running test for caps '%" GST_PTR_FORMAT "'"
 +          " from %dx%u to %dx%d with method %d", caps, src_width, src_height,
 +          dest_width, dest_height, method);
 +      run_test (caps, src_width, src_height,
 +          dest_width, dest_height, method,
 +          G_CALLBACK (on_src_handoff_passthrough), &src_buffers,
 +          G_CALLBACK (on_sink_handoff_passthrough), &sink_buffers);
 +
 +      fail_unless (src_buffers && sink_buffers);
 +      fail_unless_equals_int (g_list_length (src_buffers),
 +          g_list_length (sink_buffers));
 +
 +      for (l1 = src_buffers, l2 = sink_buffers; l1 && l2;
 +          l1 = l1->next, l2 = l2->next) {
 +        GstBuffer *a = l1->data;
 +        GstBuffer *b = l2->data;
 +        GstMapInfo mapa, mapb;
 +
 +        gst_buffer_map (a, &mapa, GST_MAP_READ);
 +        gst_buffer_map (b, &mapb, GST_MAP_READ);
 +        fail_unless_equals_int (mapa.size, mapb.size);
 +        fail_unless (mapa.data == mapb.data);
 +        gst_buffer_unmap (b, &mapb);
 +        gst_buffer_unmap (a, &mapa);
 +
 +        gst_buffer_unref (a);
 +        gst_buffer_unref (b);
 +      }
 +      g_list_free (src_buffers);
 +      src_buffers = NULL;
 +      g_list_free (sink_buffers);
 +      sink_buffers = NULL;
      }
 -    g_list_free (src_buffers);
 -    src_buffers = NULL;
 -    g_list_free (sink_buffers);
 -    sink_buffers = NULL;
 -
 -  skip:
--
      gst_caps_unref (caps);
      p++;
    }
@@@ -868,10 -913,9 +924,11 @@@ videoscale_suite (void
    tcase_add_test (tc_chain, test_upscale_1x240_640x480_method_0);
    tcase_add_test (tc_chain, test_upscale_1x240_640x480_method_1);
    tcase_add_test (tc_chain, test_upscale_1x240_640x480_method_2);
+   tcase_add_test (tc_chain, test_upscale_1x240_640x480_method_3);
    tcase_add_test (tc_chain, test_negotiation);
 +#if 0
    tcase_add_test (tc_chain, test_reverse_negotiation);
 +#endif
    tcase_add_test (tc_chain, test_basetransform_negotiation);
  
    GST_ERROR ("FIXME: test 64-bpp formats as well");
@@@ -44,8 -47,9 +47,9 @@@
  #include <gdk/gdkquartzwindow.h>
  #endif
  
 -#include <gst/interfaces/xoverlay.h>
 +#include <gst/video/videooverlay.h>
++#include <gst/video/colorbalance.h>
  #include <gst/interfaces/navigation.h>
 -#include <gst/interfaces/colorbalance.h>
  
  GST_DEBUG_CATEGORY_STATIC (seek_debug);
  #define GST_CAT_DEFAULT (seek_debug)
@@@ -137,12 -97,115 +97,115 @@@ typedef struc
    GstElementFactory *factory;
  } VisEntry;
  
- static GArray *vis_entries;
+ typedef struct
+ {
+   /* GTK widgets */
+   GtkWidget *window;
+   GtkWidget *video_combo, *audio_combo, *text_combo, *vis_combo;
+   GtkWidget *video_window;
+   GtkWidget *vis_checkbox, *video_checkbox, *audio_checkbox;
+   GtkWidget *text_checkbox, *mute_checkbox, *volume_spinbutton;
+   GtkWidget *soft_volume_checkbox, *native_audio_checkbox,
+       *native_video_checkbox;
+   GtkWidget *download_checkbox, *buffering_checkbox, *deinterlace_checkbox;
+   GtkWidget *soft_colorbalance_checkbox;
+   GtkWidget *video_sink_entry, *audio_sink_entry, *text_sink_entry;
+   GtkWidget *buffer_size_entry, *buffer_duration_entry;
+   GtkWidget *ringbuffer_maxsize_entry, *connection_speed_entry;
+   GtkWidget *av_offset_entry, *subtitle_encoding_entry;
+   GtkWidget *subtitle_fontdesc_button;
+   GtkWidget *seek_format_combo, *seek_position_label, *seek_duration_label;
+   GtkWidget *seek_entry;
+   GtkWidget *seek_scale, *statusbar;
+   guint status_id;
+   GtkWidget *step_format_combo, *step_amount_spinbutton, *step_rate_spinbutton;
+   GtkWidget *shuttle_scale;
+   GtkWidget *contrast_scale, *brightness_scale, *hue_scale, *saturation_scale;
+   struct
+   {
+     GstNavigationCommand cmd;
+     GtkWidget *button;
+   } navigation_buttons[14];
+   guintptr embed_xid;
+   /* GStreamer pipeline */
+   GstElement *pipeline;
+   GstElement *navigation_element;
+   GstElement *colorbalance_element;
 -  GstElement *xoverlay_element;
++  GstElement *overlay_element;
+   /* Settings */
+   gboolean accurate_seek;
+   gboolean keyframe_seek;
+   gboolean loop_seek;
+   gboolean flush_seek;
+   gboolean scrub;
+   gboolean play_scrub;
+   gboolean skip_seek;
+   gdouble rate;
+   /* From commandline parameters */
+   gboolean stats;
+   gboolean verbose;
+   const gchar *pipeline_spec;
+   gint pipeline_type;
+   GList *paths, *current_path;
+   GList *sub_paths, *current_sub_path;
+   gchar *audiosink_str, *videosink_str;
+   /* Internal state */
+   gint64 position, duration;
+   gboolean is_live;
+   gboolean buffering;
+   GstBufferingMode mode;
+   gint64 buffering_left;
+   GstState state;
+   guint update_id;
+   guint seek_timeout_id;
+   gulong changed_id;
+   guint fill_id;
+   gboolean need_streams;
+   gint n_video, n_audio, n_text;
 -  GStaticMutex state_mutex;
++  GMutex state_mutex;
+   GArray *vis_entries;          /* Array of VisEntry structs */
+   gboolean shuttling;
+   gdouble shuttle_rate;
+   gdouble play_rate;
+   const GstFormatDefinition *seek_format;
+   GList *formats;
+ } SeekApp;
  
- static void clear_streams (GstElement * pipeline);
+ static void clear_streams (SeekApp * app);
+ static void find_interface_elements (SeekApp * app);
  static void volume_notify_cb (GstElement * pipeline, GParamSpec * arg,
-     gpointer user_dat);
- static void find_navigation_element (void);
+     SeekApp * app);
+ static void mute_notify_cb (GstElement * pipeline, GParamSpec * arg,
+     SeekApp * app);
+ static void video_sink_activate_cb (GtkEntry * entry, SeekApp * app);
+ static void text_sink_activate_cb (GtkEntry * entry, SeekApp * app);
+ static void audio_sink_activate_cb (GtkEntry * entry, SeekApp * app);
+ static void buffer_size_activate_cb (GtkEntry * entry, SeekApp * app);
+ static void buffer_duration_activate_cb (GtkEntry * entry, SeekApp * app);
+ static void ringbuffer_maxsize_activate_cb (GtkEntry * entry, SeekApp * app);
+ static void connection_speed_activate_cb (GtkEntry * entry, SeekApp * app);
+ static void av_offset_activate_cb (GtkEntry * entry, SeekApp * app);
+ static void subtitle_encoding_activate_cb (GtkEntry * entry, SeekApp * app);
  
  /* pipeline construction */
  
@@@ -193,39 -250,31 +250,31 @@@ set_uri_property (GObject * object, con
    }
  }
  
- static GstElement *
- construct_playbin (const gchar * name, const gchar * location)
+ static void
+ playbin_set_uri (GstElement * playbin, const gchar * location,
+     const gchar * sub_location)
  {
-   GstElement *player;
-   GstElement *avsink;
-   player = gst_element_factory_make (name, "player");
-   g_assert (player);
-   playerbin_set_uri (player, location);
-   seekable_elements = g_list_prepend (seekable_elements, player);
-   avsink = gst_element_factory_make_or_warn (opt_audiosink_str, "a_sink");
-   if (avsink)
-     g_object_set (player, "audio-sink", avsink, NULL);
-   avsink = gst_element_factory_make_or_warn (opt_videosink_str, "v_sink");
-   if (avsink)
-     g_object_set (player, "video-sink", avsink, NULL);
-   return player;
+   set_uri_property (G_OBJECT (playbin), "uri", location);
+   set_uri_property (G_OBJECT (playbin), "suburi", sub_location);
  }
  
- static GstElement *
- make_playbin_pipeline (const gchar * location)
+ static void
 -make_playbin2_pipeline (SeekApp * app, const gchar * location)
++make_playbin_pipeline (SeekApp * app, const gchar * location)
  {
-   GstElement *pipeline = construct_playbin ("playbin", location);
+   GstElement *pipeline;
 -  app->pipeline = pipeline = gst_element_factory_make ("playbin2", "playbin2");
++  app->pipeline = pipeline = gst_element_factory_make ("playbin", "playbin");
+   g_assert (pipeline);
+   playbin_set_uri (pipeline, location,
+       app->current_sub_path ? app->current_sub_path->data : NULL);
  
-   /* FIXME: this is not triggered, playbin is not forwarding it from the sink */
    g_signal_connect (pipeline, "notify::volume", G_CALLBACK (volume_notify_cb),
-       NULL);
-   return pipeline;
+       app);
+   g_signal_connect (pipeline, "notify::mute", G_CALLBACK (mute_notify_cb), app);
+   app->navigation_element = GST_ELEMENT (gst_object_ref (pipeline));
+   app->colorbalance_element = GST_ELEMENT (gst_object_ref (pipeline));
  }
  
  #ifndef GST_DISABLE_PARSE
@@@ -250,8 -292,8 +292,8 @@@ typedef struc
  }
  Pipeline;
  
- static Pipeline pipelines[] = {
+ static const Pipeline pipelines[] = {
 -  {"playbin2", make_playbin2_pipeline},
 +  {"playbin", make_playbin_pipeline},
  #ifndef GST_DISABLE_PARSE
    {"parse-launch", make_parselaunch_pipeline},
  #endif
@@@ -299,60 -337,47 +337,47 @@@ static seek_format seek_formats[] = 
    {NULL, 0},
  };
  
G_GNUC_UNUSED static void
- query_positions_elems (void)
+ static void
+ query_positions (SeekApp * app)
  {
-   GList *walk = seekable_elements;
-   while (walk) {
-     GstElement *element = GST_ELEMENT (walk->data);
-     gint i = 0;
+   gint i = 0;
  
-     g_print ("positions %8.8s: ", GST_ELEMENT_NAME (element));
-     while (seek_formats[i].name) {
-       gint64 position, total;
-       GstFormat format;
+   g_print ("positions %8.8s: ", GST_ELEMENT_NAME (app->pipeline));
+   while (seek_formats[i].name) {
+     gint64 position, total;
+     GstFormat format;
  
-       format = seek_formats[i].format;
+     format = seek_formats[i].format;
  
-       if (gst_element_query_position (element, format, &position) &&
-           gst_element_query_duration (element, format, &total)) {
-         g_print ("%s %13" G_GINT64_FORMAT " / %13" G_GINT64_FORMAT " | ",
-             seek_formats[i].name, position, total);
-       } else {
-         g_print ("%s %13.13s / %13.13s | ", seek_formats[i].name, "*NA*",
-             "*NA*");
-       }
-       i++;
 -    if (gst_element_query_position (app->pipeline, &format, &position) &&
 -        gst_element_query_duration (app->pipeline, &format, &total)) {
++    if (gst_element_query_position (app->pipeline, format, &position) &&
++        gst_element_query_duration (app->pipeline, format, &total)) {
+       g_print ("%s %13" G_GINT64_FORMAT " / %13" G_GINT64_FORMAT " | ",
+           seek_formats[i].name, position, total);
+     } else {
+       g_print ("%s %13.13s / %13.13s | ", seek_formats[i].name, "*NA*", "*NA*");
      }
-     g_print (" %s\n", GST_ELEMENT_NAME (element));
-     walk = g_list_next (walk);
+     i++;
    }
+   g_print (" %s\n", GST_ELEMENT_NAME (app->pipeline));
  }
  
- static gboolean start_seek (GtkWidget * widget, GdkEventButton * event,
-     gpointer user_data);
- static gboolean stop_seek (GtkWidget * widget, GdkEventButton * event,
-     gpointer user_data);
- static void seek_cb (GtkWidget * widget);
+ static gboolean start_seek (GtkRange * range, GdkEventButton * event,
+     SeekApp * app);
+ static gboolean stop_seek (GtkRange * range, GdkEventButton * event,
+     SeekApp * app);
+ static void seek_cb (GtkRange * range, SeekApp * app);
  
  static void
- set_scale (gdouble value)
+ set_scale (SeekApp * app, gdouble value)
  {
-   g_signal_handlers_block_by_func (hscale, (void *) start_seek,
-       (void *) pipeline);
-   g_signal_handlers_block_by_func (hscale, (void *) stop_seek,
-       (void *) pipeline);
-   g_signal_handlers_block_by_func (hscale, (void *) seek_cb, (void *) pipeline);
-   gtk_adjustment_set_value (adjustment, value);
-   g_signal_handlers_unblock_by_func (hscale, (void *) start_seek,
-       (void *) pipeline);
-   g_signal_handlers_unblock_by_func (hscale, (void *) stop_seek,
-       (void *) pipeline);
-   g_signal_handlers_unblock_by_func (hscale, (void *) seek_cb,
-       (void *) pipeline);
-   gtk_widget_queue_draw (hscale);
+   g_signal_handlers_block_by_func (app->seek_scale, start_seek, app);
+   g_signal_handlers_block_by_func (app->seek_scale, stop_seek, app);
+   g_signal_handlers_block_by_func (app->seek_scale, seek_cb, app);
+   gtk_range_set_value (GTK_RANGE (app->seek_scale), value);
+   g_signal_handlers_unblock_by_func (app->seek_scale, start_seek, app);
+   g_signal_handlers_unblock_by_func (app->seek_scale, stop_seek, app);
+   g_signal_handlers_unblock_by_func (app->seek_scale, seek_cb, app);
+   gtk_widget_queue_draw (app->seek_scale);
  }
  
  static gboolean
@@@ -399,29 -422,41 +422,41 @@@ update_fill (SeekApp * app
  }
  
  static gboolean
- update_scale (gpointer data)
+ update_scale (SeekApp * app)
  {
-   if (seekable_elements) {
-     GstElement *element = GST_ELEMENT (seekable_elements->data);
+   GstFormat format = GST_FORMAT_TIME;
+   gint64 seek_pos, seek_dur;
+   gchar *str;
  
-     gst_element_query_position (element, GST_FORMAT_TIME, &position);
-     gst_element_query_duration (element, GST_FORMAT_TIME, &duration);
-   }
+   //position = 0;
+   //duration = 0;
  
-   if (stats) {
-     query_positions_elems ();
-   }
 -  gst_element_query_position (app->pipeline, &format, &app->position);
 -  gst_element_query_duration (app->pipeline, &format, &app->duration);
++  gst_element_query_position (app->pipeline, format, &app->position);
++  gst_element_query_duration (app->pipeline, format, &app->duration);
+   if (app->stats)
+     query_positions (app);
  
-   if (position >= duration)
-     duration = position;
+   if (app->position >= app->duration)
+     app->duration = app->position;
  
-   if (duration > 0) {
-     set_scale (position * N_GRAD / duration);
+   if (app->duration > 0) {
+     set_scale (app, app->position * N_GRAD / app->duration);
    }
  
-   /* FIXME: see make_playerbin2_pipeline() and volume_notify_cb() */
-   if (pipeline_type == 16) {
-     g_object_notify (G_OBJECT (pipeline), "volume");
+   if (app->seek_format) {
+     format = app->seek_format->value;
+     seek_pos = seek_dur = -1;
 -    gst_element_query_position (app->pipeline, &format, &seek_pos);
 -    gst_element_query_duration (app->pipeline, &format, &seek_dur);
++    gst_element_query_position (app->pipeline, format, &seek_pos);
++    gst_element_query_duration (app->pipeline, format, &seek_dur);
+     str = g_strdup_printf ("%" G_GINT64_FORMAT, seek_pos);
+     gtk_label_set_text (GTK_LABEL (app->seek_position_label), str);
+     g_free (str);
+     str = g_strdup_printf ("%" G_GINT64_FORMAT, seek_dur);
+     gtk_label_set_text (GTK_LABEL (app->seek_duration_label), str);
+     g_free (str);
    }
  
    return TRUE;
@@@ -662,15 -728,15 +728,15 @@@ failed
  }
  
  static void
- pause_cb (GtkButton * button, gpointer data)
+ pause_cb (GtkButton * button, SeekApp * app)
  {
-   g_mutex_lock (&state_mutex);
-   if (state != GST_STATE_PAUSED) {
 -  g_static_mutex_lock (&app->state_mutex);
++  g_mutex_lock (&app->state_mutex);
+   if (app->state != GST_STATE_PAUSED) {
      GstStateChangeReturn ret;
  
-     gtk_statusbar_pop (GTK_STATUSBAR (statusbar), status_id);
+     gtk_statusbar_pop (GTK_STATUSBAR (app->statusbar), app->status_id);
      g_print ("PAUSE pipeline\n");
-     ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
+     ret = gst_element_set_state (app->pipeline, GST_STATE_PAUSED);
      switch (ret) {
        case GST_STATE_CHANGE_FAILURE:
          goto failed;
          break;
      }
  
-     state = GST_STATE_PAUSED;
-     gtk_statusbar_push (GTK_STATUSBAR (statusbar), status_id, "Paused");
+     app->state = GST_STATE_PAUSED;
+     gtk_statusbar_push (GTK_STATUSBAR (app->statusbar), app->status_id,
+         "Paused");
    }
-   g_mutex_unlock (&state_mutex);
 -  g_static_mutex_unlock (&app->state_mutex);
++  g_mutex_unlock (&app->state_mutex);
  
    return;
  
  failed:
    {
-     g_mutex_unlock (&state_mutex);
 -    g_static_mutex_unlock (&app->state_mutex);
++    g_mutex_unlock (&app->state_mutex);
      g_print ("PAUSE failed\n");
-     gtk_statusbar_push (GTK_STATUSBAR (statusbar), status_id, "Pause failed");
+     gtk_statusbar_push (GTK_STATUSBAR (app->statusbar), app->status_id,
+         "Pause failed");
    }
  }
  
@@@ -704,55 -772,40 +772,40 @@@ stop_cb (GtkButton * button, SeekApp * 
      gint i;
  
      g_print ("READY pipeline\n");
-     gtk_statusbar_pop (GTK_STATUSBAR (statusbar), status_id);
+     gtk_statusbar_pop (GTK_STATUSBAR (app->statusbar), app->status_id);
  
-     g_mutex_lock (&state_mutex);
-     ret = gst_element_set_state (pipeline, STOP_STATE);
 -    g_static_mutex_lock (&app->state_mutex);
++    g_mutex_lock (&app->state_mutex);
+     ret = gst_element_set_state (app->pipeline, STOP_STATE);
      if (ret == GST_STATE_CHANGE_FAILURE)
        goto failed;
  
-     state = STOP_STATE;
-     gtk_statusbar_push (GTK_STATUSBAR (statusbar), status_id, "Stopped");
-     gtk_widget_queue_draw (video_window);
-     is_live = FALSE;
-     buffering = FALSE;
-     set_update_scale (FALSE);
-     set_scale (0.0);
-     set_update_fill (FALSE);
-     if (pipeline_type == 16)
-       clear_streams (pipeline);
-     g_mutex_unlock (&state_mutex);
- #if 0
-     /* if one uses parse_launch, play, stop and play again it fails as all the
-      * pads after the demuxer can't be reconnected
-      */
-     if (!strcmp (pipelines[pipeline_type].name, "parse-launch")) {
-       gst_element_set_state (pipeline, GST_STATE_NULL);
-       gst_object_unref (pipeline);
-       g_list_free (seekable_elements);
-       seekable_elements = NULL;
-       pipeline = pipelines[pipeline_type].func (pipeline_spec);
-       g_assert (pipeline);
-       gst_element_set_state (pipeline, STOP_STATE);
-       connect_bus_signals (pipeline);
-     }
- #endif
-     gtk_widget_set_sensitive (GTK_WIDGET (hscale), TRUE);
-     for (i = 0; i < G_N_ELEMENTS (navigation_buttons); i++)
-       gtk_widget_set_sensitive (navigation_buttons[i].button, FALSE);
+     app->state = STOP_STATE;
+     gtk_statusbar_push (GTK_STATUSBAR (app->statusbar), app->status_id,
+         "Stopped");
+     gtk_widget_queue_draw (app->video_window);
+     app->is_live = FALSE;
+     app->buffering = FALSE;
+     set_update_scale (app, FALSE);
+     set_scale (app, 0.0);
+     set_update_fill (app, FALSE);
+     if (app->pipeline_type == 0)
+       clear_streams (app);
 -    g_static_mutex_unlock (&app->state_mutex);
++    g_mutex_unlock (&app->state_mutex);
+     gtk_widget_set_sensitive (GTK_WIDGET (app->seek_scale), TRUE);
+     for (i = 0; i < G_N_ELEMENTS (app->navigation_buttons); i++)
+       gtk_widget_set_sensitive (app->navigation_buttons[i].button, FALSE);
    }
    return;
  
  failed:
    {
-     g_mutex_unlock (&state_mutex);
 -    g_static_mutex_unlock (&app->state_mutex);
++    g_mutex_unlock (&app->state_mutex);
      g_print ("STOP failed\n");
-     gtk_statusbar_push (GTK_STATUSBAR (statusbar), status_id, "Stop failed");
+     gtk_statusbar_push (GTK_STATUSBAR (app->statusbar), app->status_id,
+         "Stop failed");
    }
  }
  
@@@ -960,18 -1071,19 +1071,19 @@@ update_streams (SeekApp * app
      gboolean state;
  
      /* remove previous info */
-     clear_streams (GST_ELEMENT_CAST (pipeline));
+     clear_streams (app);
  
 -    /* here we get and update the different streams detected by playbin2 */
 +    /* here we get and update the different streams detected by playbin */
-     g_object_get (pipeline, "n-video", &n_video, NULL);
-     g_object_get (pipeline, "n-audio", &n_audio, NULL);
-     g_object_get (pipeline, "n-text", &n_text, NULL);
+     g_object_get (app->pipeline, "n-video", &app->n_video, NULL);
+     g_object_get (app->pipeline, "n-audio", &app->n_audio, NULL);
+     g_object_get (app->pipeline, "n-text", &app->n_text, NULL);
  
-     g_print ("video %d, audio %d, text %d\n", n_video, n_audio, n_text);
+     g_print ("video %d, audio %d, text %d\n", app->n_video, app->n_audio,
+         app->n_text);
  
      active_idx = 0;
-     for (i = 0; i < n_video; i++) {
-       g_signal_emit_by_name (pipeline, "get-video-tags", i, &tags);
+     for (i = 0; i < app->n_video; i++) {
+       g_signal_emit_by_name (app->pipeline, "get-video-tags", i, &tags);
        if (tags) {
          str = gst_structure_to_string ((GstStructure *) tags);
          g_print ("video %d: %s\n", i, str);
@@@ -1088,10 -1206,10 +1206,10 @@@ init_visualization_features (SeekApp * 
  {
    GList *list, *walk;
  
-   vis_entries = g_array_new (FALSE, FALSE, sizeof (VisEntry));
+   app->vis_entries = g_array_new (FALSE, FALSE, sizeof (VisEntry));
  
 -  list = gst_registry_feature_filter (gst_registry_get_default (),
 +  list = gst_registry_feature_filter (gst_registry_get (),
-       filter_features, FALSE, NULL);
+       filter_vis_features, FALSE, NULL);
  
    for (walk = list; walk; walk = g_list_next (walk)) {
      VisEntry entry;
@@@ -1123,8 -1241,8 +1241,8 @@@ vis_combo_cb (GtkComboBox * combo, Seek
      if (!element)
        return;
  
 -    /* set vis plugin for playbin2 */
 +    /* set vis plugin for playbin */
-     g_object_set (pipeline, "vis-plugin", element, NULL);
+     g_object_set (app->pipeline, "vis-plugin", element, NULL);
    }
  }
  
@@@ -1158,26 -1277,60 +1277,58 @@@ volume_notify_idle_cb (SeekApp * app
  }
  
  static void
- shot_cb (GtkButton * button, gpointer data)
+ volume_notify_cb (GstElement * pipeline, GParamSpec * arg, SeekApp * app)
+ {
+   /* Do this from the main thread */
+   g_idle_add ((GSourceFunc) volume_notify_idle_cb, app);
+ }
+ static gboolean
+ mute_notify_idle_cb (SeekApp * app)
+ {
+   gboolean cur_mute, new_mute;
+   g_object_get (app->pipeline, "mute", &new_mute, NULL);
+   cur_mute =
+       gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (app->mute_checkbox));
+   if (cur_mute != new_mute) {
+     g_signal_handlers_block_by_func (app->mute_checkbox, mute_toggle_cb, app);
+     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app->mute_checkbox),
+         new_mute);
+     g_signal_handlers_unblock_by_func (app->mute_checkbox, mute_toggle_cb, app);
+   }
+   return FALSE;
+ }
+ static void
+ mute_notify_cb (GstElement * pipeline, GParamSpec * arg, SeekApp * app)
+ {
+   /* Do this from the main thread */
+   g_idle_add ((GSourceFunc) mute_notify_idle_cb, app);
+ }
+ static void
+ shot_cb (GtkButton * button, SeekApp * app)
  {
 -  GstBuffer *buffer;
 +  GstSample *sample = NULL;
    GstCaps *caps;
  
 +  GST_DEBUG ("taking snapshot");
 +
    /* convert to our desired format (RGB24) */
 -  caps = gst_caps_new_simple ("video/x-raw-rgb",
 -      "bpp", G_TYPE_INT, 24, "depth", G_TYPE_INT, 24,
 +  caps = gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING, "RGB",
        /* Note: we don't ask for a specific width/height here, so that
         * videoscale can adjust dimensions from a non-1/1 pixel aspect
         * ratio to a 1/1 pixel-aspect-ratio */
 -      "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1,
 -      "endianness", G_TYPE_INT, G_BIG_ENDIAN,
 -      "red_mask", G_TYPE_INT, 0xff0000,
 -      "green_mask", G_TYPE_INT, 0x00ff00,
 -      "blue_mask", G_TYPE_INT, 0x0000ff, NULL);
 -
 -  /* convert the latest frame to the requested format */
 -  g_signal_emit_by_name (app->pipeline, "convert-frame", caps, &buffer);
 +      "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1, NULL);
 +
 +  /* convert the latest sample to the requested format */
-   g_signal_emit_by_name (pipeline, "convert-sample", caps, &sample);
++  g_signal_emit_by_name (app->pipeline, "convert-sample", caps, &sample);
    gst_caps_unref (caps);
  
 -  if (buffer) {
 +  if (sample) {
 +    GstBuffer *buffer;
      GstCaps *caps;
      GstStructure *s;
      gboolean res;
@@@ -1333,10 -1479,10 +1481,10 @@@ msg_sync_step_done (GstBus * bus, GstMe
      return;
    }
  
-   if (g_mutex_trylock (&state_mutex)) {
-     if (shuttling)
-       do_shuttle (element);
-     g_mutex_unlock (&state_mutex);
 -  if (g_static_mutex_trylock (&app->state_mutex)) {
++  if (g_mutex_trylock (&app->state_mutex)) {
+     if (app->shuttling)
+       do_shuttle (app);
 -    g_static_mutex_unlock (&app->state_mutex);
++    g_mutex_unlock (&app->state_mutex);
    } else {
      /* ignore step messages that come while we are doing a state change */
      g_print ("state change is busy\n");
@@@ -1430,17 -1577,166 +1579,171 @@@ shuttle_value_changed (GtkRange * range
  }
  
  static void
- msg_async_done (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
+ colorbalance_value_changed (GtkRange * range, SeekApp * app)
+ {
+   const gchar *label;
+   gdouble val;
+   gint ival;
+   GstColorBalanceChannel *channel = NULL;
+   const GList *channels, *l;
+   if (range == GTK_RANGE (app->contrast_scale))
+     label = "CONTRAST";
+   else if (range == GTK_RANGE (app->brightness_scale))
+     label = "BRIGHTNESS";
+   else if (range == GTK_RANGE (app->hue_scale))
+     label = "HUE";
+   else if (range == GTK_RANGE (app->saturation_scale))
+     label = "SATURATION";
+   else
+     g_assert_not_reached ();
+   val = gtk_range_get_value (range);
+   g_print ("colorbalance %s value changed %lf\n", label, val / N_GRAD);
+   if (!app->colorbalance_element) {
+     find_interface_elements (app);
+     if (!app->colorbalance_element)
+       return;
+   }
+   channels =
+       gst_color_balance_list_channels (GST_COLOR_BALANCE
+       (app->colorbalance_element));
+   for (l = channels; l; l = l->next) {
+     GstColorBalanceChannel *tmp = l->data;
+     if (g_strrstr (tmp->label, label)) {
+       channel = tmp;
+       break;
+     }
+   }
+   if (!channel)
+     return;
+   ival =
+       (gint) (0.5 + channel->min_value +
+       (val / N_GRAD) * ((gdouble) channel->max_value -
+           (gdouble) channel->min_value));
+   gst_color_balance_set_value (GST_COLOR_BALANCE (app->colorbalance_element),
+       channel, ival);
+ }
+ static void
+ seek_format_changed_cb (GtkComboBox * box, SeekApp * app)
+ {
+   gchar *format_str;
+   GList *l;
+   const GstFormatDefinition *format = NULL;
+   format_str = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (box));
+   for (l = app->formats; l; l = l->next) {
+     const GstFormatDefinition *tmp = l->data;
+     if (g_strcmp0 (tmp->nick, format_str) == 0) {
+       format = tmp;
+       break;
+     }
+   }
+   if (!format)
+     goto done;
+   app->seek_format = format;
+   update_scale (app);
+ done:
+   g_free (format_str);
+ }
+ static void
+ update_formats (SeekApp * app)
+ {
+   GstIterator *it;
+   gboolean done;
+   GList *l;
 -  gpointer item;
++  GValue item = { 0, };
+   gchar *selected;
+   gint selected_idx = 0, i;
+   selected =
+       gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT
+       (app->seek_format_combo));
+   if (selected == NULL)
+     selected = g_strdup ("time");
+   it = gst_format_iterate_definitions ();
+   done = FALSE;
+   g_list_free (app->formats);
+   app->formats = NULL;
+   while (!done) {
+     switch (gst_iterator_next (it, &item)) {
 -      case GST_ITERATOR_OK:
 -        app->formats = g_list_prepend (app->formats, item);
++      case GST_ITERATOR_OK:{
++        GstFormatDefinition *def = g_value_get_pointer (&item);
++
++        app->formats = g_list_prepend (app->formats, def);
++        g_value_reset (&item);
+         break;
++      }
+       case GST_ITERATOR_RESYNC:
+         g_list_free (app->formats);
+         app->formats = NULL;
+         gst_iterator_resync (it);
+         break;
+       case GST_ITERATOR_ERROR:
+       case GST_ITERATOR_DONE:
+       default:
+         done = TRUE;
+         break;
+     }
+   }
++  g_value_unset (&item);
+   app->formats = g_list_reverse (app->formats);
+   gst_iterator_free (it);
+   g_signal_handlers_block_by_func (app->seek_format_combo,
+       seek_format_changed_cb, app);
+   gtk_combo_box_text_remove_all (GTK_COMBO_BOX_TEXT (app->seek_format_combo));
+   for (i = 0, l = app->formats; l; l = l->next, i++) {
+     const GstFormatDefinition *def = l->data;
+     gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (app->seek_format_combo),
+         def->nick);
+     if (g_strcmp0 (def->nick, selected) == 0)
+       selected_idx = i;
+   }
+   g_signal_handlers_unblock_by_func (app->seek_format_combo,
+       seek_format_changed_cb, app);
+   gtk_combo_box_set_active (GTK_COMBO_BOX (app->seek_format_combo),
+       selected_idx);
+   g_free (selected);
+ }
+ static void
+ msg_async_done (GstBus * bus, GstMessage * message, SeekApp * app)
  {
    GST_DEBUG ("async done");
+   /* Now query all available GstFormats */
+   update_formats (app);
    /* when we get ASYNC_DONE we can query position, duration and other
     * properties */
-   update_scale (pipeline);
+   update_scale (app);
  
    /* update the available streams */
-   update_streams (pipeline);
+   update_streams (app);
  
-   find_navigation_element ();
+   find_interface_elements (app);
  }
  
  static void
@@@ -1606,30 -1904,105 +1911,106 @@@ msg_clock_lost (GstBus * bus, GstMessag
    }
  }
  
- static GstElement *navigation_element = NULL;
+ static gboolean
+ is_valid_color_balance_element (GstElement * element)
+ {
+   GstColorBalance *bal = GST_COLOR_BALANCE (element);
+   gboolean have_brightness = FALSE;
+   gboolean have_contrast = FALSE;
+   gboolean have_hue = FALSE;
+   gboolean have_saturation = FALSE;
+   const GList *channels, *l;
+   channels = gst_color_balance_list_channels (bal);
+   for (l = channels; l; l = l->next) {
+     GstColorBalanceChannel *ch = l->data;
+     if (g_strrstr (ch->label, "BRIGHTNESS"))
+       have_brightness = TRUE;
+     else if (g_strrstr (ch->label, "CONTRAST"))
+       have_contrast = TRUE;
+     else if (g_strrstr (ch->label, "HUE"))
+       have_hue = TRUE;
+     else if (g_strrstr (ch->label, "SATURATION"))
+       have_saturation = TRUE;
+   }
+   return have_brightness && have_contrast && have_hue && have_saturation;
+ }
  
  static void
- find_navigation_element (void)
+ find_interface_elements (SeekApp * app)
  {
-   GstElement *video_sink;
+   GstIterator *it;
 -  gpointer item;
++  GValue item = { 0, };
+   gboolean done = FALSE, hardware = FALSE;
  
-   g_object_get (pipeline, "video-sink", &video_sink, NULL);
-   if (!video_sink)
+   if (app->pipeline_type == 0)
      return;
  
-   if (navigation_element)
-     gst_object_unref (navigation_element);
+   if (app->navigation_element)
+     gst_object_unref (app->navigation_element);
+   app->navigation_element = NULL;
+   if (app->colorbalance_element)
+     gst_object_unref (app->colorbalance_element);
+   app->colorbalance_element = NULL;
+   app->navigation_element =
+       gst_bin_get_by_interface (GST_BIN (app->pipeline), GST_TYPE_NAVIGATION);
+   it = gst_bin_iterate_all_by_interface (GST_BIN (app->pipeline),
+       GST_TYPE_COLOR_BALANCE);
+   while (!done) {
+     switch (gst_iterator_next (it, &item)) {
+       case GST_ITERATOR_OK:{
 -        GstElement *element = GST_ELEMENT (item);
++        GstElement *element = GST_ELEMENT (g_value_get_object (&item));
+         if (is_valid_color_balance_element (element)) {
+           if (!app->colorbalance_element) {
+             app->colorbalance_element =
+                 GST_ELEMENT_CAST (gst_object_ref (element));
+             hardware =
+                 (gst_color_balance_get_balance_type (GST_COLOR_BALANCE
+                     (element)) == GST_COLOR_BALANCE_HARDWARE);
+           } else if (!hardware) {
+             gboolean tmp =
+                 (gst_color_balance_get_balance_type (GST_COLOR_BALANCE
+                     (element)) == GST_COLOR_BALANCE_HARDWARE);
+             if (tmp) {
+               if (app->colorbalance_element)
+                 gst_object_unref (app->colorbalance_element);
+               app->colorbalance_element =
+                   GST_ELEMENT_CAST (gst_object_ref (element));
+               hardware = TRUE;
+             }
+           }
+         }
  
-   if (GST_IS_NAVIGATION (video_sink)) {
-     navigation_element = gst_object_ref (video_sink);
-   } else if (GST_IS_BIN (video_sink)) {
-     navigation_element =
-         gst_bin_get_by_interface (GST_BIN (video_sink), GST_TYPE_NAVIGATION);
-   } else {
-     navigation_element = NULL;
 -        gst_object_unref (element);
++        g_value_reset (&item);
+         if (hardware && app->colorbalance_element)
+           done = TRUE;
+         break;
+       }
+       case GST_ITERATOR_RESYNC:
+         gst_iterator_resync (it);
+         done = FALSE;
+         hardware = FALSE;
+         if (app->colorbalance_element)
+           gst_object_unref (app->colorbalance_element);
+         app->colorbalance_element = NULL;
+         break;
+       case GST_ITERATOR_DONE:
+       case GST_ITERATOR_ERROR:
+       default:
+         done = TRUE;
+     }
    }
  
-   gst_object_unref (video_sink);
++  g_value_unset (&item);
+   gst_iterator_free (it);
  }
  
  /* called when Navigation command button is pressed */
@@@ -1658,40 -2036,35 +2044,35 @@@ navigation_cmd_cb (GtkButton * button, 
   * or gconfvideosink may be used which create the actual videosink only once
   * the pipeline is started) */
  static GstBusSyncReply
- bus_sync_handler (GstBus * bus, GstMessage * message, GstPipeline * data)
+ bus_sync_handler (GstBus * bus, GstMessage * message, SeekApp * app)
  {
-   GstElement *element;
 -  if ((GST_MESSAGE_TYPE (message) == GST_MESSAGE_ELEMENT) &&
 -      gst_structure_has_name (message->structure, "prepare-xwindow-id")) {
++  if (gst_is_video_overlay_prepare_window_handle_message (message)) {
+     GstElement *element = GST_ELEMENT (GST_MESSAGE_SRC (message));
  
-   if (!gst_is_video_overlay_prepare_window_handle_message (message))
-     return GST_BUS_PASS;
 -    if (app->xoverlay_element)
 -      gst_object_unref (app->xoverlay_element);
 -    app->xoverlay_element = GST_ELEMENT (gst_object_ref (element));
++    if (app->overlay_element)
++      gst_object_unref (app->overlay_element);
++    app->overlay_element = GST_ELEMENT (gst_object_ref (element));
  
-   element = GST_ELEMENT (GST_MESSAGE_SRC (message));
+     g_print ("got prepare-xwindow-id, setting XID %" G_GUINTPTR_FORMAT "\n",
+         app->embed_xid);
  
-   if (overlay_element)
-     gst_object_unref (overlay_element);
-   overlay_element = GST_ELEMENT (gst_object_ref (element));
-   if (g_object_class_find_property (G_OBJECT_GET_CLASS (element),
-           "force-aspect-ratio")) {
-     g_object_set (element, "force-aspect-ratio", TRUE, NULL);
-   }
-   /* Should have been initialised from main thread before (can't use
-    * GDK_WINDOW_XID here with Gtk+ >= 2.18, because the sync handler will
-    * be called from a streaming thread and GDK_WINDOW_XID maps to more than
-    * a simple structure lookup with Gtk+ >= 2.18, where 'more' is stuff that
-    * shouldn't be done from a non-GUI thread without explicit locking).  */
-   g_assert (embed_handle != 0);
-   g_print ("got prepare-window-handle, setting handle %" G_GUINTPTR_FORMAT "\n",
-       embed_handle);
+     if (g_object_class_find_property (G_OBJECT_GET_CLASS (element),
+             "force-aspect-ratio")) {
+       g_object_set (element, "force-aspect-ratio", TRUE, NULL);
+     }
  
-   gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (element),
-       embed_handle);
-   gst_video_overlay_handle_events (GST_VIDEO_OVERLAY (element), FALSE);
+     /* Should have been initialised from main thread before (can't use
+      * GDK_WINDOW_XID here with Gtk+ >= 2.18, because the sync handler will
+      * be called from a streaming thread and GDK_WINDOW_XID maps to more than
+      * a simple structure lookup with Gtk+ >= 2.18, where 'more' is stuff that
+      * shouldn't be done from a non-GUI thread without explicit locking).  */
+     g_assert (app->embed_xid != 0);
  
-   find_navigation_element ();
 -    gst_x_overlay_set_window_handle (GST_X_OVERLAY (element), app->embed_xid);
++    gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (element),
++        app->embed_xid);
  
+     find_interface_elements (app);
+   }
    return GST_BUS_PASS;
  }
  #endif
@@@ -1710,8 -2083,8 +2091,8 @@@ draw_cb (GtkWidget * widget, cairo_t * 
      return TRUE;
    }
  
-   if (overlay_element)
-     gst_video_overlay_expose (GST_VIDEO_OVERLAY (overlay_element));
 -  if (app->xoverlay_element)
 -    gst_x_overlay_expose (GST_X_OVERLAY (app->xoverlay_element));
++  if (app->overlay_element)
++    gst_video_overlay_expose (GST_VIDEO_OVERLAY (app->overlay_element));
  
    return FALSE;
  }
@@@ -1874,14 -2249,15 +2257,15 @@@ msg (GstBus * bus, GstMessage * message
  }
  
  static void
- connect_bus_signals (GstElement * pipeline)
+ connect_bus_signals (SeekApp * app)
  {
-   GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
+   GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (app->pipeline));
  
  #if defined (GDK_WINDOWING_X11) || defined (GDK_WINDOWING_WIN32) || defined (GDK_WINDOWING_QUARTZ)
-   /* handle prepare-window-handle element message synchronously */
-   gst_bus_set_sync_handler (bus, (GstBusSyncHandler) bus_sync_handler,
-       pipeline);
+   if (app->pipeline_type != 0) {
 -    /* handle prepare-xwindow-id element message synchronously, but only for non-playbin2 */
++    /* handle prepare-xwindow-id element message synchronously, but only for non-playbin */
+     gst_bus_set_sync_handler (bus, (GstBusSyncHandler) bus_sync_handler, app);
+   }
  #endif
  
    gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH);
@@@ -2320,82 -2907,135 +2915,135 @@@ create_ui (SeekApp * app
    /* seek bar */
    adjustment =
        GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.00, N_GRAD, 0.1, 1.0, 1.0));
-   hscale = gtk_hscale_new (adjustment);
-   gtk_scale_set_digits (GTK_SCALE (hscale), 2);
-   gtk_scale_set_value_pos (GTK_SCALE (hscale), GTK_POS_RIGHT);
-   gtk_range_set_show_fill_level (GTK_RANGE (hscale), TRUE);
-   gtk_range_set_fill_level (GTK_RANGE (hscale), N_GRAD);
-   g_signal_connect (hscale, "button_press_event", G_CALLBACK (start_seek),
-       pipeline);
-   g_signal_connect (hscale, "button_release_event", G_CALLBACK (stop_seek),
-       pipeline);
-   g_signal_connect (hscale, "format_value", G_CALLBACK (format_value),
-       pipeline);
-   if (pipeline_type == 0) {
+   app->seek_scale = gtk_hscale_new (adjustment);
+   gtk_scale_set_digits (GTK_SCALE (app->seek_scale), 2);
+   gtk_scale_set_value_pos (GTK_SCALE (app->seek_scale), GTK_POS_RIGHT);
+   gtk_range_set_show_fill_level (GTK_RANGE (app->seek_scale), TRUE);
+   gtk_range_set_fill_level (GTK_RANGE (app->seek_scale), N_GRAD);
+   g_signal_connect (app->seek_scale, "button_press_event",
+       G_CALLBACK (start_seek), app);
+   g_signal_connect (app->seek_scale, "button_release_event",
+       G_CALLBACK (stop_seek), app);
+   g_signal_connect (app->seek_scale, "format_value", G_CALLBACK (format_value),
+       app);
+   if (app->pipeline_type == 0) {
+     GtkWidget *pb2vbox, *boxes, *boxes2, *panel, *boxes3;
+     GtkWidget *volume_label, *shot_button;
+     GtkWidget *label;
 -    playbin = gtk_expander_new ("playbin2 options");
 -    /* the playbin2 panel controls for the video/audio/subtitle tracks */
++    playbin = gtk_expander_new ("playbin options");
 +    /* the playbin panel controls for the video/audio/subtitle tracks */
      panel = gtk_hbox_new (FALSE, 0);
-     video_combo = gtk_combo_box_text_new ();
-     audio_combo = gtk_combo_box_text_new ();
-     text_combo = gtk_combo_box_text_new ();
-     gtk_widget_set_sensitive (video_combo, FALSE);
-     gtk_widget_set_sensitive (audio_combo, FALSE);
-     gtk_widget_set_sensitive (text_combo, FALSE);
-     gtk_box_pack_start (GTK_BOX (panel), video_combo, TRUE, TRUE, 2);
-     gtk_box_pack_start (GTK_BOX (panel), audio_combo, TRUE, TRUE, 2);
-     gtk_box_pack_start (GTK_BOX (panel), text_combo, TRUE, TRUE, 2);
-     g_signal_connect (G_OBJECT (video_combo), "changed",
-         G_CALLBACK (video_combo_cb), pipeline);
-     g_signal_connect (G_OBJECT (audio_combo), "changed",
-         G_CALLBACK (audio_combo_cb), pipeline);
-     g_signal_connect (G_OBJECT (text_combo), "changed",
-         G_CALLBACK (text_combo_cb), pipeline);
+     app->video_combo = gtk_combo_box_text_new ();
+     app->audio_combo = gtk_combo_box_text_new ();
+     app->text_combo = gtk_combo_box_text_new ();
+     gtk_widget_set_sensitive (app->video_combo, FALSE);
+     gtk_widget_set_sensitive (app->audio_combo, FALSE);
+     gtk_widget_set_sensitive (app->text_combo, FALSE);
+     gtk_box_pack_start (GTK_BOX (panel), app->video_combo, TRUE, TRUE, 2);
+     gtk_box_pack_start (GTK_BOX (panel), app->audio_combo, TRUE, TRUE, 2);
+     gtk_box_pack_start (GTK_BOX (panel), app->text_combo, TRUE, TRUE, 2);
+     g_signal_connect (G_OBJECT (app->video_combo), "changed",
+         G_CALLBACK (video_combo_cb), app);
+     g_signal_connect (G_OBJECT (app->audio_combo), "changed",
+         G_CALLBACK (audio_combo_cb), app);
+     g_signal_connect (G_OBJECT (app->text_combo), "changed",
+         G_CALLBACK (text_combo_cb), app);
 -    /* playbin2 panel for flag checkboxes and volume/mute */
 +    /* playbin panel for flag checkboxes and volume/mute */
-     boxes = gtk_hbox_new (FALSE, 0);
-     vis_checkbox = gtk_check_button_new_with_label ("Vis");
-     video_checkbox = gtk_check_button_new_with_label ("Video");
-     audio_checkbox = gtk_check_button_new_with_label ("Audio");
-     text_checkbox = gtk_check_button_new_with_label ("Text");
-     mute_checkbox = gtk_check_button_new_with_label ("Mute");
-     download_checkbox = gtk_check_button_new_with_label ("Download");
-     buffer_checkbox = gtk_check_button_new_with_label ("Buffer");
+     boxes = gtk_grid_new ();
+     gtk_grid_set_row_spacing (GTK_GRID (boxes), 2);
+     gtk_grid_set_row_homogeneous (GTK_GRID (boxes), FALSE);
+     gtk_grid_set_column_spacing (GTK_GRID (boxes), 2);
+     gtk_grid_set_column_homogeneous (GTK_GRID (boxes), TRUE);
+     app->video_checkbox = gtk_check_button_new_with_label ("Video");
+     app->audio_checkbox = gtk_check_button_new_with_label ("Audio");
+     app->text_checkbox = gtk_check_button_new_with_label ("Text");
+     app->vis_checkbox = gtk_check_button_new_with_label ("Vis");
+     app->soft_volume_checkbox = gtk_check_button_new_with_label ("Soft Volume");
+     app->native_audio_checkbox =
+         gtk_check_button_new_with_label ("Native Audio");
+     app->native_video_checkbox =
+         gtk_check_button_new_with_label ("Native Video");
+     app->download_checkbox = gtk_check_button_new_with_label ("Download");
+     app->buffering_checkbox = gtk_check_button_new_with_label ("Buffering");
+     app->deinterlace_checkbox = gtk_check_button_new_with_label ("Deinterlace");
+     app->soft_colorbalance_checkbox =
+         gtk_check_button_new_with_label ("Soft Colorbalance");
+     app->mute_checkbox = gtk_check_button_new_with_label ("Mute");
      volume_label = gtk_label_new ("Volume");
-     volume_spinbutton = gtk_spin_button_new_with_range (0, 10.0, 0.1);
-     gtk_spin_button_set_value (GTK_SPIN_BUTTON (volume_spinbutton), 1.0);
-     gtk_box_pack_start (GTK_BOX (boxes), video_checkbox, TRUE, TRUE, 2);
-     gtk_box_pack_start (GTK_BOX (boxes), audio_checkbox, TRUE, TRUE, 2);
-     gtk_box_pack_start (GTK_BOX (boxes), text_checkbox, TRUE, TRUE, 2);
-     gtk_box_pack_start (GTK_BOX (boxes), vis_checkbox, TRUE, TRUE, 2);
-     gtk_box_pack_start (GTK_BOX (boxes), mute_checkbox, TRUE, TRUE, 2);
-     gtk_box_pack_start (GTK_BOX (boxes), download_checkbox, TRUE, TRUE, 2);
-     gtk_box_pack_start (GTK_BOX (boxes), buffer_checkbox, TRUE, TRUE, 2);
-     gtk_box_pack_start (GTK_BOX (boxes), volume_label, TRUE, TRUE, 2);
-     gtk_box_pack_start (GTK_BOX (boxes), volume_spinbutton, TRUE, TRUE, 2);
-     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (vis_checkbox), FALSE);
-     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (audio_checkbox), TRUE);
-     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (video_checkbox), TRUE);
-     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (text_checkbox), TRUE);
-     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mute_checkbox), FALSE);
-     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (download_checkbox), FALSE);
-     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (buffer_checkbox), FALSE);
-     g_signal_connect (G_OBJECT (vis_checkbox), "toggled",
-         G_CALLBACK (vis_toggle_cb), pipeline);
-     g_signal_connect (G_OBJECT (audio_checkbox), "toggled",
-         G_CALLBACK (audio_toggle_cb), pipeline);
-     g_signal_connect (G_OBJECT (video_checkbox), "toggled",
-         G_CALLBACK (video_toggle_cb), pipeline);
-     g_signal_connect (G_OBJECT (text_checkbox), "toggled",
-         G_CALLBACK (text_toggle_cb), pipeline);
-     g_signal_connect (G_OBJECT (mute_checkbox), "toggled",
-         G_CALLBACK (mute_toggle_cb), pipeline);
-     g_signal_connect (G_OBJECT (download_checkbox), "toggled",
-         G_CALLBACK (download_toggle_cb), pipeline);
-     g_signal_connect (G_OBJECT (buffer_checkbox), "toggled",
-         G_CALLBACK (buffer_toggle_cb), pipeline);
-     g_signal_connect (G_OBJECT (volume_spinbutton), "value_changed",
-         G_CALLBACK (volume_spinbutton_changed_cb), pipeline);
+     app->volume_spinbutton = gtk_spin_button_new_with_range (0, 10.0, 0.1);
+     gtk_grid_attach (GTK_GRID (boxes), app->video_checkbox, 0, 0, 1, 1);
+     gtk_grid_attach (GTK_GRID (boxes), app->audio_checkbox, 1, 0, 1, 1);
+     gtk_grid_attach (GTK_GRID (boxes), app->text_checkbox, 2, 0, 1, 1);
+     gtk_grid_attach (GTK_GRID (boxes), app->vis_checkbox, 3, 0, 1, 1);
+     gtk_grid_attach (GTK_GRID (boxes), app->soft_volume_checkbox, 4, 0, 1, 1);
+     gtk_grid_attach (GTK_GRID (boxes), app->native_audio_checkbox, 5, 0, 1, 1);
+     gtk_grid_attach (GTK_GRID (boxes), app->native_video_checkbox, 0, 1, 1, 1);
+     gtk_grid_attach (GTK_GRID (boxes), app->download_checkbox, 1, 1, 1, 1);
+     gtk_grid_attach (GTK_GRID (boxes), app->buffering_checkbox, 2, 1, 1, 1);
+     gtk_grid_attach (GTK_GRID (boxes), app->deinterlace_checkbox, 3, 1, 1, 1);
+     gtk_grid_attach (GTK_GRID (boxes), app->soft_colorbalance_checkbox, 4, 1, 1,
+         1);
+     gtk_grid_attach (GTK_GRID (boxes), app->mute_checkbox, 7, 0, 2, 1);
+     gtk_grid_attach (GTK_GRID (boxes), volume_label, 6, 1, 1, 1);
+     gtk_grid_attach (GTK_GRID (boxes), app->volume_spinbutton, 7, 1, 1, 1);
+     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app->video_checkbox),
+         TRUE);
+     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app->audio_checkbox),
+         TRUE);
+     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app->text_checkbox), TRUE);
+     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app->vis_checkbox), FALSE);
+     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app->soft_volume_checkbox),
+         TRUE);
+     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
+         (app->native_audio_checkbox), FALSE);
+     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
+         (app->native_video_checkbox), FALSE);
+     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app->download_checkbox),
+         FALSE);
+     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app->buffering_checkbox),
+         FALSE);
+     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app->deinterlace_checkbox),
+         FALSE);
+     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
+         (app->soft_colorbalance_checkbox), TRUE);
+     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app->mute_checkbox),
+         FALSE);
+     gtk_spin_button_set_value (GTK_SPIN_BUTTON (app->volume_spinbutton), 1.0);
+     g_signal_connect (G_OBJECT (app->video_checkbox), "toggled",
+         G_CALLBACK (video_toggle_cb), app);
+     g_signal_connect (G_OBJECT (app->audio_checkbox), "toggled",
+         G_CALLBACK (audio_toggle_cb), app);
+     g_signal_connect (G_OBJECT (app->text_checkbox), "toggled",
+         G_CALLBACK (text_toggle_cb), app);
+     g_signal_connect (G_OBJECT (app->vis_checkbox), "toggled",
+         G_CALLBACK (vis_toggle_cb), app);
+     g_signal_connect (G_OBJECT (app->soft_volume_checkbox), "toggled",
+         G_CALLBACK (soft_volume_toggle_cb), app);
+     g_signal_connect (G_OBJECT (app->native_audio_checkbox), "toggled",
+         G_CALLBACK (native_audio_toggle_cb), app);
+     g_signal_connect (G_OBJECT (app->native_video_checkbox), "toggled",
+         G_CALLBACK (native_video_toggle_cb), app);
+     g_signal_connect (G_OBJECT (app->download_checkbox), "toggled",
+         G_CALLBACK (download_toggle_cb), app);
+     g_signal_connect (G_OBJECT (app->buffering_checkbox), "toggled",
+         G_CALLBACK (buffering_toggle_cb), app);
+     g_signal_connect (G_OBJECT (app->deinterlace_checkbox), "toggled",
+         G_CALLBACK (deinterlace_toggle_cb), app);
+     g_signal_connect (G_OBJECT (app->soft_colorbalance_checkbox), "toggled",
+         G_CALLBACK (soft_colorbalance_toggle_cb), app);
+     g_signal_connect (G_OBJECT (app->mute_checkbox), "toggled",
+         G_CALLBACK (mute_toggle_cb), app);
+     g_signal_connect (G_OBJECT (app->volume_spinbutton), "value-changed",
+         G_CALLBACK (volume_spinbutton_changed_cb), app);
 -    /* playbin2 panel for snapshot */
 +    /* playbin panel for snapshot */
      boxes2 = gtk_hbox_new (FALSE, 0);
      shot_button = gtk_button_new_from_stock (GTK_STOCK_SAVE);
      gtk_widget_set_tooltip_text (shot_button,
  
    /* connect things ... */
    g_signal_connect (G_OBJECT (play_button), "clicked", G_CALLBACK (play_cb),
-       pipeline);
+       app);
    g_signal_connect (G_OBJECT (pause_button), "clicked", G_CALLBACK (pause_cb),
-       pipeline);
+       app);
    g_signal_connect (G_OBJECT (stop_button), "clicked", G_CALLBACK (stop_cb),
-       pipeline);
-   g_signal_connect (G_OBJECT (accurate_checkbox), "toggled",
-       G_CALLBACK (accurate_toggle_cb), pipeline);
-   g_signal_connect (G_OBJECT (key_checkbox), "toggled",
-       G_CALLBACK (key_toggle_cb), pipeline);
-   g_signal_connect (G_OBJECT (loop_checkbox), "toggled",
-       G_CALLBACK (loop_toggle_cb), pipeline);
-   g_signal_connect (G_OBJECT (flush_checkbox), "toggled",
-       G_CALLBACK (flush_toggle_cb), pipeline);
-   g_signal_connect (G_OBJECT (scrub_checkbox), "toggled",
-       G_CALLBACK (scrub_toggle_cb), pipeline);
-   g_signal_connect (G_OBJECT (play_scrub_checkbox), "toggled",
-       G_CALLBACK (play_scrub_toggle_cb), pipeline);
-   g_signal_connect (G_OBJECT (skip_checkbox), "toggled",
-       G_CALLBACK (skip_toggle_cb), pipeline);
-   g_signal_connect (G_OBJECT (rate_spinbutton), "value_changed",
-       G_CALLBACK (rate_spinbutton_changed_cb), pipeline);
-   g_signal_connect (G_OBJECT (window), "delete-event", delete_event_cb, NULL);
+       app);
+   g_signal_connect (G_OBJECT (app->window), "delete-event",
+       G_CALLBACK (delete_event_cb), app);
+ }
+ static void
+ set_defaults (SeekApp * app)
+ {
+   memset (app, 0, sizeof (SeekApp));
+   app->flush_seek = TRUE;
+   app->scrub = TRUE;
+   app->rate = 1.0;
+   app->position = app->duration = -1;
+   app->state = GST_STATE_NULL;
+   app->need_streams = TRUE;
 -  g_static_mutex_init (&app->state_mutex);
++  g_mutex_init (&app->state_mutex);
+   app->play_rate = 1.0;
+ }
+ static void
+ reset_app (SeekApp * app)
+ {
+   g_free (app->audiosink_str);
+   g_free (app->videosink_str);
+   g_list_free (app->formats);
 -  g_static_mutex_free (&app->state_mutex);
++  g_mutex_clear (&app->state_mutex);
 -  if (app->xoverlay_element)
 -    gst_object_unref (app->xoverlay_element);
++  if (app->overlay_element)
++    gst_object_unref (app->overlay_element);
+   if (app->navigation_element)
+     gst_object_unref (app->navigation_element);
+   g_list_foreach (app->paths, (GFunc) g_free, NULL);
+   g_list_free (app->paths);
+   g_list_foreach (app->sub_paths, (GFunc) g_free, NULL);
+   g_list_free (app->sub_paths);
+   g_print ("free pipeline\n");
+   gst_object_unref (app->pipeline);
+ }
+ int
+ main (int argc, char **argv)
+ {
+   SeekApp app;
+   GOptionEntry options[] = {
+     {"stats", 's', 0, G_OPTION_ARG_NONE, &app.stats,
+         "Show pad stats", NULL},
+     {"verbose", 'v', 0, G_OPTION_ARG_NONE, &app.verbose,
+         "Verbose properties", NULL},
+     {NULL}
+   };
+   GOptionContext *ctx;
+   GError *err = NULL;
+   set_defaults (&app);
 -#if !GLIB_CHECK_VERSION (2, 31, 0)
 -  if (!g_thread_supported ())
 -    g_thread_init (NULL);
 -#endif
 -
+   ctx = g_option_context_new ("- test seeking in gsteamer");
+   g_option_context_add_main_entries (ctx, options, NULL);
+   g_option_context_add_group (ctx, gst_init_get_option_group ());
+   g_option_context_add_group (ctx, gtk_get_option_group (TRUE));
+   if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
+     g_print ("Error initializing: %s\n", err->message);
+     exit (1);
+   }
+   GST_DEBUG_CATEGORY_INIT (seek_debug, "seek", 0, "seek example");
+   if (argc < 3) {
+     print_usage (argc, argv);
+     exit (-1);
+   }
+   app.pipeline_type = atoi (argv[1]);
+   if (app.pipeline_type < 0 || app.pipeline_type >= G_N_ELEMENTS (pipelines)) {
+     print_usage (argc, argv);
+     exit (-1);
+   }
+   app.pipeline_spec = argv[2];
+   if (g_path_is_absolute (app.pipeline_spec) &&
+       (g_strrstr (app.pipeline_spec, "*") != NULL ||
+           g_strrstr (app.pipeline_spec, "?") != NULL)) {
+     app.paths = handle_wildcards (app.pipeline_spec);
+   } else {
+     app.paths = g_list_prepend (app.paths, g_strdup (app.pipeline_spec));
+   }
+   if (!app.paths) {
+     g_print ("opening %s failed\n", app.pipeline_spec);
+     exit (-1);
+   }
+   app.current_path = app.paths;
+   if (argc > 3 && argv[3]) {
+     if (g_path_is_absolute (argv[3]) &&
+         (g_strrstr (argv[3], "*") != NULL ||
+             g_strrstr (argv[3], "?") != NULL)) {
+       app.sub_paths = handle_wildcards (argv[3]);
+     } else {
+       app.sub_paths = g_list_prepend (app.sub_paths, g_strdup (argv[3]));
+     }
+     if (!app.sub_paths) {
+       g_print ("opening %s failed\n", argv[3]);
+       exit (-1);
+     }
+     app.current_sub_path = app.sub_paths;
+   }
+   pipelines[app.pipeline_type].func (&app, app.current_path->data);
+   g_assert (app.pipeline);
+   create_ui (&app);
  
    /* show the gui. */
-   gtk_widget_show_all (window);
+   gtk_widget_show_all (app.window);
  
    /* realize window now so that the video window gets created and we can
     * obtain its XID before the pipeline is started up and the videosink
     * asks for the XID of the window to render onto */
-   gtk_widget_realize (window);
+   gtk_widget_realize (app.window);
  
  #if defined (GDK_WINDOWING_X11) || defined (GDK_WINDOWING_WIN32) || defined (GDK_WINDOWING_QUARTZ)
-   /* we should have the handle now */
-   g_assert (embed_handle != 0);
+   /* we should have the XID now */
+   g_assert (app.embed_xid != 0);
+   if (app.pipeline_type == 0) {
 -    gst_x_overlay_set_window_handle (GST_X_OVERLAY (app.pipeline),
++    gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (app.pipeline),
+         app.embed_xid);
+   }
  #endif
  
-   if (verbose) {
-     g_signal_connect (pipeline, "deep_notify",
+   if (app.verbose) {
+     g_signal_connect (app.pipeline, "deep_notify",
          G_CALLBACK (gst_object_default_deep_notify), NULL);
    }
  
Simple merge
Simple merge