Index: configure.in
===================================================================
RCS file: /cvs/gnome/totem/configure.in,v
retrieving revision 1.235
diff -u -p -r1.235 configure.in
--- configure.in	10 Sep 2005 18:22:48 -0000	1.235
+++ configure.in	19 Oct 2005 10:17:14 -0000
@@ -53,14 +53,15 @@ dnl the two versions here implicate the 
 dnl release versions. We want core newer than 0.8.6 (either cvs or a next
 dnl prerelease; 0.8.7 is preferred) and gst-plugins newer than 0.8.4
 dnl (either CVS or a prerelease; 0.8.5 is preferred).
-GST_REQS=0.8.6.1
-GSTPLUG_REQS=0.8.4.1
 XINE_REQS=1.0.1
+GST_MAJORMINOR=auto
 
 AC_ARG_ENABLE(gstreamer,
-	AC_HELP_STRING([--enable-gstreamer],[use GStreamer instead of xine for the backend]),
+	AC_HELP_STRING([--enable-gstreamer],[use GStreamer instead of xine for the backend (and optionally specify a version)]),
 	[case "${enableval}" in
 	yes) ENABLE_GST=yes ;;
+        0.8) ENABLE_GST=yes && GST_MAJORMINOR=0.8 ;;
+        0.9) ENABLE_GST=yes && GST_MAJORMINOR=0.9 ;;
         no)  ENABLE_GST=no ;;
 	*) AC_MSG_ERROR(bad value ${enableval} for --enable-gstreamer) ;;
 	esac],
@@ -78,20 +79,36 @@ if test x$ENABLE_GST = xno; then
 fi
 
 if test x$HAVE_XINE = xno; then
-	GST_MAJORMINOR=0.8
-	PKG_CHECK_MODULES(GST, \
-			gstreamer-$GST_MAJORMINOR >= $GST_REQS \
-			gstreamer-gconf-$GST_MAJORMINOR >= $GSTPLUG_REQS \
-			gstreamer-interfaces-$GST_MAJORMINOR >= $GSTPLUG_REQS,
+	dnl some sort of autodetection
+	if test x$GST_MAJORMINOR = xauto; then
+		PKG_CHECK_MODULES(GST, gstreamer-0.8, [
+				  GST_MAJORMINOR=0.8],[GST_MAJORMINOR=0.9])
+	fi
+	dnl set different requirements for supported major versions
+	if test x$GST_MAJORMINOR = x0.8; then
+		GST_REQS=0.8.6.1
+		GSTPLUG_REQS=0.8.4.1
+		MM="gstreamer-0.8 >= $GST_REQS gstreamer-gconf-0.8 >= $GSTPLUG_REQS gstreamer-interfaces-0.8 >= $GSTPLUG_REQS"
+	else
+		GST_REQS=0.9.1
+		GSTPLUG_REQS=0.9.1
+		MM="gstreamer-0.9 >= $GST_REQS gstreamer-plugins-base-0.9 >= $GSTPLUG_REQS gconf-2.0"
+	fi
+	PKG_CHECK_MODULES(GST, $MM,
 			HAVE_GSTREAMER=yes, HAVE_GSTREAMER=no)
-	MM="gstreamer-$GST_MAJORMINOR >= $GST_REQS gstreamer-gconf-$GST_MAJORMINOR >= $GSTPLUG_REQS gstreamer-interfaces-$GST_MAJORMINOR >= $GSTPLUG_REQS"
+	if test x$GST_MAJORMINOR = x0.9; then
+		GST_LIBS="$GST_LIBS -lgstinterfaces-0.9"
+		AC_SUBST(GST_LIBS)
+		EXTRA_BACKEND_LIBS="-lgstinterfaces-0.9"
+		AC_DEFINE(HAVE_GSTREAMER_09, 1, [Whether we use Gst 0.8 or 0.9])
+	fi
 
 dnl Give error and exit if we don't have gstreamer
 	if test "x$HAVE_GSTREAMER" = "xno"; then
 		AC_MSG_ERROR(you need the GStreamer or the xine-lib development packages installed)
 	fi
 
-	AC_MSG_RESULT(GStreamer)
+	AC_MSG_RESULT(GStreamer-$GST_MAJORMINOR)
 fi
 
 AM_CONDITIONAL(TOTEM_GST, test x$HAVE_GSTREAMER = "xyes")
@@ -181,12 +198,13 @@ AC_DEFINE_UNQUOTED([ISO_CODES_PREFIX],["
 
 AM_CONDITIONAL(HAVE_GNOME, test x$HAVE_GNOME = "xyes")
 EXTRA_GNOME_CFLAGS="$EXTRA_GNOME_CFLAGS"
-EXTRA_GNOME_LIBS="$EXTRA_GNOME_LIBS"
+EXTRA_GNOME_LIBS="$EXTRA_GNOME_LIBS $EXTRA_BACKEND_LIBS"
 AC_SUBST(EXTRA_GNOME_CFLAGS)
 AC_SUBST(EXTRA_GNOME_LIBS)
 
 PKG_CHECK_MODULES(GTK, gtk+-x11-2.0 $MM gthread-2.0)
 AC_SUBST(GTK_CFLAGS)
+GTK_LIBS="$GTK_LIBS $EXTRA_BACKEND_LIBS"
 AC_SUBST(GTK_LIBS)
 
 dnl *******
@@ -261,6 +279,7 @@ if test "x$ENABLE_MOZILLA" = "xyes" ; th
 		 gnome-vfs-2.0],,
 		[ENABLE_MOZILLA=no])
 
+	MOZILLA_LIBS="$MOZILLA_LIBS $EXTRA_BACKEND_LIBS"
 	AC_SUBST([MOZILLA_CFLAGS])
 	AC_SUBST([MOZILLA_LIBS])
 fi
@@ -336,6 +355,7 @@ if test x$ENABLE_NAUTILUS = "xyes" ; the
 			[HAVE_NAUTILUS=yes], [HAVE_NAUTILUS=no])
 fi
 
+NAUTILUS_LIBS="$NAUTILUS_LIBS $EXTRA_BACKEND_LIBS"
 AC_SUBST(NAUTILUS_CFLAGS)
 AC_SUBST(NAUTILUS_LIBS)
 if test x$HAVE_NAUTILUS = "xyes"; then
@@ -515,7 +535,7 @@ help/ru/Makefile
 
 echo
 if test x$HAVE_XINE = xno ; then
-	echo "Using the GStreamer backend"
+	echo "Using the GStreamer-$GST_MAJORMINOR backend"
 else
 	echo "Using the xine backend"
 fi
Index: src/totem.c
===================================================================
RCS file: /cvs/gnome/totem/src/totem.c,v
retrieving revision 1.462
diff -u -p -r1.462 totem.c
--- src/totem.c	24 Sep 2005 23:05:39 -0000	1.462
+++ src/totem.c	19 Oct 2005 10:17:17 -0000
@@ -1396,6 +1396,9 @@ seek_slider_changed_cb (GtkAdjustment *a
 	time = bacon_video_widget_get_stream_length (totem->bvw);
 	totem_statusbar_set_time_and_length (TOTEM_STATUSBAR (totem->statusbar),
 			(int) (pos * time / 1000), time / 1000);
+
+	if (bacon_video_widget_can_direct_seek (totem->bvw))
+		totem_action_seek (totem, pos);
 }
 
 static gboolean
@@ -1403,14 +1406,16 @@ seek_slider_released_cb (GtkWidget *widg
 {
 	if (g_object_get_data (G_OBJECT (widget), "fs") != FALSE)
 	{
-		totem_action_seek (totem,
+		if (!bacon_video_widget_can_direct_seek (totem->bvw))
+			totem_action_seek (totem,
 				gtk_adjustment_get_value (totem->fs_seekadj) / 65535);
 		/* Update the fullscreen seek adjustment */
 		gtk_adjustment_set_value (totem->seekadj,
 				gtk_adjustment_get_value
 				(totem->fs_seekadj));
 	} else {
-		totem_action_seek (totem,
+		if (!bacon_video_widget_can_direct_seek (totem->bvw))
+			totem_action_seek (totem,
 				gtk_adjustment_get_value (totem->seekadj) / 65535);
 		/* Update the seek adjustment */
 		gtk_adjustment_set_value (totem->fs_seekadj,
Index: src/backend/bacon-video-widget-gst.c
===================================================================
RCS file: /cvs/gnome/totem/src/backend/bacon-video-widget-gst.c,v
retrieving revision 1.198
diff -u -p -r1.198 bacon-video-widget-gst.c
--- src/backend/bacon-video-widget-gst.c	13 Sep 2005 19:34:20 -0000	1.198
+++ src/backend/bacon-video-widget-gst.c	19 Oct 2005 10:17:23 -0000
@@ -36,14 +36,20 @@
 #include <nvtv_simple.h>
 #endif 
 
+#include <gst/gst.h>
+#ifdef HAVE_GSTREAMER_09
+#include <gst/interfaces/xoverlay.h>
+#include <gst/interfaces/navigation.h>
+#include <gst/interfaces/colorbalance.h>
+#else /* HAVE_GSTREAMER_09 */
 /* gstgconf */
 #include <gst/gconf/gconf.h>
 
 /* GStreamer Interfaces */
 #include <gst/xoverlay/xoverlay.h>
 #include <gst/navigation/navigation.h>
-#include <gst/mixer/mixer.h>
 #include <gst/colorbalance/colorbalance.h>
+#endif /* HAVE_GSTREAMER_09 */
 
 /* system */
 #include <unistd.h>
@@ -67,6 +73,11 @@
 #define CONFIG_FILE ".gnome2"G_DIR_SEPARATOR_S"totem_config"
 #define DEFAULT_TITLE _("Totem Video Window")
 
+#ifndef HAVE_GSTREAMER_09
+  #define GstState GstElementState
+  #define GST_STATE_CHANGE_SUCCESS GST_STATE_SUCCESS
+#endif
+
 /* Signals */
 enum
 {
@@ -104,10 +115,10 @@ enum
 };
 
 static char *video_props_str[4] = {
-	GCONF_PREFIX"/brightness",
-	GCONF_PREFIX"/contrast",
-	GCONF_PREFIX"/saturation",
-	GCONF_PREFIX"/hue"
+  GCONF_PREFIX"/brightness",
+  GCONF_PREFIX"/contrast",
+  GCONF_PREFIX"/saturation",
+  GCONF_PREFIX"/hue"
 };
 
 struct BaconVideoWidgetPrivate
@@ -117,15 +128,12 @@ struct BaconVideoWidgetPrivate
 
   GstElement *play;
   guint update_id;
-  GstMixer *mixer;
-  GstMixerTrack *mixer_track;
   GstXOverlay *xoverlay;
   GstColorBalance *balance;
 
   GdkPixbuf *logo_pixbuf;
 
   gboolean media_has_video, media_has_audio;
-
   gint64 stream_length;
   gint64 current_time_nanos;
   gint64 current_time;
@@ -134,6 +142,7 @@ struct BaconVideoWidgetPrivate
   GstTagList *tagcache, *audiotags, *videotags;
 
   GError *last_error;
+  gboolean cache_errors;
   gboolean got_redirect;
 
   GdkWindow *video_window;
@@ -144,6 +153,9 @@ struct BaconVideoWidgetPrivate
   gboolean show_vfx;
   VisualsQuality visq;
   GstElement *vis_element;
+#ifdef HAVE_GSTREAMER_09
+  GstElement *vis_capsfilter, *audio_capsfilter;
+#endif /* HAVE_GSTREAMER_09 */
 
   /* Other stuff */
   int xpos, ypos;
@@ -795,6 +807,7 @@ bacon_video_widget_signal_idler (BaconVi
 
           break;
         }
+#ifndef HAVE_GSTREAMER_09
       case ASYNC_ERROR:
         {
 	  GError *err = signal->signal_data.error.error;
@@ -807,15 +820,14 @@ bacon_video_widget_signal_idler (BaconVi
 	      emit = FALSE;
           }
 
-          if (emit) {
+	  if (bvw->priv->cache_errors) {
+	    if (!bvw->priv->last_error) {
+	      bvw->priv->last_error = g_error_copy (err);
+	    }
+	  } else if (emit) {
             g_signal_emit (G_OBJECT (bvw),
                            bvw_table_signals[SIGNAL_ERROR], 0,
 			   err->message, TRUE, FALSE);
-            
-            /* Keep a copy of the last emitted message */
-            if (!bvw->priv->last_error) {
-              bvw->priv->last_error = g_error_copy (err);
-	    }
           }
           
           /* Cleaning the error infos */
@@ -865,13 +877,6 @@ bacon_video_widget_signal_idler (BaconVi
 			 0, NULL);
           break;
         }
-      case ASYNC_NOTIFY_STREAMINFO:
-        {
-          g_signal_emit (G_OBJECT (bvw),
-			 bvw_table_signals[SIGNAL_GOT_METADATA], 0, NULL);
-          g_signal_emit (bvw, bvw_table_signals[SIGNAL_CHANNELS_CHANGE], 0);
-          break;
-        }
       case ASYNC_EOS:
         {
           gst_element_set_state (GST_ELEMENT (bvw->priv->play),
@@ -885,6 +890,14 @@ bacon_video_widget_signal_idler (BaconVi
 			 0, signal->signal_data.buffering.percent);
           break;
         }
+#endif /* !HAVE_GSTREAMER_09 */
+      case ASYNC_NOTIFY_STREAMINFO:
+        {
+          g_signal_emit (G_OBJECT (bvw),
+			 bvw_table_signals[SIGNAL_GOT_METADATA], 0, NULL);
+          g_signal_emit (bvw, bvw_table_signals[SIGNAL_CHANNELS_CHANGE], 0);
+          break;
+        }
       case ASYNC_REDIRECT:
 	{
 	  g_signal_emit (G_OBJECT (bvw), bvw_table_signals[SIGNAL_REDIRECT],
@@ -902,6 +915,195 @@ bacon_video_widget_signal_idler (BaconVi
   return (queue_length > 0);
 }
 
+static gboolean cb_iterate (BaconVideoWidget *bvw);
+static void parse_stream_info (BaconVideoWidget *bvw);
+#ifdef HAVE_GSTREAMER_09
+
+static gboolean
+bacon_video_widget_bus_message_cb (GstBus * bus, GstMessage * message,
+                                   gpointer data)
+{
+  BaconVideoWidget *bvw = (BaconVideoWidget *) data;
+
+  g_return_val_if_fail (bvw != NULL, TRUE);
+  g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), TRUE);
+
+  switch (GST_MESSAGE_TYPE (message)) {
+    case GST_MESSAGE_ERROR: {
+      char *debug;
+      GError *error;
+
+      gst_message_parse_error (message, &error, &debug);
+      if (bvw->priv->cache_errors) {
+	if (!bvw->priv->last_error)
+          bvw->priv->last_error = error;
+	else
+	  g_error_free (error);
+      } else {
+        g_signal_emit (G_OBJECT (bvw), bvw_table_signals[SIGNAL_ERROR], 0,
+		       error->message, TRUE, FALSE);
+	g_error_free (error);
+      }
+
+      /* Cleaning the error infos */
+      g_free (debug);
+      break;
+    }
+    case GST_MESSAGE_WARNING: {
+      GError *error;
+      char *debug;
+
+      gst_message_parse_warning (message, &error, &debug);
+      g_signal_emit (G_OBJECT (bvw), bvw_table_signals[SIGNAL_ERROR], 0,
+		     error->message, FALSE, FALSE);
+
+      /* clean-up */
+      g_error_free (error);
+      g_free (debug);
+      break;
+    }
+    case GST_MESSAGE_TAG: {
+      GstTagList *tag_list, *result;
+      GstElementFactory *f;
+      GstObject *src;
+
+      gst_message_parse_tag (message, &tag_list);
+      src = GST_MESSAGE_SRC (message);
+
+      /* all tags */
+      result = gst_tag_list_merge (bvw->priv->tagcache, tag_list,
+				   GST_TAG_MERGE_APPEND);
+      if (bvw->priv->tagcache)
+        gst_tag_list_free (bvw->priv->tagcache);
+      bvw->priv->tagcache = result;
+
+      /* media-type-specific tags */
+      if (GST_IS_ELEMENT (src) &&
+	  (f = gst_element_get_factory (GST_ELEMENT (src)))) {
+        const gchar *klass = gst_element_factory_get_klass (f);
+        GstTagList **cache = NULL;
+
+        if (g_strrstr (klass, "Video")) {
+          cache = &bvw->priv->videotags;
+        } else if (g_strrstr (klass, "Audio")) {
+          cache = &bvw->priv->audiotags;
+        }
+
+        if (cache) {
+          result = gst_tag_list_merge (*cache, tag_list, GST_TAG_MERGE_APPEND);
+          if (*cache)
+            gst_tag_list_free (*cache);
+          *cache = result;
+        }
+      }
+
+      /* clean up */
+      gst_tag_list_free (tag_list);
+
+      g_signal_emit (G_OBJECT (bvw),
+		     bvw_table_signals[SIGNAL_GOT_METADATA], 0);
+      break;
+    }
+    case GST_MESSAGE_EOS:
+      g_signal_emit (G_OBJECT (bvw), bvw_table_signals[SIGNAL_EOS], 0, NULL);
+      break;
+    case GST_MESSAGE_BUFFERING: {
+      const GstStructure *str;
+      gint percent = 0;
+
+      str = gst_message_get_structure (message);
+      gst_structure_get_int (str, "buffer-percent", &percent);
+      g_signal_emit (G_OBJECT (bvw), bvw_table_signals[SIGNAL_BUFFERING], 0,
+		     percent);
+      break;
+    }
+    case GST_MESSAGE_APPLICATION: {
+      const GstStructure *str;
+      const char *title;
+
+      str = gst_message_get_structure (message);
+      title = gst_structure_get_name (str);
+
+      g_message ("Unhandled application message %s", title);
+      break;
+    }
+    case GST_MESSAGE_STATE_CHANGED: {
+      GstState old_state, new_state, pending_state;
+
+      /* we only care about playbin (pipeline) state changes */
+      if (GST_MESSAGE_SRC (message) != GST_OBJECT (bvw->priv->play))
+	break;
+
+      gst_message_parse_state_changed (message, &old_state, &new_state,
+          &pending_state);
+
+      /* now do stuff */
+      if (old_state == GST_STATE_PLAYING) {
+        if (bvw->priv->update_id != 0) {
+          g_source_remove (bvw->priv->update_id);
+          bvw->priv->update_id = 0;
+        }
+      } else if (new_state == GST_STATE_PLAYING) {
+        if (bvw->priv->update_id != 0)
+          g_source_remove (bvw->priv->update_id);
+        bvw->priv->update_id =
+	    g_timeout_add (200, (GSourceFunc) cb_iterate, bvw);
+      }
+
+      if (old_state <= GST_STATE_READY &&
+          new_state >= GST_STATE_PAUSED) {
+        parse_stream_info (bvw);
+      } else if (new_state <= GST_STATE_READY &&
+                 old_state >= GST_STATE_PAUSED) {
+        bvw->priv->media_has_video = FALSE;
+        bvw->priv->media_has_audio = FALSE;
+
+        /* clean metadata cache */
+        if (bvw->priv->tagcache) {
+          gst_tag_list_free (bvw->priv->tagcache);
+          bvw->priv->tagcache = NULL;
+        }
+        if (bvw->priv->audiotags) {
+          gst_tag_list_free (bvw->priv->audiotags);
+          bvw->priv->audiotags = NULL;
+        }
+        if (bvw->priv->videotags) {
+          gst_tag_list_free (bvw->priv->videotags);
+          bvw->priv->videotags = NULL;
+        }
+
+        bvw->priv->video_width = 0;
+        bvw->priv->video_height = 0;
+      }
+      break;
+    }
+
+    case GST_MESSAGE_ELEMENT:{
+      gchar *src_name;
+
+      src_name = gst_object_get_name (message->src);
+
+      g_message ("Unhandled element message '%s' from element '%s'", 
+          gst_structure_get_name (message->structure), src_name);
+
+      g_free (src_name);
+      break;
+    }
+
+    case GST_MESSAGE_CLOCK_PROVIDE:
+    case GST_MESSAGE_CLOCK_LOST:
+    case GST_MESSAGE_NEW_CLOCK:
+      break;
+
+    default:
+      g_message ("Unhandled message type 0x%x", GST_MESSAGE_TYPE (message));
+      break;
+  }
+
+  /* yes, remove the message from the queue */
+  return TRUE;
+}
+#else /* HAVE_GSTREAMER_09 */
 static void
 got_found_tag (GstElement *play, GstElement *source,
                GstTagList *tag_list, BaconVideoWidget * bvw)
@@ -924,28 +1126,18 @@ got_found_tag (GstElement *play, GstElem
 }
 
 static void
-group_switch (GstElement *play, BaconVideoWidget *bvw)
+got_eos (GstElement * play, BaconVideoWidget * bvw)
 {
   BVWSignal *signal;
 
   g_return_if_fail (bvw != NULL);
   g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
 
-  if (bvw->priv->tagcache) {
-    gst_tag_list_free (bvw->priv->tagcache);
-    bvw->priv->tagcache = NULL;
-  }
-  if (bvw->priv->audiotags) {
-    gst_tag_list_free (bvw->priv->audiotags);
-    bvw->priv->audiotags = NULL;
-  }
-  if (bvw->priv->videotags) {
-    gst_tag_list_free (bvw->priv->videotags);
-    bvw->priv->videotags = NULL;
-  }
+  if (bvw->priv->got_redirect)
+    return;
 
   signal = g_new0 (BVWSignal, 1);
-  signal->signal_id = ASYNC_NOTIFY_STREAMINFO;
+  signal->signal_id = ASYNC_EOS;
 
   g_async_queue_push (bvw->priv->queue, signal);
 
@@ -953,19 +1145,17 @@ group_switch (GstElement *play, BaconVid
 }
 
 static void
-got_redirect (GstElement *play, const gchar * new_location,
-	      BaconVideoWidget *bvw)
+got_buffering (GstElement * play, gint percentage,
+	       BaconVideoWidget * bvw)
 {
   BVWSignal *signal;
 
   g_return_if_fail (bvw != NULL);
   g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
 
-  bvw->priv->got_redirect = TRUE;
-
   signal = g_new0 (BVWSignal, 1);
-  signal->signal_id = ASYNC_REDIRECT;
-  signal->signal_data.redirect.new_location = g_strdup (new_location);
+  signal->signal_id = ASYNC_BUFFERING;
+  signal->signal_data.buffering.percent = percentage;
 
   g_async_queue_push (bvw->priv->queue, signal);
 
@@ -973,36 +1163,102 @@ got_redirect (GstElement *play, const gc
 }
 
 static void
-got_video_size (BaconVideoWidget * bvw)
+state_change (GstElement *play, GstState old_state,
+	      GstState new_state, BaconVideoWidget *bvw)
+{
+  if (old_state == GST_STATE_PLAYING) {
+    if (bvw->priv->update_id != 0) {
+      g_source_remove (bvw->priv->update_id);
+      bvw->priv->update_id = 0;
+    }
+  } else if (new_state == GST_STATE_PLAYING) {
+    if (bvw->priv->update_id != 0)
+      g_source_remove (bvw->priv->update_id);
+    bvw->priv->update_id = g_timeout_add (200, (GSourceFunc) cb_iterate, bvw);
+  }
+
+  if (old_state <= GST_STATE_READY &&
+      new_state >= GST_STATE_PAUSED) {
+    parse_stream_info (bvw);
+  } else if (new_state <= GST_STATE_READY &&
+             old_state >= GST_STATE_PAUSED) {
+    bvw->priv->media_has_video = FALSE;
+    bvw->priv->media_has_audio = FALSE;
+
+    /* clean metadata cache */
+    if (bvw->priv->tagcache)
+    {
+      gst_tag_list_free (bvw->priv->tagcache);
+      bvw->priv->tagcache = NULL;
+    }
+    if (bvw->priv->audiotags) {
+      gst_tag_list_free (bvw->priv->audiotags);
+      bvw->priv->audiotags = NULL;
+    }
+    if (bvw->priv->videotags) {
+      gst_tag_list_free (bvw->priv->videotags);
+      bvw->priv->videotags = NULL;
+    }
+
+    bvw->priv->video_width = 0;
+    bvw->priv->video_height = 0;
+  }
+}
+
+static void
+got_error (GstElement *play, GstElement *orig, GError *error,
+           gchar *debug, BaconVideoWidget * bvw)
 {
   BVWSignal *signal;
   
   g_return_if_fail (bvw != NULL);
   g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
 
+  /* since we're opening, we will never enter the mainloop
+   * until we return, so setting an idle handler doesn't
+   * help... Anyway, let's prepare a message. */
+  if (bvw->priv->cache_errors) {
+    if (!bvw->priv->last_error)
+      bvw->priv->last_error = g_error_copy (error);
+    return;
+  }
+
   signal = g_new0 (BVWSignal, 1);
-  signal->signal_id = ASYNC_VIDEO_SIZE;
-  signal->signal_data.video_size.width = bvw->priv->video_width;
-  signal->signal_data.video_size.height = bvw->priv->video_height;
+  signal->signal_id = ASYNC_ERROR;
+  signal->signal_data.error.element = orig;
+  signal->signal_data.error.error = g_error_copy (error);
+  if (debug)
+    signal->signal_data.error.debug_message = g_strdup (debug);
 
   g_async_queue_push (bvw->priv->queue, signal);
 
   g_idle_add ((GSourceFunc) bacon_video_widget_signal_idler, bvw);
 }
+#endif /* HAVE_GSTREAMER_09 */
 
 static void
-got_eos (GstElement * play, BaconVideoWidget * bvw)
+group_switch (GstElement *play, BaconVideoWidget *bvw)
 {
   BVWSignal *signal;
-  
+
   g_return_if_fail (bvw != NULL);
   g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
- 
-  if (bvw->priv->got_redirect)
-    return;
+
+  if (bvw->priv->tagcache) {
+    gst_tag_list_free (bvw->priv->tagcache);
+    bvw->priv->tagcache = NULL;
+  }
+  if (bvw->priv->audiotags) {
+    gst_tag_list_free (bvw->priv->audiotags);
+    bvw->priv->audiotags = NULL;
+  }
+  if (bvw->priv->videotags) {
+    gst_tag_list_free (bvw->priv->videotags);
+    bvw->priv->videotags = NULL;
+  }
 
   signal = g_new0 (BVWSignal, 1);
-  signal->signal_id = ASYNC_EOS;
+  signal->signal_id = ASYNC_NOTIFY_STREAMINFO;
 
   g_async_queue_push (bvw->priv->queue, signal);
 
@@ -1010,17 +1266,19 @@ got_eos (GstElement * play, BaconVideoWi
 }
 
 static void
-got_buffering (GstElement * play, gint percentage,
-	       BaconVideoWidget * bvw)
+got_redirect (GstElement *play, const gchar * new_location,
+	      BaconVideoWidget *bvw)
 {
   BVWSignal *signal;
 
   g_return_if_fail (bvw != NULL);
   g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
 
+  bvw->priv->got_redirect = TRUE;
+
   signal = g_new0 (BVWSignal, 1);
-  signal->signal_id = ASYNC_BUFFERING;
-  signal->signal_data.buffering.percent = percentage;
+  signal->signal_id = ASYNC_REDIRECT;
+  signal->signal_data.redirect.new_location = g_strdup (new_location);
 
   g_async_queue_push (bvw->priv->queue, signal);
 
@@ -1028,15 +1286,21 @@ got_buffering (GstElement * play, gint p
 }
 
 static void
-got_stream_length (GstElement * play, gint64 length_nanos,
-                   BaconVideoWidget * bvw)
+got_video_size (BaconVideoWidget * bvw)
 {
+  BVWSignal *signal;
+
   g_return_if_fail (bvw != NULL);
   g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
 
-  bvw->priv->stream_length = (gint64) length_nanos / GST_MSECOND;
-  
-  //g_signal_emit (G_OBJECT (bvw), bvw_table_signals[SIGNAL_GOT_METADATA], 0, NULL);
+  signal = g_new0 (BVWSignal, 1);
+  signal->signal_id = ASYNC_VIDEO_SIZE;
+  signal->signal_data.video_size.width = bvw->priv->video_width;
+  signal->signal_data.video_size.height = bvw->priv->video_height;
+
+  g_async_queue_push (bvw->priv->queue, signal);
+
+  g_idle_add ((GSourceFunc) bacon_video_widget_signal_idler, bvw);
 }
 
 static void
@@ -1110,19 +1374,28 @@ static gboolean
 cb_iterate (BaconVideoWidget *bvw)
 {
   GstFormat fmt = GST_FORMAT_TIME;
-  gint64 value;
+  gint64 pos = -1, len = -1;
 
   /* check length/pos of stream */
+#if HAVE_GSTREAMER_09
+  if (gst_element_query_position (bvw->priv->play, &fmt, &pos, &len)) {
+#else /* HAVE_GSTREAMER_09 */
   if (gst_element_query (GST_ELEMENT (bvw->priv->play),
-			 GST_QUERY_TOTAL, &fmt, &value) &&
-      value != -1 && value / GST_MSECOND != bvw->priv->stream_length) {
-    got_stream_length (GST_ELEMENT (bvw->priv->play),
-		       value, bvw);
+			 GST_QUERY_TOTAL, &fmt, &len)) {
+#endif /* HAVE_GSTREAMER_09 */
+    if (len != -1) {
+      bvw->priv->stream_length = len / GST_MSECOND;
+      //g_signal_emit (G_OBJECT (bvw), bvw_table_signals[SIGNAL_GOT_METADATA], 0, NULL);
+    }
+#ifndef HAVE_GSTREAMER_09
   }
   if (gst_element_query (GST_ELEMENT (bvw->priv->play),
-			 GST_QUERY_POSITION, &fmt, &value)) {
-    got_time_tick (GST_ELEMENT (bvw->priv->play),
-		   value, bvw);
+			 GST_QUERY_POSITION, &fmt, &pos)) {
+#endif /* HAVE_GSTREAMER_09 */
+    if (pos != -1) {
+      got_time_tick (GST_ELEMENT (bvw->priv->play),
+		     pos, bvw);
+    }
   }
 
   return TRUE;
@@ -1134,11 +1407,18 @@ caps_set (GObject * obj,
 {
   GstPad *pad = GST_PAD (obj);
   GstStructure *s;
+#ifdef HAVE_GSTREAMER_09
+  GstCaps *caps;
 
-  if (!GST_PAD_CAPS (pad))
+  if (!(caps = gst_pad_get_negotiated_caps (pad)))
+#else /* HAVE_GSTREAMER_09 */
+  const GstCaps *caps;
+
+  if (!(caps = GST_PAD_CAPS (pad)))
+#endif /* HAVE_GSTREAMER_09 */
     return;
 
-  s = gst_caps_get_structure (GST_PAD_CAPS (pad), 0);
+  s = gst_caps_get_structure (caps, 0);
   if (s) {
     const GValue *par;
 
@@ -1165,12 +1445,13 @@ caps_set (GObject * obj,
     bacon_video_widget_set_aspect_ratio (bvw, bvw->priv->ratio_type);
   }
 
-  /* and disable ourselves */
-  //g_signal_handlers_disconnect_by_func (pad, caps_set, bvw);
+#ifdef HAVE_GSTREAMER_09
+  gst_caps_unref (caps);
+#endif /* HAVE_GSTREAMER_09 */
 }
 
-static GstCaps * fixate_visualization (GstPad *pad, const GstCaps *in_caps,
-				       BaconVideoWidget *bvw);
+static void get_visualization_size (BaconVideoWidget *bvw,
+				    int *w, int *h, int *fps);
 
 static void
 parse_stream_info (BaconVideoWidget *bvw)
@@ -1197,33 +1478,43 @@ parse_stream_info (BaconVideoWidget *bvw
     if (strstr (val->value_name, "AUDIO")) {
       if (!bvw->priv->media_has_audio) {
         bvw->priv->media_has_audio = TRUE;
-        /*if (!bvw->priv->media_has_video &&
-            bvw->priv->show_vfx && bvw->priv->vis_element) {
-          videopad = gst_element_get_pad (bvw->priv->vis_element, "src");
-        }*/
       }
     } else if (strstr (val->value_name, "VIDEO")) {
       bvw->priv->media_has_video = TRUE;
       if (!videopad) {
         g_object_get (info, "object", &videopad, NULL);
+#ifndef HAVE_GSTREAMER_09
         /* hack for 0.8.5 */
         if (!videopad)
           g_object_get (info, "pad", &videopad, NULL);
+#endif /* !HAVE_GSTREAMER_09 */
       }
     }
   }
 
   if (videopad) {
+#if HAVE_GSTREAMER_09
+    GstCaps *caps;
+
+    if ((caps = gst_pad_get_negotiated_caps (videopad))) {
+      caps_set (G_OBJECT (videopad), NULL, bvw);
+      gst_caps_unref (caps);
+    }
+    g_signal_connect (videopad, "notify::caps",
+        G_CALLBACK (caps_set), bvw);
+#else
     GstPad *real = (GstPad *) GST_PAD_REALIZE (videopad);
 
     /* handle explicit caps as well - they're set later */
     if (((GstRealPad *) real)->link != NULL && GST_PAD_CAPS (real))
       caps_set (G_OBJECT (real), NULL, bvw);
-    //else
-      g_signal_connect (real, "notify::caps",
-          G_CALLBACK (caps_set), bvw);
+    g_signal_connect (real, "notify::caps",
+        G_CALLBACK (caps_set), bvw);
+#endif
   } else if (bvw->priv->show_vfx && bvw->priv->vis_element) {
-    fixate_visualization (NULL, NULL, bvw);
+    int dummy;
+    get_visualization_size (bvw, &bvw->priv->video_width,
+			    &bvw->priv->video_height, &dummy);
   }
 
   g_list_foreach (streaminfo, (GFunc) g_object_unref, NULL);
@@ -1231,87 +1522,14 @@ parse_stream_info (BaconVideoWidget *bvw
 }
 
 static void
-stream_info_set (GObject * obj, GParamSpec * pspec, BaconVideoWidget * bvw)
-{
-  BVWSignal *signal;
-
-  parse_stream_info (bvw);
-
-  signal = g_new0 (BVWSignal, 1);
-  signal->signal_id = ASYNC_NOTIFY_STREAMINFO;
-
-  g_async_queue_push (bvw->priv->queue, signal);
-
-  g_idle_add ((GSourceFunc) bacon_video_widget_signal_idler, bvw);
-}
-
-static void
-state_change (GstElement *play, GstElementState old_state,
-	      GstElementState new_state, BaconVideoWidget *bvw)
-{
-  if (old_state == GST_STATE_PLAYING) {
-    if (bvw->priv->update_id != 0) {
-      g_source_remove (bvw->priv->update_id);
-      bvw->priv->update_id = 0;
-    }
-  } else if (new_state == GST_STATE_PLAYING) {
-    if (bvw->priv->update_id != 0)
-      g_source_remove (bvw->priv->update_id);
-    bvw->priv->update_id = g_timeout_add (200, (GSourceFunc) cb_iterate, bvw);
-  }
-
-  if (old_state <= GST_STATE_READY &&
-      new_state >= GST_STATE_PAUSED) {
-    parse_stream_info (bvw);
-  } else if (new_state <= GST_STATE_READY &&
-             old_state >= GST_STATE_PAUSED) {
-    bvw->priv->media_has_video = FALSE;
-    bvw->priv->media_has_audio = FALSE;
-
-    /* clean metadata cache */
-    if (bvw->priv->tagcache)
-    {
-      gst_tag_list_free (bvw->priv->tagcache);
-      bvw->priv->tagcache = NULL;
-    }
-    if (bvw->priv->audiotags) {
-      gst_tag_list_free (bvw->priv->audiotags);
-      bvw->priv->audiotags = NULL;
-    }
-    if (bvw->priv->videotags) {
-      gst_tag_list_free (bvw->priv->videotags);
-      bvw->priv->videotags = NULL;
-    }
-
-    bvw->priv->video_width = 0;
-    bvw->priv->video_height = 0;
-  }
-}
-
-static void
-got_error (GstElement *play, GstElement *orig, GError *error,
-           gchar *debug, BaconVideoWidget * bvw)
-{
-  BVWSignal *signal;
-  
-  g_return_if_fail (bvw != NULL);
-  g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
-
-  /* since we're opening, we will never enter the mainloop
-   * until we return, so setting an idle handler doesn't
-   * help... Anyway, let's prepare a message. */
-  if (GST_STATE (play) != GST_STATE_PLAYING) {
-    if (!bvw->priv->last_error)
-      bvw->priv->last_error = g_error_copy (error);
-    return;
-  }
-  
+stream_info_set (GObject * obj, GParamSpec * pspec, BaconVideoWidget * bvw)
+{
+  BVWSignal *signal;
+
+  parse_stream_info (bvw);
+
   signal = g_new0 (BVWSignal, 1);
-  signal->signal_id = ASYNC_ERROR;
-  signal->signal_data.error.element = orig;
-  signal->signal_data.error.error = g_error_copy (error);
-  if (debug)
-    signal->signal_data.error.debug_message = g_strdup (debug);
+  signal->signal_id = ASYNC_NOTIFY_STREAMINFO;
 
   g_async_queue_push (bvw->priv->queue, signal);
 
@@ -1335,28 +1553,23 @@ bacon_video_widget_finalize (GObject * o
       bvw->priv->queue = NULL;
     }
 
-  if (bvw->priv->vis_plugins_list)
-    {
-      g_list_foreach (bvw->priv->vis_plugins_list, (GFunc) g_free, NULL);
-      g_list_free (bvw->priv->vis_plugins_list);
-      bvw->priv->vis_plugins_list = NULL;
-    }
+  if (bvw->priv->vis_plugins_list) {
+    g_list_free (bvw->priv->vis_plugins_list);
+    bvw->priv->vis_plugins_list = NULL;
+  }
 
-  if (bvw->priv->play != NULL && GST_IS_ELEMENT (bvw->priv->play))
-    {
-      gst_element_set_state (GST_ELEMENT (bvw->priv->play), GST_STATE_READY);
-      gst_object_unref (GST_OBJECT (bvw->priv->play));
-      bvw->priv->play = NULL;
-    }
+  if (bvw->priv->play != NULL && GST_IS_ELEMENT (bvw->priv->play)) {
+    gst_element_set_state (GST_ELEMENT (bvw->priv->play), GST_STATE_READY);
+    gst_object_unref (GST_OBJECT (bvw->priv->play));
+    bvw->priv->play = NULL;
+  }
 
-  if (bvw->priv->update_id)
-    {
-      g_source_remove (bvw->priv->update_id);
-      bvw->priv->update_id = 0;
-    }
+  if (bvw->priv->update_id) {
+    g_source_remove (bvw->priv->update_id);
+    bvw->priv->update_id = 0;
+  }
 
-  if (bvw->priv->tagcache)
-  {
+  if (bvw->priv->tagcache) {
     gst_tag_list_free (bvw->priv->tagcache);
     bvw->priv->tagcache = NULL;
   }
@@ -1454,11 +1667,7 @@ bacon_video_widget_get_property (GObject
 char *
 bacon_video_widget_get_backend_name (BaconVideoWidget * bvw)
 {
-  guint major, minor, micro;
-
-  gst_version (&major, &minor, &micro);
-
-  return g_strdup_printf ("GStreamer version %d.%d.%d", major, minor, micro);
+  return gst_version_string ();
 }
 
 static gboolean
@@ -1695,14 +1904,10 @@ bacon_video_widget_get_tv_out (BaconVide
   return bvw->priv->tv_out_type;
 }
 
-static GstCaps *
-cb_audio_fixate (GstPad *pad,
-		 const GstCaps *in_caps,
-		 BaconVideoWidget *bvw)
+static gint
+get_num_audio_channels (BaconVideoWidget * bvw)
 {
-  gint channels = -1, n, count, diff = -1;
-  const GstStructure *s, *closest = NULL;
-  const GValue *v;
+  gint channels;
 
   switch (bvw->priv->speakersetup) {
     case BVW_AUDIO_SOUND_STEREO:
@@ -1722,11 +1927,18 @@ cb_audio_fixate (GstPad *pad,
       break;
     case BVW_AUDIO_SOUND_AC3PASSTHRU:
     default:
-      break;
+      g_return_val_if_reached (-1);
   }
 
-  if (channels == -1)
-    return NULL;
+  return channels;
+}
+
+static GstCaps *
+fixate_to_num (const GstCaps * in_caps, gint channels)
+{
+  gint n, count, diff = -1;
+  const GstStructure *s, *closest = NULL;
+  const GValue *v;
 
   /* there might be multiple structures, and one might contain the
    * channelcount that we want. Try that. */
@@ -1792,10 +2004,65 @@ cb_audio_fixate (GstPad *pad,
     }
   }
 
-  /* FIXME: we could do something with closest here... */
+  /* close guess */
+  if (closest)
+    return gst_caps_new_full (gst_structure_copy (closest), NULL);
+
   return NULL;
 }
 
+#ifdef HAVE_GSTREAMER_09
+static void
+set_audio_filter (BaconVideoWidget *bvw)
+{
+  gint channels;
+  GstCaps *caps, *res;
+  GstPad *pad;
+
+  /* reset old */
+  g_object_set (G_OBJECT (bvw->priv->audio_capsfilter),
+      "caps", NULL, NULL);
+
+  /* get possible caps */
+  pad = gst_element_get_pad (bvw->priv->audio_capsfilter, "src");
+  caps = gst_pad_get_allowed_caps (pad);
+  gst_object_unref (GST_OBJECT (pad));
+
+  if ((channels = get_num_audio_channels (bvw)) == -1)
+    return;
+
+  res = fixate_to_num (caps, channels);
+  gst_caps_unref (caps);
+
+  /* set */
+  if (res && gst_caps_is_empty (res)) {
+    gst_caps_unref (res);
+    res = NULL;
+  }
+  g_object_set (G_OBJECT (bvw->priv->audio_capsfilter),
+      "caps", res, NULL);
+  gst_caps_unref (res);
+
+  /* reset */
+  pad = gst_element_get_pad (bvw->priv->audio_capsfilter, "src");
+  gst_pad_set_caps (pad, NULL);
+  gst_object_unref (GST_OBJECT (pad));
+}
+#else /* HAVE_GSTREAMER_09 */
+static GstCaps *
+cb_audio_fixate (GstPad *pad,
+		 const GstCaps *in_caps,
+		 BaconVideoWidget *bvw)
+{
+  gint channels;
+
+  if ((channels = get_num_audio_channels (bvw)) == -1)
+    return NULL;
+
+  return fixate_to_num (in_caps, channels);
+}
+#endif /* HAVE_GSTREAMER_09 */
+
 BaconVideoWidgetAudioOutType
 bacon_video_widget_get_audio_out_type (BaconVideoWidget *bvw)
 {
@@ -1809,22 +2076,29 @@ gboolean
 bacon_video_widget_set_audio_out_type (BaconVideoWidget *bvw,
                                        BaconVideoWidgetAudioOutType type)
 {
-  GstElement *audiosink = NULL;
+#ifdef HAVE_GSTREAMER_09
+  GstPad *pad;
+#endif /* HAVE_GSTREAMER_09 */
 
   g_return_val_if_fail (bvw != NULL, FALSE);
   g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), FALSE);
 
   if (type == bvw->priv->speakersetup)
     return FALSE;
+  else if (type == BVW_AUDIO_SOUND_AC3PASSTHRU)
+    return FALSE;
 
   bvw->priv->speakersetup = type;
   gconf_client_set_int (bvw->priv->gc,
       GCONF_PREFIX"/audio_output_type", type, NULL);
 
-  g_object_get (G_OBJECT (bvw->priv->play), "audio-sink", &audiosink, NULL);
-  if (GST_STATE (bvw->priv->play) >= GST_STATE_PAUSED) {
-    //gst_pad_renegotiate (gst_element_get_pad (audiosink, "sink"));
-  }
+#ifdef HAVE_GSTREAMER_09
+  pad = gst_element_get_pad (bvw->priv->audio_capsfilter, "sink");
+  GST_STREAM_LOCK (pad);
+  set_audio_filter (bvw);
+  GST_STREAM_UNLOCK (pad);
+  gst_object_unref (GST_OBJECT (pad));
+#endif /* HAVE_GSTREAMER_09 */
 
   return FALSE;
 }
@@ -1900,16 +2174,27 @@ bacon_video_widget_open_with_subtitle (B
 		  bvw->priv->mrl, "suburi", subtitle_uri, NULL);
   }
 
+  bvw->priv->cache_errors = TRUE;
+#ifdef HAVE_GSTREAMER_09
+  ret = (gst_element_set_state (bvw->priv->play, GST_STATE_PAUSED) !=
+      GST_STATE_CHANGE_FAILURE);
+#else
   ret = (gst_element_set_state (bvw->priv->play, GST_STATE_PAUSED) ==
-      GST_STATE_SUCCESS);
+      GST_STATE_CHANGE_SUCCESS);
+#endif /* HAVE_GSTREAMER_09 */
+
   if (!ret && !bvw->priv->got_redirect) {
     if (error) {
+#ifdef HAVE_GSTREAMER_09
+      while (g_main_iteration (FALSE));
+#endif /* HAVE_GSTREAMER_09 */
       if (bvw->priv->last_error) {
 	GError *e = bvw->priv->last_error;
 
 #define is_error(e, d, c) \
   (e->domain == GST_##d##_ERROR && \
    e->code == GST_##d##_ERROR_##c)
+
 	if (is_error (e, RESOURCE, NOT_FOUND) ||
 	    is_error (e, RESOURCE, OPEN_READ)) {
 	  if (strchr (mrl, ':') &&
@@ -1924,7 +2209,8 @@ bacon_video_widget_open_with_subtitle (B
 		  _("Location not found."));
 	    } else {
 	      g_set_error (error, BVW_ERROR, BVW_ERROR_FILE_PERMISSION,
-		  _("You don't have permission to open that location."));
+		  _("Could not open location; "
+		    "You may not have permission to open the file."));
 	    }
 	  }
 	} else if (e->domain == GST_RESOURCE_ERROR) {
@@ -1951,6 +2237,7 @@ bacon_video_widget_open_with_subtitle (B
     g_free (bvw->priv->mrl);
     bvw->priv->mrl = NULL;
   }
+  bvw->priv->cache_errors = FALSE;
 
   if (ret)
     g_signal_emit (bvw, bvw_table_signals[SIGNAL_CHANNELS_CHANGE], 0);
@@ -1973,40 +2260,44 @@ bacon_video_widget_play (BaconVideoWidge
     bvw->priv->last_error = NULL;
   }
 
+  bvw->priv->cache_errors = TRUE;
+#ifdef HAVE_GSTREAMER_09
   ret = (gst_element_set_state (GST_ELEMENT (bvw->priv->play),
-      GST_STATE_PLAYING) == GST_STATE_SUCCESS);
+      GST_STATE_PLAYING) != GST_STATE_CHANGE_FAILURE);
+#else
+  ret = (gst_element_set_state (GST_ELEMENT (bvw->priv->play),
+      GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS);
+#endif /* HAVE_GSTREAMER_09 */
+
   if (!ret) {
+#ifdef HAVE_GSTREAMER_09
+    while (g_main_iteration (FALSE));
+#endif
     g_set_error (error, BVW_ERROR, BVW_ERROR_GENERIC, _("Failed to play: %s"),
 	 (bvw->priv->last_error != NULL) ?
 	 bvw->priv->last_error->message : _("unknown error"));
   }
+  bvw->priv->cache_errors = FALSE;
 
   return ret;
 }
 
 gboolean
-bacon_video_widget_seek (BaconVideoWidget *bvw, float position, GError **gerror)
+bacon_video_widget_can_direct_seek (BaconVideoWidget *bvw)
 {
-  gint64 seek_time, length_nanos;
-
   g_return_val_if_fail (bvw != NULL, FALSE);
   g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), FALSE);
   g_return_val_if_fail (GST_IS_ELEMENT (bvw->priv->play), FALSE);
 
-  /* Resetting last_error to NULL */
-  if (bvw->priv->last_error) {
-    g_error_free (bvw->priv->last_error);
-    bvw->priv->last_error = NULL;
-  }
-
-  length_nanos = (gint64) (bvw->priv->stream_length * GST_MSECOND);
-  seek_time = (gint64) (length_nanos * position);
-
-  gst_element_seek (bvw->priv->play, GST_SEEK_METHOD_SET |
-		    GST_SEEK_FLAG_FLUSH | GST_FORMAT_TIME,
-		    seek_time);
+#ifdef HAVE_GSTREAMER_09
+  if (bvw->priv->mrl &&
+      (g_str_has_prefix (bvw->priv->mrl, "file://") ||
+       g_str_has_prefix (bvw->priv->mrl, "dvd://") ||
+       g_str_has_prefix (bvw->priv->mrl, "vcd://")))
+    return TRUE;
+#endif /* HAVE_GSTREAMER_09 */
 
-  return TRUE;
+  return FALSE;
 }
 
 gboolean
@@ -2022,13 +2313,37 @@ bacon_video_widget_seek_time (BaconVideo
     bvw->priv->last_error = NULL;
   }
 
+  bvw->priv->cache_errors = TRUE;
+#ifdef HAVE_GSTREAMER_09
+  gst_element_seek (bvw->priv->play, 1.0,
+		    GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
+		    GST_SEEK_TYPE_SET, time * GST_MSECOND,
+		    GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
+#else
   gst_element_seek (bvw->priv->play, GST_SEEK_METHOD_SET |
 		    GST_SEEK_FLAG_FLUSH | GST_FORMAT_TIME,
 		    time * GST_MSECOND);
+#endif
+  bvw->priv->cache_errors = FALSE;
 
   return TRUE;
 }
 
+gboolean
+bacon_video_widget_seek (BaconVideoWidget *bvw, float position, GError **error)
+{
+  gint64 seek_time, length_nanos;
+
+  g_return_val_if_fail (bvw != NULL, FALSE);
+  g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), FALSE);
+  g_return_val_if_fail (GST_IS_ELEMENT (bvw->priv->play), FALSE);
+
+  length_nanos = (gint64) (bvw->priv->stream_length * GST_MSECOND);
+  seek_time = (gint64) (length_nanos * position);
+
+  return bacon_video_widget_seek_time (bvw, seek_time / GST_MSECOND, error);
+}
+
 void
 bacon_video_widget_stop (BaconVideoWidget * bvw)
 {
@@ -2064,6 +2379,7 @@ bacon_video_widget_dvd_event (BaconVideo
   g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
   g_return_if_fail (GST_IS_ELEMENT (bvw->priv->play));
 
+#ifndef HAVE_GSTREAMER_09
   switch (type) {
     case BVW_DVD_ROOT_MENU:
     case BVW_DVD_TITLE_MENU:
@@ -2108,6 +2424,7 @@ bacon_video_widget_dvd_event (BaconVideo
     default:
       break;
   }
+#endif
 }
 
 void
@@ -2316,49 +2633,95 @@ bacon_video_widget_set_media_device (Bac
   bvw->priv->media_device = g_strdup (path);
 }
 
-static GstCaps *
-fixate_visualization (GstPad *pad, const GstCaps *in_caps,
-		      BaconVideoWidget *bvw)
+static void
+get_visualization_size (BaconVideoWidget *bvw,
+			int *w, int *h, int *fps)
 {
-  GstCaps *caps;
-  GstStructure *s;
-  int fps, w, h;
-
-  switch (bvw->priv->visq)
-    {
+  /* now see how close we can go */
+  switch (bvw->priv->visq) {
     case VISUAL_SMALL:
-      fps = 10;
-      w = 200;
-      h = 150;
+      *fps = 10;
+      *w = 200;
+      *h = 150;
       break;
     case VISUAL_NORMAL:
-      fps = 20;
-      w = 320;
-      h = 240;
+      *fps = 20;
+      *w = 320;
+      *h = 240;
       break;
     case VISUAL_LARGE:
-      fps = 25;
-      w = 640;
-      h = 480;
+      *fps = 25;
+      *w = 640;
+      *h = 480;
       break;
     case VISUAL_EXTRA_LARGE:
-      fps = 30;
-      w = 800;
-      h = 600;
+      *fps = 30;
+      *w = 800;
+      *h = 600;
       break;
     default:
       /* shut up warnings */
-      fps = w = h = 0;
+      *fps = *w = *h = 0;
       g_assert_not_reached ();
   }
+}
+
+#ifdef HAVE_GSTREAMER_09
+static void
+change_visualization_quality (BaconVideoWidget *bvw)
+{
+  GstPad *pad, *spad;
+  GstCaps *caps;
+  GstStructure *s;
+  int fps, w, h;
+
+  /* get size */
+  get_visualization_size (bvw, &w, &h, &fps);
+
+  /* first unset any old filter, otherwise _get_allowed_caps takes the
+   * old one into account. */
+  g_object_set (G_OBJECT (bvw->priv->vis_capsfilter),
+		"caps", NULL, NULL);
+
+  /* see what we can do */
+  pad = gst_element_get_pad (bvw->priv->vis_element, "src");
+  spad = gst_element_get_pad (bvw->priv->vis_element, "sink");
+  caps = gst_pad_get_allowed_caps (pad);
+
+  /* fixate */
+  s = gst_caps_get_structure (caps, 0);
+  gst_caps_structure_fixate_field_nearest_int (s, "width", w);
+  gst_caps_structure_fixate_field_nearest_int (s, "height", h);
+  gst_caps_structure_fixate_field_nearest_double (s, "framerate", fps);
+
+  /* set this */
+  g_object_set (G_OBJECT (bvw->priv->vis_capsfilter),
+		"caps", caps, NULL);
+
+  /* re-negotiate - FIXME: is this still needed? */
+  GST_STREAM_LOCK (spad);
+  gst_pad_set_caps (pad, NULL);
+  GST_STREAM_UNLOCK (spad);
+
+  gst_object_unref (GST_OBJECT (spad));
+  gst_object_unref (GST_OBJECT (pad));
+}
+#else /* HAVE_GSTREAMER_09 */
+static GstCaps *
+fixate_visualization (GstPad *pad, const GstCaps *in_caps,
+		      BaconVideoWidget *bvw)
+{
+  GstCaps *caps;
+  GstStructure *s;
+  int fps, w, h;
 
+  /* get size */
+  get_visualization_size (bvw, &w, &h, &fps);
   bvw->priv->video_width = w;
   bvw->priv->video_height = h;
-  if (!in_caps)
-    return NULL;
 
   /* simple please */
-  if (gst_caps_get_size (in_caps) > 1)
+  if (!in_caps || gst_caps_get_size (in_caps) > 1)
     return NULL;
 
   /* fixate */
@@ -2372,12 +2735,15 @@ fixate_visualization (GstPad *pad, const
   gst_caps_free (caps);
   return NULL;
 }
+#endif /* HAVE_GSTREAMER_09 */
 
 static void
 setup_vis (BaconVideoWidget * bvw)
 {
-  const GstElement *vis;
-  gint rel = -1, mic = 0;
+  GstElement *vis;
+
+#ifndef HAVE_GSTREAMER_09
+  static gint rel = -1, mic = 0;
 
   /* only if >= 0.8.6.1, else it'll hang after one song (refcount bug) */
   if (rel == -1) {
@@ -2387,17 +2753,47 @@ setup_vis (BaconVideoWidget * bvw)
     g_assert (p); /* otherwise we can't be here */
     if (sscanf (p->desc.version, "%*d.%*d.%d.%d", &rel, &mic) < 1)
       g_assert_not_reached ();
+  }
 
-    /* only if >= 0.8.6.1 */
-    if (rel < 6 || (rel == 6 && mic < 1)) {
-      g_warning ("Visualization disabled because your gst-plugins is too old (%d.%d.%d.%d)", 0, 8, rel, mic);
-      return;
-    }
+  /* only if >= 0.8.6.1 */
+  if (rel < 6 || (rel == 6 && mic < 1)) {
+    g_warning ("Visualization disabled because your gst-plugins is too old (%d.%d.%d.%d)", 0, 8, rel, mic);
+    return;
   }
+#endif /* !HAVE_GSTREAMER_09 */
 
   if (bvw->priv->show_vfx && bvw->priv->vis_element) {
+#ifdef HAVE_GSTREAMER_09
+    GstElement *bin;
+    GstPad *pad;
+
+    /* unparent */
+    g_object_set (G_OBJECT (bvw->priv->play),
+		  "vis-plugin", NULL, NULL);
+
+    bin = gst_bin_new ("vis-bin");
+    gst_object_ref (GST_OBJECT (bvw->priv->vis_capsfilter));
+    gst_object_ref (GST_OBJECT (bvw->priv->vis_element));
+    gst_bin_add_many (GST_BIN (bin), bvw->priv->vis_element,
+		      bvw->priv->vis_capsfilter, NULL);
+    vis = bin;
+
+    pad = gst_element_get_pad (bvw->priv->vis_element, "sink");
+    gst_element_add_pad (bin, gst_ghost_pad_new ("sink", pad));
+    gst_object_unref (GST_OBJECT (pad));
+
+    pad = gst_element_get_pad (bvw->priv->vis_capsfilter, "src");
+    gst_element_add_pad (bin, gst_ghost_pad_new ("src", pad));
+    gst_object_unref (GST_OBJECT (pad));
+
+    gst_element_link_pads (bvw->priv->vis_element, "src",
+			   bvw->priv->vis_capsfilter, "sink");
+
+    change_visualization_quality (bvw);
+#else /* HAVE_GSTREAMER_09 */
     gst_object_ref (GST_OBJECT (bvw->priv->vis_element));
     vis = bvw->priv->vis_element;
+#endif /* HAVE_GSTREAMER_09 */
   } else {
     vis = NULL;
   }
@@ -2422,89 +2818,97 @@ bacon_video_widget_set_show_visuals (Bac
   return TRUE;
 }
 
-GList *
-bacon_video_widget_get_visuals_list (BaconVideoWidget * bvw)
+static gboolean
+filter_features (GstPluginFeature * feature, gpointer data)
 {
-  GList *pool_registries = NULL, *registries = NULL, *vis_plugins_list = NULL;
-  GList *plugins = NULL, *features = NULL;
-
-  g_return_val_if_fail (bvw != NULL, NULL);
-  g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), NULL);
-  g_return_val_if_fail (GST_IS_ELEMENT (bvw->priv->play), NULL);
-
-  /* Cache */
-  if (bvw->priv->vis_plugins_list)
-    {
-      return bvw->priv->vis_plugins_list;
-    }
-
-  pool_registries = gst_registry_pool_list ();
-
-  registries = pool_registries;
+  GstElementFactory *f;
 
-  while (registries)
-    {
-      GstRegistry *registry = GST_REGISTRY (registries->data);
-
-      plugins = registry->plugins;
+  if (!GST_IS_ELEMENT_FACTORY (feature))
+    return FALSE;
+  f = GST_ELEMENT_FACTORY (feature);
+  if (!g_strrstr (gst_element_factory_get_klass (f), "Visualization"))
+    return FALSE;
 
-      while (plugins)
-	{
-	  GstPlugin *plugin = GST_PLUGIN (plugins->data);
+  return TRUE;
+}
 
-	  features = gst_plugin_get_feature_list (plugin);
+static GList *
+get_visualization_features (void)
+{
+#ifdef HAVE_GSTREAMER_09
+  return gst_registry_feature_filter (gst_registry_get_default (),
+      filter_features, FALSE, NULL);
+#else
+  return gst_registry_pool_feature_filter (
+      (GstPluginFeatureFilter) filter_features, FALSE, NULL);
+#endif
+}
 
-	  while (features)
-	    {
-	      GstPluginFeature *feature = GST_PLUGIN_FEATURE (features->data);
-
-	      if (GST_IS_ELEMENT_FACTORY (feature))
-		{
-		  GstElementFactory *factory = GST_ELEMENT_FACTORY (feature);
-		  if (g_strrstr (factory->details.klass, "Visualization"))
-		    {
-		      vis_plugins_list = g_list_append (vis_plugins_list,
-							(char *)
-							g_strdup
-							(GST_OBJECT_NAME
-							 (factory)));
-		    }
-		}
-	      features = g_list_next (features);
-	    }
+static void
+add_longname (GstElementFactory *f, GList ** to)
+{
+  *to = g_list_append (*to, (gchar *) gst_element_factory_get_longname (f));
+}
 
-	  plugins = g_list_next (plugins);
-	}
+GList *
+bacon_video_widget_get_visuals_list (BaconVideoWidget * bvw)
+{
+  GList *features, *names = NULL;
 
-      registries = g_list_next (registries);
-    }
+  g_return_val_if_fail (bvw != NULL, NULL);
+  g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), NULL);
+  g_return_val_if_fail (GST_IS_ELEMENT (bvw->priv->play), NULL);
 
-  g_list_free (pool_registries);
-  pool_registries = NULL;
+  if (bvw->priv->vis_plugins_list) {
+    return bvw->priv->vis_plugins_list;
+  }
 
-  bvw->priv->vis_plugins_list = vis_plugins_list;
+  features = get_visualization_features ();
+  g_list_foreach (features, (GFunc) add_longname, &names);
+  g_list_free (features);
+  bvw->priv->vis_plugins_list = names;
 
-  return vis_plugins_list;
+  return names;
 }
 
 gboolean
 bacon_video_widget_set_visuals (BaconVideoWidget * bvw, const char *name)
 {
+  GList *features, *item;
+  GstElementFactory *fac = NULL;
   GstElement *old_vis = bvw->priv->vis_element;
 
   g_return_val_if_fail (bvw != NULL, FALSE);
   g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), FALSE);
   g_return_val_if_fail (GST_IS_ELEMENT (bvw->priv->play), FALSE);
 
-  bvw->priv->vis_element = gst_element_factory_make (name,
-                                                     "vis_plugin_element");
+  /* find */
+  features = get_visualization_features ();
+  for (item = features; item != NULL; item = item->next) {
+    GstElementFactory *f = item->data;
+
+    if (!strcmp (name, gst_element_factory_get_longname (f))) {
+      fac = f;
+      break;
+    }
+  }
+  g_list_free (features);
+  /* could be the user has an outdated preference, etc -- fail silently */
+  if (!fac)
+    return FALSE;
+
+  /* now create */
+  bvw->priv->vis_element = gst_element_factory_create (fac, "vis-plugin");
+
   if (!bvw->priv->vis_element) {
     bvw->priv->vis_element = old_vis;
     return FALSE;
   }
 
+#ifndef HAVE_GSTREAMER_09
   g_signal_connect (gst_element_get_pad (bvw->priv->vis_element, "src"),
 		    "fixate", G_CALLBACK (fixate_visualization), bvw);
+#endif /* !HAVE_GSTREAMER_09 */
 
   gconf_client_set_string (bvw->priv->gc,
       GCONF_PREFIX"/visual", name, NULL);
@@ -2531,9 +2935,11 @@ bacon_video_widget_set_visuals_quality (
   gconf_client_set_int (bvw->priv->gc,
       GCONF_PREFIX"/visual_quality", quality, NULL);
 
-  if (GST_STATE (bvw->priv->play) >= GST_STATE_PAUSED) {
-    //gst_pad_renegotiate (gst_element_get_pad (bvw->priv->vis_element, "src"));
+#ifdef HAVE_GSTREAMER_09
+  if (bvw->priv->vis_element && bvw->priv->show_vfx) {
+    change_visualization_quality (bvw);
   }
+#endif /* HAVE_GSTREAMER_09 */
 }
 
 gboolean
@@ -2873,6 +3279,10 @@ bacon_video_widget_get_mrls (BaconVideoW
 
   switch (type) {
     case MEDIA_TYPE_CDDA: {
+#ifdef HAVE_GSTREAMER_09
+      gchar *uri[] = { "cdda://", NULL };
+      mrls = g_strdupv (uri);
+#else
       GstElement *cdda;
       gint64 tracks;
       GstFormat fmt;
@@ -2885,11 +3295,19 @@ bacon_video_widget_get_mrls (BaconVideoW
 	gst_object_unref (GST_OBJECT (cdda));
         return NULL;
       }
+#ifdef HAVE_GSTREAMER_09
+      if (gst_element_set_state (cdda, GST_STATE_PAUSED) ==
+              GST_STATE_CHANGE_FAILURE) {
+	gst_object_unref (GST_OBJECT (cdda));
+	return NULL;
+      }
+#else
       if (gst_element_set_state (cdda, GST_STATE_PAUSED) !=
-              GST_STATE_SUCCESS) {
+              GST_STATE_CHANGE_SUCCESS) {
 	gst_object_unref (GST_OBJECT (cdda));
 	return NULL;
       }
+#endif /* HAVE_GSTREAMER_09 */
       if (!gst_pad_query (gst_element_get_pad (cdda, "src"),
               GST_QUERY_TOTAL, &fmt, &tracks)) {
 	gst_element_set_state (cdda, GST_STATE_NULL);
@@ -2902,6 +3320,7 @@ bacon_video_widget_get_mrls (BaconVideoW
       while (tracks-- > 0) {
 	mrls[tracks] = g_strdup_printf ("cdda://%d", (gint) tracks + 1);
       }
+#endif /* HAVE_GSTREAMER_09 */
       break;
     }
     case MEDIA_TYPE_VCD: {
@@ -2949,12 +3368,22 @@ bacon_video_widget_get_metadata_string (
 					   GST_TAG_ARTIST, 0, &string);
       break;
     case BVW_INFO_YEAR: {
+#ifdef HAVE_GSTREAMER_09
+      GDate *date;
+      if ((res = gst_tag_list_get_date (bvw->priv->tagcache,
+					GST_TAG_DATE, &date))) {
+	string = g_strdup_printf ("%d", g_date_get_year (date));
+        g_date_free (date);
+      }
+#else
       guint julian;
       if ((res = gst_tag_list_get_uint (bvw->priv->tagcache,
 					GST_TAG_DATE, &julian))) {
-	GDate *d = g_date_new_julian (julian);
-	string = g_strdup_printf ("%d", g_date_get_year (d));
+	GDate *date = g_date_new_julian (julian);
+	string = g_strdup_printf ("%d", g_date_get_year (date));
+        g_date_free (date);
       }
+#endif /* HAVE_GSTREAMER_09 */
       break;
     }
     case BVW_INFO_ALBUM:
@@ -3007,7 +3436,7 @@ bacon_video_widget_get_metadata_int (Bac
       break;
     case BVW_INFO_TRACK_NUMBER:
       if (!gst_tag_list_get_uint (bvw->priv->tagcache,
-				  GST_TAG_TRACK_NUMBER, &integer))
+				  GST_TAG_TRACK_NUMBER, (guint *) &integer))
         integer = 0;
       break;
     case BVW_INFO_DIMENSION_X:
@@ -3181,7 +3610,6 @@ bacon_video_widget_get_current_frame (Ba
   g_list_foreach (streaminfo, (GFunc) g_object_ref, NULL);
   for (; streaminfo != NULL; streaminfo = streaminfo->next) {
     GObject *info = streaminfo->data;
-    GstPad *real;
     gint type;
     GParamSpec *pspec;
     GEnumValue *val;
@@ -3194,14 +3622,20 @@ bacon_video_widget_get_current_frame (Ba
 
     if (strstr (val->value_name, "VIDEO")) {
       GstPad *pad = NULL;
+#ifndef HAVE_GSTREAMER_09
+      GstPad *real;
+#endif /* !HAVE_GSTREAMER_09 */
 
       g_object_get (info, "object", &pad, NULL);
+#ifdef HAVE_GSTREAMER_09
+      from = gst_pad_get_negotiated_caps (pad);
+#else
       /* hack for 0.8.5 */
       if (!pad)
         g_object_get (info, "pad", &pad, NULL);
-      g_assert (GST_IS_PAD (pad));
       real = (GstPad *) GST_PAD_REALIZE (pad);
       from = gst_caps_copy (GST_PAD_CAPS (real));
+#endif /* HAVE_GSTREAMER_09 */
       break;
     }
   }
@@ -3268,9 +3702,17 @@ G_DEFINE_TYPE(BaconVideoWidget, bacon_vi
 struct poptOption *
 bacon_video_widget_get_popt_table (void)
 {
+#ifdef HAVE_GSTREAMER_09
+  static struct poptOption gstreamer_options[] = {
+    POPT_TABLEEND
+  };
+  gst_init (NULL, NULL);
+  return gstreamer_options;
+#else
   /* Initializing GStreamer backend and parse our options from the command 
      line options */
   return (struct poptOption *) gst_init_get_popt_table ();
+#endif
 }
 
 void
@@ -3289,6 +3731,29 @@ bacon_video_widget_error_quark (void)
   return q;
 }
 
+#ifdef HAVE_GSTREAMER_09
+/* fold function to pick the best colorspace element */
+static gboolean
+find_colorbalance_element (GstElement *element, GValue * ret, GstElement **cb)
+{
+  GstColorBalanceClass *cb_class;
+
+  if (!GST_IS_COLOR_BALANCE (element))
+    return TRUE;
+
+  cb_class = GST_COLOR_BALANCE_GET_CLASS (element);
+  if (GST_COLOR_BALANCE_TYPE (cb_class) == GST_COLOR_BALANCE_HARDWARE) {
+    gst_object_replace ((GstObject **) cb, (GstObject *) element);
+    /* shortcuts the fold */
+    return FALSE;
+  } else if (*cb == NULL) {
+    gst_object_replace ((GstObject **) cb, (GstObject *) element);
+    return TRUE;
+  } else {
+    return TRUE;
+  }
+}
+#else /* HAVE_GSTREAMER_09 */
 static void
 out_error (GstElement *el, GstElement *src,
 	   GError *err, gchar *debug,
@@ -3298,6 +3763,7 @@ out_error (GstElement *el, GstElement *s
     *((GError **) data) = g_error_copy (err);
   }
 }
+#endif /* HAVE_GSTREAMER_09 */
 
 GtkWidget *
 bacon_video_widget_new (int width, int height,
@@ -3306,9 +3772,12 @@ bacon_video_widget_new (int width, int h
   GConfValue *confvalue;
   BaconVideoWidget *bvw;
   GstElement *audio_sink = NULL, *video_sink = NULL;
-  gulong sig1, sig2;
   gint i;
-  GError *local_err = NULL;
+#ifdef HAVE_GSTREAMER_09
+  GstBus *bus;
+#else
+  gulong sig;
+#endif /* HAVE_GSTREAMER_09 */
 
   bvw = BACON_VIDEO_WIDGET (g_object_new
                             (bacon_video_widget_get_type (), NULL));
@@ -3321,7 +3790,19 @@ bacon_video_widget_new (int width, int h
     g_object_unref (G_OBJECT (bvw));
     return NULL;
   }
-  
+
+#ifdef HAVE_GSTREAMER_09
+  bus = gst_pipeline_get_bus (GST_PIPELINE (bvw->priv->play));
+  gst_bus_add_signal_watch (bus);
+
+  g_signal_connect (bus, "message", 
+                    G_CALLBACK (bacon_video_widget_bus_message_cb),
+                    bvw);
+
+  bvw->priv->vis_capsfilter = gst_element_factory_make ("capsfilter",
+							"vis-capsfilter");
+#endif /* HAVE_GSTREAMER_09 */
+
   bvw->priv->speakersetup = BVW_AUDIO_SOUND_STEREO;
   bvw->priv->media_device = g_strdup ("/dev/dvd");
   bvw->priv->init_width = 240;
@@ -3336,6 +3817,7 @@ bacon_video_widget_new (int width, int h
   bvw->priv->cursor_shown = TRUE;
   bvw->priv->logo_mode = TRUE;
   bvw->priv->auto_resize = TRUE;
+  bvw->priv->cache_errors = TRUE;
 
   /* gconf setting in backend */
   bvw->priv->gc = gconf_client_get_default ();
@@ -3343,20 +3825,27 @@ bacon_video_widget_new (int width, int h
       cb_gconf, bvw, NULL, NULL);
 
   if (type == BVW_USE_TYPE_VIDEO || type == BVW_USE_TYPE_AUDIO) {
+#ifdef HAVE_GSTREAMER_09
+    audio_sink = gst_element_factory_make ("gconfaudiosink", "audio-sink");
+    if (audio_sink)
+      gst_element_set_bus (audio_sink, bus);
+#else
     audio_sink = gst_gconf_get_default_audio_sink ();
-    if (!GST_IS_ELEMENT (audio_sink))
-      {
-        g_message ("failed to render default audio sink from gconf");
-        return NULL;
-      }
+#endif
+  } else {
+    audio_sink = gst_element_factory_make ("fakesink", "audio-fake-sink");
   }
 
   if (type == BVW_USE_TYPE_VIDEO) {
+#ifdef HAVE_GSTREAMER_09
+    video_sink = gst_element_factory_make ("gconfvideosink", "video-sink");
+    if (video_sink)
+      gst_element_set_bus (video_sink, bus);
+#else
     video_sink = gst_gconf_get_default_video_sink ();
-    if (!GST_IS_ELEMENT (video_sink)) {
-        g_message ("failed to render default video sink from gconf");
-        return NULL;
-    } else {
+#endif
+
+    if (video_sink) {
       GDate d;
 
       g_date_clear (&d, 1);
@@ -3375,11 +3864,20 @@ bacon_video_widget_new (int width, int h
           puzzle = gst_element_factory_make ("puzzle", NULL);
           if (puzzle) {
             GstElement *bin = gst_bin_new ("videosinkbin");
+#ifdef HAVE_GSTREAMER_09
+            GstPad *pad;
+#endif /* HAVE_GSTREAMER_09 */
 
             gst_bin_add_many (GST_BIN (bin), puzzle, video_sink, NULL);
-            gst_element_link (puzzle, video_sink);
+            gst_element_link_pads (puzzle, "src", video_sink, "sink");
+#ifdef HAVE_GSTREAMER_09
+            pad = gst_element_get_pad (puzzle, "sink");
+            gst_element_add_pad (bin, gst_ghost_pad_new ("sink", pad));
+            gst_object_unref (pad);
+#else /* HAVE_GSTREAMER_09 */
             gst_element_add_ghost_pad (bin,
                 gst_element_get_pad (puzzle, "sink"), "sink");
+#endif /* HAVE_GSTREAMER_09 */
             video_sink = bin;
           }
         }
@@ -3388,24 +3886,31 @@ bacon_video_widget_new (int width, int h
           gconf_value_free (confvalue);
       }
     }
-  }
-
-  if (video_sink == NULL) {
-    video_sink = gst_element_factory_make ("fakesink", "fakevideosink");
-  }
-  if (audio_sink == NULL) {
-    audio_sink = gst_element_factory_make ("fakesink", "fakeaudiosink");
+  } else {
+    video_sink = gst_element_factory_make ("fakesink", "video-fake-sink");
   }
 
   /* check video */
-  sig1 = g_signal_connect (video_sink, "error", G_CALLBACK (out_error),
-      			   &local_err);
-  if (gst_element_set_state (video_sink,
-			     GST_STATE_READY) != GST_STATE_SUCCESS) {
+#ifndef HAVE_GSTREAMER_09
+  sig = g_signal_connect (video_sink, "error", G_CALLBACK (out_error),
+      			  &bvw->priv->last_error);
+  if (!video_sink ||
+      gst_element_set_state (video_sink,
+			     GST_STATE_READY) != GST_STATE_CHANGE_SUCCESS) {
+#else
+  if (!video_sink ||
+      gst_element_set_state (video_sink,
+			     GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
+#endif /* !HAVE_GSTREAMER_09 */
+
     /* Videosink not available; give user feedback on what to do now */
     if (err) {
-      if (local_err && local_err->domain == GST_RESOURCE_ERROR) {
-	switch (local_err->code) {
+#ifdef HAVE_GSTREAMER_09
+      while (g_main_iteration (FALSE));
+#endif /* HAVE_GSTREAMER_09 */
+      if (bvw->priv->last_error &&
+	  bvw->priv->last_error->domain == GST_RESOURCE_ERROR) {
+	switch (bvw->priv->last_error->code) {
 	  case GST_RESOURCE_ERROR_NOT_FOUND:
 	  case GST_RESOURCE_ERROR_OPEN_WRITE:
 	    /* can use the default below... */
@@ -3421,28 +3926,46 @@ bacon_video_widget_new (int width, int h
       }
       if (!*err) {
 	/* "default" */
-	g_set_error (err, BVW_ERROR, BVW_ERROR_VIDEO_PLUGIN,
-	    _("Failed to open video output. It may not be available. "
-	      "Please select another video output in the Multimedia Systems Selector."));
+	if (video_sink) {
+	  g_set_error (err, BVW_ERROR, BVW_ERROR_VIDEO_PLUGIN,
+	      _("Failed to open video output. It may not be available. "
+	        "Please select another video output in the Multimedia Systems Selector."));
+	} else {
+	  g_set_error (err, BVW_ERROR, BVW_ERROR_VIDEO_PLUGIN,
+	      _("Could not find the video output. "
+		"You may need to install additional GStreamer plugins, or select another video output in the Multimedia Systems Selector."));
+	}
       }
-      if (local_err)
-	g_error_free (local_err);
+      if (bvw->priv->last_error)
+	g_error_free (bvw->priv->last_error);
     }
     gst_object_unref (GST_OBJECT (video_sink));
     gst_object_unref (GST_OBJECT (audio_sink));
     g_free (bvw);
     return NULL;
   }
-  g_signal_handler_disconnect (video_sink, sig1);
+#ifndef HAVE_GSTREAMER_09
+  g_signal_handler_disconnect (video_sink, sig);
 
   /* check audio */
-  sig2 = g_signal_connect (audio_sink, "error", G_CALLBACK (out_error),
-			   &local_err);
-  if (gst_element_set_state (audio_sink,
-			     GST_STATE_READY) != GST_STATE_SUCCESS) {
+  sig = g_signal_connect (audio_sink, "error", G_CALLBACK (out_error),
+			  &bvw->priv->last_error);
+  if (!audio_sink ||
+      gst_element_set_state (audio_sink,
+			     GST_STATE_READY) != GST_STATE_CHANGE_SUCCESS) {
+#else
+  if (!audio_sink ||
+      gst_element_set_state (audio_sink,
+			     GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
+#endif /* !HAVE_GSTREAMER_09 */
+
     if (err) {
-      if (local_err && local_err->domain == GST_RESOURCE_ERROR) {
-	switch (local_err->code) {
+#ifdef HAVE_GSTREAMER_09
+      while (g_main_iteration (FALSE));
+#endif /* HAVE_GSTREAMER_09 */
+      if (bvw->priv->last_error &&
+	  bvw->priv->last_error->domain == GST_RESOURCE_ERROR) {
+	switch (bvw->priv->last_error->code) {
 	  case GST_RESOURCE_ERROR_OPEN_WRITE:
 	  case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
 	    /* use default below */
@@ -3463,33 +3986,68 @@ bacon_video_widget_new (int width, int h
 	}
       }
       if (!*err) {
-	/* "default" */
-        g_set_error (err, BVW_ERROR, BVW_ERROR_AUDIO_PLUGIN,
-	    _("Failed to open audio output. You may not have permission to open the sound device, or the sound server may not be running. "
-	      "Please select another audio output in the Multimedia Systems Selector."));
+	if (audio_sink) {
+	  /* "default" */
+          g_set_error (err, BVW_ERROR, BVW_ERROR_AUDIO_PLUGIN,
+	      _("Failed to open audio output. You may not have permission to open the sound device, or the sound server may not be running. "
+	        "Please select another audio output in the Multimedia Systems Selector."));
+	} else {
+	  g_set_error (err, BVW_ERROR, BVW_ERROR_AUDIO_PLUGIN,
+	      _("Could not find the audio output. "
+		"You may need to install additional GStreamer plugins, or select another audio output in the Multimedia Systems Selector"));
+	}
       }
-      if (local_err)
-	g_error_free (local_err);
+      if (bvw->priv->last_error)
+	g_error_free (bvw->priv->last_error);
     }
     gst_object_unref (GST_OBJECT (video_sink));
     gst_object_unref (GST_OBJECT (audio_sink));
     g_free (bvw);
     return NULL;
   }
+#ifndef HAVE_GSTREAMER_09
   /* somehow, alsa hangs? */
   gst_element_set_state (audio_sink, GST_STATE_NULL);
-  g_signal_handler_disconnect (audio_sink, sig2);
+  g_signal_handler_disconnect (audio_sink, sig);
+#endif /* !HAVE_GSTREAMER_09 */
+
+#ifdef HAVE_GSTREAMER_09
+  do {
+    GstElement *bin;
+    GstPad *pad;
+
+    bvw->priv->audio_capsfilter =
+        gst_element_factory_make ("capsfilter", "audiofilter");
+    bin = gst_bin_new ("audiosinkbin");
+    gst_bin_add_many (GST_BIN (bin),
+	bvw->priv->audio_capsfilter, audio_sink, NULL);
+    gst_element_link_pads (bvw->priv->audio_capsfilter, "src",
+	audio_sink, "sink");
+
+    pad = gst_element_get_pad (bvw->priv->audio_capsfilter, "sink");
+    gst_element_add_pad (bin, gst_ghost_pad_new ("sink", pad));
+    gst_object_unref (pad);
+
+    audio_sink = bin;
+  } while (0);
+#else
+  g_signal_connect (GST_PAD_REALIZE (gst_element_get_pad (audio_sink, "sink")),
+		    "fixate", G_CALLBACK (cb_audio_fixate), (gpointer) bvw);
+#endif /* HAVE_GSTREAMER_09 */
 
   /* now tell playbin */
   g_object_set (G_OBJECT (bvw->priv->play), "video-sink",
 		video_sink, NULL);
   g_object_set (G_OBJECT (bvw->priv->play), "audio-sink",
 		audio_sink, NULL);
-  g_signal_connect (GST_PAD_REALIZE (gst_element_get_pad (audio_sink, "sink")),
-		    "fixate", G_CALLBACK (cb_audio_fixate), (gpointer) bvw);
 
   bvw->priv->vis_plugins_list = NULL;
+  bvw->priv->cache_errors = FALSE;
+#ifdef HAVE_GSTREAMER_09
+  gst_object_unref (bus);
+#endif /* HAVE_GSTREAMER_09 */
 
+#ifndef HAVE_GSTREAMER_09
   g_signal_connect (G_OBJECT (bvw->priv->play), "eos",
 		    (GtkSignalFunc) got_eos, (gpointer) bvw);
   g_signal_connect (G_OBJECT (bvw->priv->play), "state-change",
@@ -3500,12 +4058,15 @@ bacon_video_widget_new (int width, int h
 		    G_CALLBACK (got_error), (gpointer) bvw);
   g_signal_connect (G_OBJECT (bvw->priv->play), "buffering",
 		    G_CALLBACK (got_buffering), (gpointer) bvw);
+#endif /* !HAVE_GSTREAMER_09 */
   g_signal_connect (G_OBJECT (bvw->priv->play), "notify::source",
 		    G_CALLBACK (got_source), (gpointer) bvw);
   g_signal_connect (G_OBJECT (bvw->priv->play), "notify::stream-info",
 		    G_CALLBACK (stream_info_set), (gpointer) bvw);
-  g_signal_connect (G_OBJECT (bvw->priv->play), "group-switch",
-		    G_CALLBACK (group_switch), (gpointer) bvw);
+  if (TOTEM_OBJECT_HAS_SIGNAL (bvw->priv->play, "group-switch") != FALSE) {
+    g_signal_connect (G_OBJECT (bvw->priv->play), "group-switch",
+		      G_CALLBACK (group_switch), (gpointer) bvw);
+  }
   if (TOTEM_OBJECT_HAS_SIGNAL (bvw->priv->play, "got-redirect") != FALSE) {
     g_signal_connect (G_OBJECT (bvw->priv->play), "got-redirect",
 		      G_CALLBACK (got_redirect), (gpointer) bvw);
@@ -3514,13 +4075,34 @@ bacon_video_widget_new (int width, int h
   /* We try to get an element supporting XOverlay interface */
   if (type == BVW_USE_TYPE_VIDEO && GST_IS_BIN (bvw->priv->play)) {
     GstElement *element = NULL;
+#ifdef HAVE_GSTREAMER_09
+    GstIterator *iter;
+#else /* HAVE_GSTREAMER_09 */
     GList *elements = NULL, *l_elements = NULL;
-    
-    element = gst_bin_get_by_interface (GST_BIN (video_sink),
-                                        GST_TYPE_X_OVERLAY);
+#endif /* HAVE_GSTREAMER_09 */
+
+    /* get videosink */
+    if (GST_IS_BIN (video_sink)) {
+      element = gst_bin_get_by_interface (GST_BIN (video_sink),
+					  GST_TYPE_X_OVERLAY);
+    } else {
+      element = video_sink;
+    }
     if (GST_IS_X_OVERLAY (element))
       bvw->priv->xoverlay = GST_X_OVERLAY (element);
-    
+
+#ifdef HAVE_GSTREAMER_09
+    iter = gst_bin_iterate_all_by_interface (GST_BIN (bvw->priv->play),
+					     GST_TYPE_COLOR_BALANCE);
+    /* naively assume no resync */
+    element = NULL;
+    gst_iterator_fold (iter,
+        (GstIteratorFoldFunction) find_colorbalance_element, NULL, &element);
+    gst_iterator_free (iter);
+
+    if (element)
+      bvw->priv->balance = GST_COLOR_BALANCE (element);
+#else /* HAVE_GSTREAMER_09 */
     /* Get them all and prefer hardware one */
     elements = gst_bin_get_all_by_interface (GST_BIN (bvw->priv->play),
                                              GST_TYPE_COLOR_BALANCE);
@@ -3559,6 +4141,7 @@ bacon_video_widget_new (int width, int h
       {
         bvw->priv->balance = GST_COLOR_BALANCE (element);
       }
+#endif /* HAVE_GSTREAMER_09 */
   }
 
   /* Setup brightness and contrast */
@@ -3575,11 +4158,24 @@ bacon_video_widget_new (int width, int h
   /* audio out, if any */
   confvalue = gconf_client_get_without_default (bvw->priv->gc,
       GCONF_PREFIX"/audio_output_type", NULL);
+#ifdef HAVE_GSTREAMER_09
+  if (confvalue != NULL &&
+      (type != BVW_USE_TYPE_METADATA && type != BVW_USE_TYPE_CAPTURE)) {
+    bvw->priv->speakersetup = gconf_value_get_int (confvalue);
+    bvw->priv->speakersetup = gconf_value_get_int (confvalue) - 1;
+    bacon_video_widget_set_audio_out_type (bvw, bvw->priv->speakersetup + 1);
+    gconf_value_free (confvalue);
+  } else {
+    bvw->priv->speakersetup = -1;
+    bacon_video_widget_set_audio_out_type (bvw, BVW_AUDIO_SOUND_STEREO);
+  }
+#else /* HAVE_GSTREAMER_09 */
   if (confvalue != NULL &&
       (type != BVW_USE_TYPE_METADATA && type != BVW_USE_TYPE_CAPTURE)) {
     bvw->priv->speakersetup = gconf_value_get_int (confvalue);
     gconf_value_free (confvalue);
   }
+#endif /* HAVE_GSTREAMER_09 */
 
   /* visualization */
   confvalue = gconf_client_get_without_default (bvw->priv->gc,
@@ -3602,8 +4198,8 @@ bacon_video_widget_new (int width, int h
         gst_element_factory_make (gconf_value_get_string (confvalue), NULL);
     gconf_value_free (confvalue);
   }
+  setup_vis ();
 #endif
-  setup_vis (bvw);
 
   /* tv/conn (not used yet) */
   confvalue = gconf_client_get_without_default (bvw->priv->gc,
Index: src/backend/bacon-video-widget-xine.c
===================================================================
RCS file: /cvs/gnome/totem/src/backend/bacon-video-widget-xine.c,v
retrieving revision 1.208
diff -u -p -r1.208 bacon-video-widget-xine.c
--- src/backend/bacon-video-widget-xine.c	24 Sep 2005 19:15:08 -0000	1.208
+++ src/backend/bacon-video-widget-xine.c	19 Oct 2005 10:17:25 -0000
@@ -2150,6 +2150,12 @@ bacon_video_widget_play (BaconVideoWidge
 	return TRUE;
 }
 
+gboolean
+bacon_video_widget_can_direct_seek (BaconVideoWidget *bvw)
+{
+	return FALSE;
+}
+
 gboolean bacon_video_widget_seek (BaconVideoWidget *bvw, float position,
 		GError **gerror)
 {
Index: src/backend/bacon-video-widget.h
===================================================================
RCS file: /cvs/gnome/totem/src/backend/bacon-video-widget.h,v
retrieving revision 1.63
diff -u -p -r1.63 bacon-video-widget.h
--- src/backend/bacon-video-widget.h	10 Jul 2005 21:05:07 -0000	1.63
+++ src/backend/bacon-video-widget.h	19 Oct 2005 10:17:25 -0000
@@ -134,6 +134,7 @@ gboolean bacon_video_widget_seek		 (Baco
 gboolean bacon_video_widget_seek_time		 (BaconVideoWidget *bvw,
 						  gint64 time,
 						  GError **error);
+gboolean bacon_video_widget_can_direct_seek	 (BaconVideoWidget *bvw);
 float bacon_video_widget_get_position            (BaconVideoWidget *bvw);
 gint64 bacon_video_widget_get_current_time       (BaconVideoWidget *bvw);
 gint64 bacon_video_widget_get_stream_length      (BaconVideoWidget *bvw);
Index: src/backend/gstscreenshot.c
===================================================================
RCS file: /cvs/gnome/totem/src/backend/gstscreenshot.c,v
retrieving revision 1.1
diff -u -p -r1.1 gstscreenshot.c
--- src/backend/gstscreenshot.c	8 Oct 2004 18:06:03 -0000	1.1
+++ src/backend/gstscreenshot.c	19 Oct 2005 10:17:26 -0000
@@ -24,6 +24,100 @@
 #include <gst/gst.h>
 #include "gstscreenshot.h"
 
+#ifdef HAVE_GSTREAMER_09
+
+static GstFlowReturn
+have_data (GstPad * pad, GstBuffer * buf)
+{
+  g_object_set_data (G_OBJECT (pad), "data", buf);
+  return GST_FLOW_OK;
+}
+
+static GstCaps *
+get_any (GstPad * pad)
+{
+  return gst_caps_new_any ();
+}
+
+GstBuffer *
+bvw_frame_conv_convert (GstBuffer * buf,
+    GstCaps * from, GstCaps * to)
+{
+  GstElement *pipe, *csp, *scl, *flt;
+  GstPad *in, *out, *tmp1, *tmp2;
+  GstBuffer *ret;
+  GstCaps *tcaps;
+
+  /* setup */
+  pipe = gst_pipeline_new ("test");
+  csp = gst_element_factory_make ("ffmpegcolorspace", "csp");
+  scl = gst_element_factory_make ("identity", "scl");
+  flt = gst_element_factory_make ("capsfilter", "flt");
+  if (!csp || !scl || !flt) {
+    g_warning ("missing elements, please fix installation");
+    return NULL;
+  }
+  gst_bin_add_many (GST_BIN (pipe), csp, scl, flt, NULL);
+
+  /* own pads */
+  in = gst_pad_new ("in", GST_PAD_SRC);
+  out = gst_pad_new ("out", GST_PAD_SINK);
+  gst_pad_set_chain_function (out, have_data);
+  gst_pad_set_getcaps_function (in, get_any);
+  gst_pad_set_getcaps_function (out, get_any);
+  gst_element_add_pad (pipe, in);
+  gst_element_add_pad (pipe, out);
+
+  /* link */
+  g_object_set (G_OBJECT (flt), "caps", to, NULL);
+  tmp1 = gst_element_get_pad (csp, "sink");
+  tmp2 = gst_element_get_pad (flt, "src");
+  if (gst_pad_link (in, tmp1) < 0 ||
+      !gst_element_link_pads (csp, "src", scl, "sink") ||
+      !gst_element_link_pads (scl, "src", flt, "sink") ||
+      gst_pad_link (tmp2, out) < 0) {
+    g_warning ("Setup failed");
+    return NULL;
+  }
+  gst_object_unref (GST_OBJECT (tmp1));
+  gst_object_unref (GST_OBJECT (tmp2));
+
+  /* activate */
+  if (gst_element_set_state (pipe, GST_STATE_PAUSED) != GST_STATE_CHANGE_SUCCESS) {
+    g_warning ("Failed to set state on elements - fixme");
+    return NULL;
+  } else if (!gst_pad_set_caps (in, from)) {
+    gchar *s = gst_caps_to_string (from);
+    g_warning ("Pad did not accept %s", s);
+    g_free (s);
+    return NULL;
+  }
+
+  /* now push data and the chain function will be called */
+  if (gst_pad_push (in, buf) != GST_FLOW_OK) {
+    g_warning ("Wrong state - fixme");
+    return NULL;
+  }
+  ret = g_object_get_data (G_OBJECT (out), "data");
+  tcaps = gst_pad_get_negotiated_caps (out);
+  if (!gst_caps_is_equal (tcaps, to)) {
+    gchar *s1 = gst_caps_to_string (tcaps), *s2 = gst_caps_to_string (to);
+    g_warning ("Out caps (%s) is not what we requested (%s)", s1, s2);
+    g_free (s1);
+    g_free (s1);
+    gst_buffer_unref (ret);
+    return NULL;
+  }
+  gst_caps_unref (tcaps);
+
+  /* unref */
+  gst_object_unref (GST_OBJECT (pipe));
+
+  return ret;
+}
+
+#else /* HAVE_GSTREAMER_09 */
+
 #define BVW_TYPE_FRAME_CONV \
   (bvw_frame_conv_get_type ())
 #define BVW_FRAME_CONV(obj) \
@@ -168,3 +262,5 @@ bvw_frame_conv_convert (GstBuffer * buf,
 
   return ret;
 }
+
+#endif /* HAVE_GSTREAMER_09 */
