2006-06-12 Matthew Allum <mallum@openedhand.com>
authorMatthew Allum <mallum@openedhand.com>
Mon, 12 Jun 2006 20:38:57 +0000 (20:38 +0000)
committerMatthew Allum <mallum@openedhand.com>
Mon, 12 Jun 2006 20:38:57 +0000 (20:38 +0000)
        * clutter/Makefile.am:
        * clutter/clutter-media.c:
        * clutter/clutter-media.h:
        * clutter/clutter-video-texture.c:
        * clutter/clutter-video-texture.h:
        * clutter/clutter.h:
        * examples/test-video.c: (main):
        * examples/video-cube.c: (main):
        Add new 'media' interface.
        Drop Totem based video playback code replace with newly
        rewritten supper Jorn based code. Clutter is now fully LGPL.

        * clutter/clutter-texture.c: (tile_dimension):
        Remove uneeded overlap code.

ChangeLog
clutter/Makefile.am
clutter/clutter-label.c
clutter/clutter-media.c [new file with mode: 0644]
clutter/clutter-media.h [new file with mode: 0644]
clutter/clutter-texture.c
clutter/clutter-video-texture.c
clutter/clutter-video-texture.h
clutter/clutter.h
examples/test-video.c
examples/video-cube.c

index 408de32..c28d370 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2006-06-12  Matthew Allum  <mallum@openedhand.com>
+
+       * clutter/Makefile.am:
+       * clutter/clutter-media.c:
+       * clutter/clutter-media.h:
+       * clutter/clutter-video-texture.c:
+       * clutter/clutter-video-texture.h:
+       * clutter/clutter.h:
+       * examples/test-video.c: (main):
+       * examples/video-cube.c: (main):
+       Add new 'media' interface.
+       Drop Totem based video playback code replace with newly
+       rewritten supper Jorn based code. Clutter is now fully LGPL.  
+
+       * clutter/clutter-texture.c: (tile_dimension): 
+       Remove uneeded overlap code.
+
 2006-06-08  Iain Holmes  <iain@openedhand.com>
 
        * clutter/clutter-texture.c:
index b1caab1..00dcf8f 100644 (file)
@@ -7,6 +7,7 @@ BUILT_SOURCES = $(MARSHALFILES) $(ENUMFILES)
 
 source_h = clutter-keysyms.h       \
           clutter-util.h          \
+          clutter-media.h         \
            clutter-event.h         \
           clutter-color.h         \
           clutter-timeline.h      \
@@ -65,6 +66,7 @@ CLEANFILES = $(BUILT_SOURCES) stamp-clutter-enum-types.h
 
 source_c = clutter-main.c          \
           clutter-util.c          \
+          clutter-media.c         \
            clutter-event.c         \
           clutter-color.c         \
           clutter-timeline.c      \
index 4467cab..83b406c 100644 (file)
@@ -144,6 +144,16 @@ clutter_label_make_pixbuf (ClutterLabel *label)
 }
 
 static void
+clutter_label_allocate_coords (ClutterElement        *element,
+                              ClutterElementBox     *box)
+{
+  
+
+
+}
+
+
+static void
 clutter_label_set_property (GObject      *object, 
                            guint         prop_id,
                            const GValue *value, 
diff --git a/clutter/clutter-media.c b/clutter/clutter-media.c
new file mode 100644 (file)
index 0000000..3885cbb
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Authored By Matthew Allum  <mallum@openedhand.com>
+ *
+ * Copyright (C) 2006 OpenedHand
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "clutter-media.h"
+#include "clutter-main.h"
+#include "clutter-enum-types.h"
+#include "clutter-private.h"   /* for DBG */
+
+static void clutter_media_base_init (gpointer g_class);
+
+GType
+clutter_media_get_type (void)
+{
+  static GType media_type = 0;
+
+  if (!media_type)
+    {
+      static const GTypeInfo media_info =
+      {
+       sizeof (ClutterMediaInterface),
+       clutter_media_base_init,
+       NULL,                   
+      };
+
+      media_type = g_type_register_static (G_TYPE_INTERFACE, "ClutterMedia",
+                                          &media_info, 0);
+    }
+
+  return media_type;
+}
+
+static void
+clutter_media_base_init (gpointer g_iface)
+{
+  static gboolean initialized = FALSE;
+
+  if (!initialized)
+    {
+      initialized = TRUE;
+
+      /* props */
+
+      g_object_interface_install_property 
+       (g_iface,
+        g_param_spec_string 
+        ("uri",
+         "URI",
+         "The loaded URI.",
+         NULL,
+         G_PARAM_READWRITE |
+         G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
+         G_PARAM_STATIC_BLURB));
+
+      g_object_interface_install_property 
+       (g_iface,
+        g_param_spec_boolean
+        ("playing",
+         "Playing",
+         "TRUE if playing.",
+         FALSE,
+         G_PARAM_READWRITE |
+         G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
+         G_PARAM_STATIC_BLURB));
+
+      g_object_interface_install_property 
+       (g_iface,
+        g_param_spec_int
+        ("position",
+         "Position",
+         "The position in the current stream in seconds.",
+         0, G_MAXINT, 0,
+         G_PARAM_READWRITE |
+         G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
+         G_PARAM_STATIC_BLURB));
+
+      g_object_interface_install_property 
+       (g_iface,
+        g_param_spec_double
+        ("volume",
+         "Volume",
+         "The audio volume.",
+         0, 100, 50,
+         G_PARAM_READWRITE |
+         G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
+         G_PARAM_STATIC_BLURB));
+
+      g_object_interface_install_property 
+       (g_iface,
+        g_param_spec_boolean
+        ("can-seek",
+         "Can seek",
+         "TRUE if the current stream is seekable.",
+         FALSE,
+         G_PARAM_READABLE |
+         G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
+         G_PARAM_STATIC_BLURB));
+        
+      g_object_interface_install_property 
+       (g_iface,
+        g_param_spec_int
+        ("buffer-percent",
+         "Buffer percent",
+         "The percentage the current stream buffer is filled.",
+         0, 100, 0,
+         G_PARAM_READABLE |
+         G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
+         G_PARAM_STATIC_BLURB));
+        
+      g_object_interface_install_property 
+       (g_iface,
+        g_param_spec_int
+        ("duration",
+         "Duration",
+         "The duration of the current stream in seconds.",
+         0, G_MAXINT, 0,
+         G_PARAM_READABLE |
+         G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
+         G_PARAM_STATIC_BLURB));
+
+      /* signals */
+
+      g_signal_new ("metadata-available",
+                   CLUTTER_TYPE_MEDIA,
+                   G_SIGNAL_RUN_LAST,
+                   G_STRUCT_OFFSET (ClutterMediaInterface,
+                                    metadata_available),
+                   NULL, NULL,
+                   g_cclosure_marshal_VOID__POINTER,
+                   G_TYPE_NONE, 1, G_TYPE_POINTER);
+      
+      g_signal_new ("eos",
+                   CLUTTER_TYPE_MEDIA,
+                   G_SIGNAL_RUN_LAST,
+                   G_STRUCT_OFFSET (ClutterMediaInterface,
+                                    eos),
+                   NULL, NULL,
+                   g_cclosure_marshal_VOID__VOID,
+                   G_TYPE_NONE, 0);
+      
+      g_signal_new ("error",
+                   CLUTTER_TYPE_MEDIA,
+                   G_SIGNAL_RUN_LAST,
+                   G_STRUCT_OFFSET (ClutterMediaInterface,
+                                    error),
+                   NULL, NULL,
+                   g_cclosure_marshal_VOID__POINTER,
+                   G_TYPE_NONE, 1, G_TYPE_POINTER);
+    }
+}
+
+void
+clutter_media_set_uri (ClutterMedia *media,
+                      const char   *uri)
+{
+  g_return_if_fail (CLUTTER_IS_MEDIA(media));
+
+  CLUTTER_MEDIA_GET_INTERFACE (media)->set_uri (media, uri);
+}
+
+const char*
+clutter_media_get_uri (ClutterMedia *media)
+{
+  g_return_val_if_fail (CLUTTER_IS_MEDIA(media), NULL);
+
+  return CLUTTER_MEDIA_GET_INTERFACE (media)->get_uri (media);
+}
+
+void
+clutter_media_set_playing (ClutterMedia *media,
+                          gboolean      playing)
+{
+  g_return_if_fail (CLUTTER_IS_MEDIA(media));
+
+  CLUTTER_MEDIA_GET_INTERFACE (media)->set_playing (media, playing);
+}
+
+gboolean
+clutter_media_get_playing (ClutterMedia *media)
+{
+  g_return_val_if_fail (CLUTTER_IS_MEDIA(media), FALSE);
+
+  return CLUTTER_MEDIA_GET_INTERFACE (media)->get_playing (media);
+}
+
+void
+clutter_media_set_position (ClutterMedia *media,
+                           int           position)
+{
+  g_return_if_fail (CLUTTER_IS_MEDIA(media));
+
+  CLUTTER_MEDIA_GET_INTERFACE (media)->set_position (media, position);
+}
+
+int
+clutter_media_get_position (ClutterMedia *media)
+{
+  g_return_val_if_fail (CLUTTER_IS_MEDIA(media), 0);
+
+  return CLUTTER_MEDIA_GET_INTERFACE (media)->get_position (media);
+}
+
+void
+clutter_media_set_volume (ClutterMedia *media,
+                         double        volume)
+{
+  g_return_if_fail (CLUTTER_IS_MEDIA(media));
+
+  CLUTTER_MEDIA_GET_INTERFACE (media)->set_position (media, volume);
+}
+
+double
+clutter_media_get_volume (ClutterMedia *media)
+{
+  g_return_val_if_fail (CLUTTER_IS_MEDIA(media), 0.0);
+
+  return CLUTTER_MEDIA_GET_INTERFACE (media)->get_volume (media);
+}
+
+gboolean
+clutter_media_get_can_seek (ClutterMedia *media)
+{
+  g_return_val_if_fail (CLUTTER_IS_MEDIA(media), FALSE);
+
+  return CLUTTER_MEDIA_GET_INTERFACE (media)->can_seek (media);
+}
+
+int
+clutter_media_get_buffer_percent (ClutterMedia *media)
+{
+  g_return_val_if_fail (CLUTTER_IS_MEDIA(media), 0);
+
+  return CLUTTER_MEDIA_GET_INTERFACE (media)->get_buffer_percent (media);
+}
+
+int
+clutter_media_get_duration (ClutterMedia *media)
+{
+  g_return_val_if_fail (CLUTTER_IS_MEDIA(media), 0);
+
+  return CLUTTER_MEDIA_GET_INTERFACE (media)->get_duration (media);
+}
+
+/* helper funcs */
+
+void
+clutter_media_set_filename (ClutterMedia *media, const gchar *filename)
+{
+  gchar *uri;
+
+  if (filename[0] != '/')
+    uri = g_strdup_printf ("file://%s/%s", g_get_current_dir (), filename);
+  else 
+    uri = g_strdup_printf ("file://%s", filename);
+
+  clutter_media_set_uri (media, uri);
+
+  g_free(uri);
+}
diff --git a/clutter/clutter-media.h b/clutter/clutter-media.h
new file mode 100644 (file)
index 0000000..293030b
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Authored By Matthew Allum  <mallum@openedhand.com>
+ *
+ * Copyright (C) 2006 OpenedHand
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _HAVE_CLUTTER_MEDIA_H
+#define _HAVE_CLUTTER_MEDIA_H
+
+#include <glib-object.h>
+#include <gst/gsttaglist.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_MEDIA clutter_media_get_type()
+
+#define CLUTTER_MEDIA(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  CLUTTER_TYPE_MEDIA, ClutterMedia))
+
+#define CLUTTER_IS_MEDIA(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  CLUTTER_TYPE_MEDIA))
+
+#define CLUTTER_MEDIA_GET_INTERFACE(obj) \
+  (G_TYPE_INSTANCE_GET_INTERFACE ((obj), \
+  CLUTTER_TYPE_MEDIA, ClutterMediaInterface))
+
+typedef struct _ClutterMedia           ClutterMedia;      
+typedef struct _ClutterMediaInterface  ClutterMediaInterface;
+
+struct _ClutterMediaInterface
+{
+  GTypeInterface           base_iface;
+  void (*set_uri)           (ClutterMedia *media,
+                            const char   *uri);
+  const char *(*get_uri)    (ClutterMedia *media);
+  void (*set_playing)       (ClutterMedia *media,
+                            gboolean      playing);
+  gboolean (*get_playing)   (ClutterMedia *media);
+  void (*set_position)      (ClutterMedia *media,
+                            int           position);
+  int (*get_position)       (ClutterMedia *media);
+  void (*set_volume)        (ClutterMedia *media,
+                            double        volume);
+  double (*get_volume)      (ClutterMedia *media);
+  gboolean (*can_seek)      (ClutterMedia *media);
+  int (*get_buffer_percent) (ClutterMedia *media);
+  int (*get_duration)       (ClutterMedia *media);
+
+  /* signals */
+
+  void (* metadata_available) (ClutterMedia *media,
+                              GstTagList   *tag_list);
+  void (* eos)                (ClutterMedia *media);
+  void (* error)              (ClutterMedia *media,
+                              GError       *error);
+};
+
+
+GType clutter_media_get_type     (void);
+
+void
+clutter_media_set_uri            (ClutterMedia *media,
+                                 const char   *uri);
+const char *
+clutter_media_get_uri            (ClutterMedia *media);
+
+void
+clutter_media_set_playing        (ClutterMedia *media,
+                                 gboolean      playing);
+
+gboolean
+clutter_media_get_playing        (ClutterMedia *media);
+
+void
+clutter_media_set_position       (ClutterMedia *media,
+                                 int           position);
+
+int
+clutter_media_get_position       (ClutterMedia *media);
+
+void
+clutter_media_set_volume         (ClutterMedia *media,
+                                 double        volume);
+
+double
+clutter_media_get_volume         (ClutterMedia *media);
+
+gboolean
+clutter_media_get_can_seek       (ClutterMedia *media);
+
+int
+clutter_media_get_buffer_percent (ClutterMedia *media);
+
+int
+clutter_media_get_duration       (ClutterMedia *media);
+
+void
+clutter_media_set_filename       (ClutterMedia *media, 
+                                 const gchar  *filename);
+
+G_END_DECLS
+
+#endif
index 0c755e6..bb09505 100644 (file)
@@ -40,9 +40,6 @@ G_DEFINE_TYPE (ClutterTexture, clutter_texture, CLUTTER_TYPE_ELEMENT);
 #define PIXEL_TYPE GL_UNSIGNED_INT_8_8_8_8_REV
 #endif
 
-#define OVERLAP 0  /* Dont need as CLAMP_TO_EDGE */
-
-/* FIXME: actually use */
 typedef struct ClutterTextureTileDimention
 {
   gint pos, size, waste;
@@ -144,8 +141,7 @@ tile_dimension (int                          to_fill,
        }
       else
        {
-         to_fill -= (size - OVERLAP);
-         pos += size - OVERLAP;
+         to_fill -= size; pos += size;
          while (size >= 2 * to_fill || size - to_fill > waste)
            size /= 2;
        }
index a2fa630..f6575eb 100644 (file)
@@ -1,4 +1,4 @@
-/* Heavily based on totems bacon-video-widget .. */
+
 
 #include "clutter-video-texture.h"
 #include "clutter-main.h"
 
 #include <glib.h>
 
-static void
-got_time_tick (GstElement          *play, 
-              gint64               time_nanos, 
-              ClutterVideoTexture *video_texture);
-static void
-stop_play_pipeline (ClutterVideoTexture *video_texture);
-
-G_DEFINE_TYPE (ClutterVideoTexture,   \
-               clutter_video_texture, \
-               CLUTTER_TYPE_TEXTURE);
-
-enum
+struct ClutterVideoTexturePrivate
 {
-  SIGNAL_ERROR,
-  SIGNAL_EOS,
-  SIGNAL_REDIRECT,
-  SIGNAL_TITLE_CHANGE,
-  SIGNAL_CHANNELS_CHANGE,
-  SIGNAL_TICK,
-  SIGNAL_GOT_METADATA,
-  SIGNAL_BUFFERING,
-  SIGNAL_SPEED_WARNING,
-  LAST_SIGNAL
+  GstElement *playbin;
+  char       *uri;
+  gboolean    can_seek;
+  int         buffer_percent;
+  int         duration;
+  gboolean    force_aspect_ratio;
+  guint       tick_timeout_id;
 };
 
-/* Properties */
-enum
-{
+enum {
   PROP_0,
-  PROP_POSITION,
-  PROP_CURRENT_TIME,
-  PROP_STREAM_LENGTH,
+  /* ClutterMedia proprs */
+  PROP_URI,
   PROP_PLAYING,
-  PROP_SEEKABLE,
-};
+  PROP_POSITION,
+  PROP_VOLUME,
+  PROP_CAN_SEEK,
+  PROP_BUFFER_PERCENT,
+  PROP_DURATION,
 
-struct ClutterVideoTexturePrivate
-{
-  GstElement                     *play, *video_sink, *audio_sink;
-  gboolean                        has_video, has_audio;
-  gint64                          stream_length;
-  gint64                          current_time_nanos;
-  gint64                          current_time;
-  float                           current_position;
-  gchar                          *mrl;
-
-  gboolean                        got_redirect;
-  gint                            eos_id;
-  guint                           update_id;
-
-  GstTagList                     *tagcache, *audiotags, *videotags;
-
-  const GValue                   *movie_par; /* Movie pixel aspect ratio */
-  gint                            video_fps_d, video_fps_n;
-  gint                            video_width, video_height;
-  ClutterVideoTextureAspectRatio  ratio_type;
-
-  GstMessageType                  ignore_messages_mask;
-  GstBus                         *bus;
-  gulong                          sig_bus_async;
+  /* Extra texture props */
+  PROP_FORCE_ASPECT_RATIO
 };
 
-static int cvt_signals[LAST_SIGNAL] = { 0 };
 
-GQuark
-clutter_video_texture_error_quark (void)
-{
-  return g_quark_from_static_string ("clutter-video-texture-error-quark");
-}
+#define TICK_TIMEOUT 0.5
 
-/* This is a hack to avoid doing poll_for_state_change() indirectly
- * from the bus message callback (via EOS => totem => close => wait for READY)
- * and deadlocking there. We need something like a
- * gst_bus_set_auto_flushing(bus, FALSE) ... */
-static gboolean
-signal_eos_delayed (gpointer user_data)
-{
-  ClutterVideoTexture *video_texture = (ClutterVideoTexture*)user_data;
+static void clutter_media_init (ClutterMediaInterface *iface);
 
-  g_signal_emit (video_texture, cvt_signals[SIGNAL_EOS], 0, NULL);
+static gboolean tick_timeout (ClutterVideoTexture *video_texture);
 
-  video_texture->priv->eos_id = 0;
+G_DEFINE_TYPE_EXTENDED (ClutterVideoTexture,                          \
+                       clutter_video_texture,                        \
+                       CLUTTER_TYPE_TEXTURE,                         \
+                       0,                                            \
+                       G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_MEDIA,    \
+                                              clutter_media_init));
 
-  return FALSE;
-}
+/* Interface implementation */
 
-static gboolean
-query_timeout (ClutterVideoTexture *video_texture)
+static void
+set_uri (ClutterMedia *media,
+        const char   *uri)
 {
-  ClutterVideoTexturePrivate *priv;
-  GstFormat                   fmt = GST_FORMAT_TIME;
-  gint64                      prev_len = -1, pos = -1, len = -1;
+  ClutterVideoTexture        *video_texture = CLUTTER_VIDEO_TEXTURE(media);
+  ClutterVideoTexturePrivate *priv; 
+  GstState                    state, pending;
+
+  g_return_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture));
 
   priv = video_texture->priv;
-  
-  /* check length/pos of stream */
-  prev_len = priv->stream_length;
 
-  if (gst_element_query_duration (priv->play, &fmt, &len)) 
+  if (!priv->playbin)
+    return;
+
+  if (priv->uri)
+    g_free (priv->uri);
+
+  if (uri) 
     {
-      if (len != -1 && fmt == GST_FORMAT_TIME) 
-       {
-         priv->stream_length = len / GST_MSECOND;
-         if (priv->stream_length != prev_len) 
-           {
-             g_signal_emit (video_texture, 
-                            cvt_signals[SIGNAL_GOT_METADATA], 0, NULL);
-           }
-       }
+      priv->uri = g_strdup (uri);
+    
+      /**
+       * Ensure the tick timeout is installed.
+       * 
+       * We also have it installed in PAUSED state, because
+       * seeks etc may have a delayed effect on the position.
+       **/
+    if (priv->tick_timeout_id == 0) 
+      {
+       priv->tick_timeout_id = g_timeout_add (TICK_TIMEOUT * 1000,
+                                              (GSourceFunc) tick_timeout,
+                                              video_texture);
+      }
     } 
   else 
     {
-      CLUTTER_DBG ("could not get duration");
-    }
-
-  if (gst_element_query_position (priv->play, &fmt, &pos)) 
-    {
-      if (pos != -1 && fmt == GST_FORMAT_TIME) 
+      priv->uri = NULL;
+    
+      if (priv->tick_timeout_id > 0) 
        {
-         got_time_tick (GST_ELEMENT (priv->play), pos, video_texture);
+         g_source_remove (priv->tick_timeout_id);
+         priv->tick_timeout_id = 0;
        }
-    } 
-  else 
-    CLUTTER_DBG ("could not get position");
+    }
+  
+  priv->can_seek = FALSE;
+  priv->duration = 0;
 
-  return TRUE;
+  gst_element_get_state (priv->playbin, &state, &pending, 0);
+
+  if (pending)
+    state = pending;
+  
+  gst_element_set_state (priv->playbin, GST_STATE_NULL);
+  
+  g_object_set (priv->playbin,
+               "uri", uri,
+               NULL);
+  
+  /**
+   * Restore state.
+   **/
+  if (uri) 
+    gst_element_set_state (priv->playbin, state);
+  
+  /**
+   * Emit notififications for all these to make sure UI is not showing
+   * any properties of the old URI.
+   **/
+  g_object_notify (G_OBJECT (video_texture), "uri");
+  g_object_notify (G_OBJECT (video_texture), "can-seek");
+  g_object_notify (G_OBJECT (video_texture), "duration");
+  g_object_notify (G_OBJECT (video_texture), "position");
+  
 }
 
-static void
-got_video_size (ClutterVideoTexture *video_texture)
+static const char *
+get_uri (ClutterMedia *media)
 {
-  GstMessage *msg;
-
-  g_return_if_fail (video_texture != NULL);
+  ClutterVideoTexture        *video_texture = CLUTTER_VIDEO_TEXTURE(media);
+  ClutterVideoTexturePrivate *priv; 
 
-  /* Do we even care about this info as comes from texture sizing ? */
-  CLUTTER_DBG("%ix%i", 
-             video_texture->priv->video_width,
-             video_texture->priv->video_height);
+  g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), NULL);
 
-  msg = gst_message_new_application 
-    (GST_OBJECT (video_texture->priv->play),
-        gst_structure_new ("video-size", 
-                          "width", G_TYPE_INT,
-                          video_texture->priv->video_width, 
-                          "height", G_TYPE_INT,
-                          video_texture->priv->video_height, NULL));
+  priv = video_texture->priv;
 
-  gst_element_post_message (video_texture->priv->play, msg);
+  return priv->uri;
 }
 
-
 static void
-caps_set (GObject             *obj,
-         GParamSpec          *pspec, 
-         ClutterVideoTexture *video_texture)
+set_playing (ClutterMedia *media,
+            gboolean      playing)
 {
-  ClutterVideoTexturePrivate *priv;
-  GstPad                     *pad = GST_PAD (obj);
-  GstStructure               *s;
-  GstCaps                    *caps;
+  ClutterVideoTexture         *video_texture = CLUTTER_VIDEO_TEXTURE(media);
+  ClutterVideoTexturePrivate *priv; 
+
+  g_return_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture));
 
   priv = video_texture->priv;
 
-  if (!(caps = gst_pad_get_negotiated_caps (pad)))
+  if (!priv->playbin)
     return;
-
-  /* Get video decoder caps */
-  s = gst_caps_get_structure (caps, 0);
-
-  /* Again do we even need this - sizing info from texture signal.. */
-
-  if (s) 
+        
+  if (priv->uri) 
     {
-      /* We need at least width/height and framerate */
-      if (!(gst_structure_get_fraction (s, "framerate", 
-                                       &priv->video_fps_n, 
-                                       &priv->video_fps_d) 
-           &&
-           gst_structure_get_int (s, "width", &priv->video_width) &&
-           gst_structure_get_int (s, "height", &priv->video_height)))
-       return;
-
-    /* Get the movie PAR if available */
-    priv->movie_par = gst_structure_get_value (s, "pixel-aspect-ratio");
+      GstState state;
     
-    /* Now set for real */
-    clutter_video_texture_set_aspect_ratio (video_texture, priv->ratio_type);
-  }
-
-  gst_caps_unref (caps);
+      if (playing)
+       state = GST_STATE_PLAYING;
+      else
+       state = GST_STATE_PAUSED;
+    
+      gst_element_set_state (video_texture->priv->playbin, state);
+    } 
+  else 
+    {
+      if (playing)
+       g_warning ("Tried to play, but no URI is loaded.");
+    }
+  
+  g_object_notify (G_OBJECT (video_texture), "playing");
+  g_object_notify (G_OBJECT (video_texture), "position");
 }
 
-static void
-parse_stream_info (ClutterVideoTexture *video_texture)
+static gboolean
+get_playing (ClutterMedia *media)
 {
-  ClutterVideoTexturePrivate *priv;
-  GList                      *streaminfo = NULL;
-  GstPad                     *videopad = NULL;
+  ClutterVideoTexture        *video_texture = CLUTTER_VIDEO_TEXTURE(media);
+  ClutterVideoTexturePrivate *priv; 
+  GstState                    state, pending;
 
+  g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), FALSE);
+       
   priv = video_texture->priv;
 
-  g_object_get (priv->play, "stream-info", &streaminfo, NULL);
+  if (!priv->playbin)
+    return FALSE;
+  
+  gst_element_get_state (priv->playbin, &state, &pending, 0);
+  
+  if (pending)
+    return (pending == GST_STATE_PLAYING);
+  else
+    return (state == GST_STATE_PLAYING);
+}
 
-  streaminfo = g_list_copy (streaminfo);
+static void
+set_position (ClutterMedia *media,
+             int           position) /* seconds */
+{
+  ClutterVideoTexture        *video_texture = CLUTTER_VIDEO_TEXTURE(media);
+  ClutterVideoTexturePrivate *priv; 
 
-  g_list_foreach (streaminfo, (GFunc) g_object_ref, NULL);
+  g_return_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture));
 
-  for ( ; streaminfo != NULL; streaminfo = streaminfo->next) 
-    {
-      GObject    *info = streaminfo->data;
-      gint        type;
-      GParamSpec *pspec;
-      GEnumValue *val;
+  priv = video_texture->priv;
 
-      if (!info)
-       continue;
+  if (!priv->playbin)
+    return;
 
-      g_object_get (info, "type", &type, NULL);
+  gst_element_seek (priv->playbin,
+                   1.0,
+                   GST_FORMAT_TIME,
+                   GST_SEEK_FLAG_FLUSH,
+                   GST_SEEK_TYPE_SET,
+                   position * GST_SECOND,
+                   0, 0);
+}
 
-      pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (info), "type");
-      val = g_enum_get_value (G_PARAM_SPEC_ENUM (pspec)->enum_class, type);
+static int
+get_position (ClutterMedia *media)
+{
+  ClutterVideoTexture        *video_texture = CLUTTER_VIDEO_TEXTURE(media);
+  ClutterVideoTexturePrivate *priv; 
+  GstQuery                   *query;
+  gint64                      position;
 
-      if (!g_strcasecmp (val->value_nick, "audio")) 
-       {
-         priv->has_audio = TRUE;
-       } 
-      else if (!g_strcasecmp (val->value_nick, "video")) 
-       {
-         priv->has_video = TRUE;
+  g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), -1);
 
-         if (!videopad) 
-           g_object_get (info, "object", &videopad, NULL);
-       }
-    }
+  priv = video_texture->priv;
 
-  if (videopad) 
-    {
-      GstCaps *caps;
+  if (!priv->playbin)
+    return -1;
+  
+  query = gst_query_new_position (GST_FORMAT_TIME);
+  
+  if (gst_element_query (priv->playbin, query)) 
+    gst_query_parse_position (query, NULL, &position);
+  else
+    position = 0;
+  
+  gst_query_unref (query);
+  
+  return (position / GST_SECOND);
+}
 
-      if ((caps = gst_pad_get_negotiated_caps (videopad))) 
-       {
-         caps_set (G_OBJECT (videopad), NULL, video_texture);
-         gst_caps_unref (caps);
-       }
+static void
+set_volume (ClutterMedia *media,
+           double        volume)
+{
+  ClutterVideoTexture        *video_texture = CLUTTER_VIDEO_TEXTURE(media);
+  ClutterVideoTexturePrivate *priv; 
 
-      g_signal_connect (videopad, "notify::caps",
-                       G_CALLBACK (caps_set), video_texture);
-    } 
+  g_return_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture));
+  // g_return_if_fail (volume >= 0.0 && volume <= GST_VOL_MAX);
 
-  g_list_foreach (streaminfo, (GFunc) g_object_unref, NULL);
-  g_list_free (streaminfo);
+  priv = video_texture->priv;
+  
+  if (!priv->playbin)
+    return;
+  
+  g_object_set (G_OBJECT (video_texture->priv->playbin),
+               "volume", volume,
+               NULL);
+  
+  g_object_notify (G_OBJECT (video_texture), "volume");
 }
 
-static void
-handle_element_message (ClutterVideoTexture *video_texture, GstMessage *msg)
+static double
+get_volume (ClutterMedia *media)
 {
-  const gchar *type_name = NULL;
-  gchar       *src_name;
+  ClutterVideoTexture        *video_texture = CLUTTER_VIDEO_TEXTURE(media);
+  ClutterVideoTexturePrivate *priv; 
+  double                      volume;
 
-  CLUTTER_MARK();
+  g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), 0.0);
 
-  src_name = gst_object_get_name (msg->src);
+  priv = video_texture->priv;
+  
+  if (!priv->playbin)
+    return 0.0;
 
-  if (msg->structure)
-    type_name = gst_structure_get_name (msg->structure);
+  g_object_get (priv->playbin,
+               "volume", &volume,
+               NULL);
+  
+  return volume;
+}
 
-  if (type_name == NULL)
-    goto unhandled;
+static gboolean
+can_seek (ClutterMedia *media)
+{
+  ClutterVideoTexture        *video_texture = CLUTTER_VIDEO_TEXTURE(media);
 
-  if (strcmp (type_name, "redirect") == 0) 
-    {
-      const gchar *new_location;
+  g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), FALSE);
+  
+  return video_texture->priv->can_seek;
+}
 
-      new_location = gst_structure_get_string (msg->structure, "new-location");
+static int
+get_buffer_percent (ClutterMedia *media)
+{
+  ClutterVideoTexture         *video_texture = CLUTTER_VIDEO_TEXTURE(media);
 
-      CLUTTER_DBG ("Got redirect to '%s'", GST_STR_NULL (new_location));
+  g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), -1);
+  
+  return video_texture->priv->buffer_percent;
+}
 
-      if (new_location && *new_location) 
-       {
-         g_signal_emit (video_texture, 
-                        cvt_signals[SIGNAL_REDIRECT], 
-                        0, 
-                        new_location);
-         goto done;
-       }
-    }
+static int
+get_duration (ClutterMedia *media)
+{
+  ClutterVideoTexture         *video_texture = CLUTTER_VIDEO_TEXTURE(media);
+
+  g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), -1);
 
- unhandled:
-  CLUTTER_DBG ("Unhandled element message '%s' from element '%s'",
-              GST_STR_NULL (type_name), src_name);
- done:
-  g_free (src_name);
+  return video_texture->priv->duration;
 }
 
 static void
-handle_application_message (ClutterVideoTexture *video_texture, 
-                           GstMessage          *msg)
+clutter_media_init (ClutterMediaInterface *iface)
 {
-  const gchar *msg_name;
+  iface->set_uri            = set_uri;
+  iface->get_uri            = get_uri;
+  iface->set_playing        = set_playing;
+  iface->get_playing        = get_playing;
+  iface->set_position       = set_position;
+  iface->get_position       = get_position;
+  iface->set_volume         = set_volume;
+  iface->get_volume         = get_volume;
+  iface->can_seek           = can_seek;
+  iface->get_buffer_percent = get_buffer_percent;
+  iface->get_duration       = get_duration;
+}
 
-  msg_name = gst_structure_get_name (msg->structure);
+static void
+clutter_video_texture_dispose (GObject *object)
+{
+  ClutterVideoTexture        *self;
+  ClutterVideoTexturePrivate *priv; 
 
-  g_return_if_fail (msg_name != NULL);
+  self = CLUTTER_VIDEO_TEXTURE(object); 
+  priv = self->priv;
 
-  CLUTTER_DBG ("Handling application message");
+  /* FIXME: flush an errors off bus ? */
+  /* gst_bus_set_flushing (priv->bus, TRUE); */
 
-  if (strcmp (msg_name, "notify-streaminfo") == 0
+  if (priv->playbin
     {
-      g_signal_emit (video_texture, cvt_signals[SIGNAL_GOT_METADATA], 0, NULL);
-      g_signal_emit (video_texture, cvt_signals[SIGNAL_CHANNELS_CHANGE], 0);
+      gst_element_set_state (priv->playbin, GST_STATE_NULL);
+      gst_object_unref (GST_OBJECT (priv->playbin));
+      priv->playbin = NULL;
     }
-  else if (strcmp (msg_name, "video-size") == 0)
-    {
-      g_signal_emit (video_texture, cvt_signals[SIGNAL_GOT_METADATA], 0, NULL);
 
-      CLUTTER_DBG("Got video size");
+  if (priv->tick_timeout_id > 0) 
+    {
+      g_source_remove (priv->tick_timeout_id);
+      priv->tick_timeout_id = 0;
     }
-  else
-    CLUTTER_DBG ("Unhandled application message %s", msg_name);
+
+  G_OBJECT_CLASS (clutter_video_texture_parent_class)->dispose (object);
 }
 
 static void
-bus_message_cb (GstBus *bus, GstMessage *message, gpointer data)
+clutter_video_texture_finalize (GObject *object)
 {
-  ClutterVideoTexturePrivate *priv;
-  ClutterVideoTexture        *video_texture = (ClutterVideoTexture*)data;
-  GstMessageType              msg_type;
+  ClutterVideoTexture        *self;
+  ClutterVideoTexturePrivate *priv; 
+
+  self = CLUTTER_VIDEO_TEXTURE(object); 
+  priv = self->priv;
 
-  g_return_if_fail (video_texture != NULL);
-  g_return_if_fail (CLUTTER_IS_VIDEO_TEXTURE(video_texture));
+  if (priv->uri)
+    g_free(priv->uri);
 
-  priv = video_texture->priv;
+  G_OBJECT_CLASS (clutter_video_texture_parent_class)->finalize (object);
+}
 
-  msg_type = GST_MESSAGE_TYPE (message);
+static void
+clutter_video_texture_set_property (GObject      *object, 
+                                   guint         property_id,
+                                   const GValue *value, 
+                                   GParamSpec   *pspec)
+{
+  ClutterVideoTexture *video_texture;
 
-  /* somebody else is handling the message, 
-     probably in poll_for_state_change */
-  if (priv->ignore_messages_mask & msg_type) 
-    {
-      gchar *src_name = gst_object_get_name (message->src);
-      CLUTTER_DBG ("Ignoring %s message from element %s as requested",
-                  gst_message_type_get_name (msg_type), src_name);
-      g_free (src_name);
-      return;
-    }
+  video_texture = CLUTTER_VIDEO_TEXTURE(object);
 
-  if (msg_type != GST_MESSAGE_STATE_CHANGED && clutter_want_debug()) 
+  switch (property_id)
     {
-      gchar *src_name = gst_object_get_name (message->src);
-      CLUTTER_DBG ("Handling %s message from element %s",
-                  gst_message_type_get_name (msg_type), src_name);
-      g_free (src_name);
+    case PROP_URI:
+      clutter_media_set_uri (CLUTTER_MEDIA(video_texture), 
+                            g_value_get_string (value));
+      break;
+    case PROP_PLAYING:
+      clutter_media_set_playing (CLUTTER_MEDIA(video_texture),
+                                g_value_get_boolean (value));
+      break;
+    case PROP_POSITION:
+      clutter_media_set_position (CLUTTER_MEDIA(video_texture),
+                                 g_value_get_int (value));
+      break;
+    case PROP_VOLUME:
+      clutter_media_set_volume (CLUTTER_MEDIA(video_texture),
+                               g_value_get_double (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
     }
+}
 
-  switch (msg_type) 
-    {
-    case GST_MESSAGE_ERROR: 
-      {
-       GError *error = NULL;
-       gchar  *debug = NULL;
+static void
+clutter_video_texture_get_property (GObject    *object, 
+                                   guint       property_id,
+                                   GValue     *value, 
+                                   GParamSpec *pspec)
+{
+  ClutterVideoTexture *video_texture;
+  ClutterMedia        *media;
 
-       gst_message_parse_error (message, &error, &debug);
+  video_texture = CLUTTER_VIDEO_TEXTURE (object);
+  media         = CLUTTER_MEDIA (video_texture);
 
-       CLUTTER_DBG ("Error message: %s [%s]", 
-                    GST_STR_NULL (error->message),
-                    GST_STR_NULL (debug));
+  switch (property_id)
+    {
+    case PROP_URI:
+      g_value_set_string (value, clutter_media_get_uri (media));
+      break;
+    case PROP_PLAYING:
+      g_value_set_boolean (value, clutter_media_get_playing (media));
+      break;
+    case PROP_POSITION:
+      g_value_set_int (value, clutter_media_get_position (media));
+      break;
+    case PROP_VOLUME:
+      g_value_set_double (value, clutter_media_get_volume (media));
+      break;
+    case PROP_CAN_SEEK:
+      g_value_set_boolean (value, clutter_media_get_can_seek (media));
+      break;
+    case PROP_BUFFER_PERCENT:
+      g_value_set_int (value, clutter_media_get_buffer_percent (media));
+      break;
+    case PROP_DURATION:
+      g_value_set_int (value, clutter_media_get_duration (media));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
 
-       g_signal_emit (video_texture, 
-                      cvt_signals[SIGNAL_ERROR], 
-                      0,
-                      error->message, 
-                      TRUE, 
-                      FALSE);
+static void
+clutter_video_texture_class_init (ClutterVideoTextureClass *klass)
+{
+  GObjectClass        *object_class;
+  ClutterElementClass *element_class;
 
-       g_error_free (error);
+  object_class = (GObjectClass*)klass;
+  element_class = (ClutterElementClass*)klass;
 
-       if (priv->play)
-         gst_element_set_state (priv->play, GST_STATE_NULL);
+  object_class->dispose      = clutter_video_texture_dispose;
+  object_class->finalize     = clutter_video_texture_finalize;
+  object_class->set_property = clutter_video_texture_set_property;
+  object_class->get_property = clutter_video_texture_get_property;
 
-       g_free (debug);
-       break;
-      }
-    case GST_MESSAGE_WARNING: 
-      {
-       GError *error = NULL;
-       gchar  *debug = NULL;
+  /* Interface props */
 
-       gst_message_parse_warning (message, &error, &debug);
+  g_object_class_override_property (object_class, PROP_URI, "uri");
+  g_object_class_override_property (object_class, PROP_PLAYING, "playing");
+  g_object_class_override_property (object_class, PROP_POSITION, "position");
+  g_object_class_override_property (object_class, PROP_VOLUME, "volume");
+  g_object_class_override_property (object_class, PROP_CAN_SEEK, "can-seek");
+  g_object_class_override_property (object_class, PROP_DURATION, "duration");
+  g_object_class_override_property (object_class, PROP_BUFFER_PERCENT, 
+                                   "buffer-percent" );
+}
 
-       g_warning ("%s [%s]", 
-                  GST_STR_NULL (error->message), 
-                  GST_STR_NULL (debug));
+static void
+bus_message_error_cb (GstBus            *bus,
+                      GstMessage        *message,
+                      ClutterVideoTexture *video_texture)
+{
+  GError *error;
 
-       g_error_free (error);
-       g_free (debug);
-       break;
-      }
-    case GST_MESSAGE_TAG: 
-      {
-       GstTagList *tag_list, *result;
-       GstElementFactory *f;
+  error = NULL;
+  gst_message_parse_error (message, &error, NULL);
+        
+  g_signal_emit_by_name (CLUTTER_MEDIA(video_texture), "error", error);
 
-       gst_message_parse_tag (message, &tag_list);
+  g_error_free (error);
+}
 
-       CLUTTER_DBG ("Tags: %p", tag_list);
+static void
+bus_message_eos_cb (GstBus            *bus,
+                    GstMessage        *message,
+                    ClutterVideoTexture *video_texture)
+{
+  g_object_notify (G_OBJECT (video_texture), "position");
 
-       /* all tags */
-       result = gst_tag_list_merge (priv->tagcache, 
-                                    tag_list, 
-                                    GST_TAG_MERGE_KEEP);
+  g_signal_emit_by_name (CLUTTER_MEDIA(video_texture), "eos");
+}
 
-       if (priv->tagcache)
-         gst_tag_list_free (priv->tagcache);
-       priv->tagcache = result;
-       
-       /* media-type-specific tags */
-       if (GST_IS_ELEMENT (message->src) &&
-           (f = gst_element_get_factory (GST_ELEMENT (message->src)))) 
-         {
-           const gchar *klass = gst_element_factory_get_klass (f);
-           GstTagList **cache = NULL;
-         
-         if (g_strrstr (klass, "Video")) 
-           {
-             cache = &priv->videotags;
-           } 
-         else if (g_strrstr (klass, "Audio")) 
-           {
-             cache = &priv->audiotags;
-           }
-         
-         if (cache) 
-           {
-             result = gst_tag_list_merge (*cache, tag_list, 
-                                          GST_TAG_MERGE_KEEP);
-             if (*cache)
-               gst_tag_list_free (*cache);
-             *cache = result;
-           }
-         }
-
-       gst_tag_list_free (tag_list);
-       g_signal_emit (video_texture, cvt_signals[SIGNAL_GOT_METADATA], 0);
-       break;
-    }
-    case GST_MESSAGE_EOS:
-      CLUTTER_DBG ("GST_MESSAGE_EOS");
+static void
+bus_message_tag_cb (GstBus            *bus,
+                    GstMessage        *message,
+                    ClutterVideoTexture *video_texture)
+{
+  GstTagList *tag_list;
 
-      if (priv->eos_id == 0)
-        priv->eos_id = g_idle_add (signal_eos_delayed, video_texture);
-      break;
-    case GST_MESSAGE_BUFFERING: 
-      {
-       gint percent = 0;
-       gst_structure_get_int (message->structure, "buffer-percent", &percent);
+  gst_message_parse_tag (message, &tag_list);
 
-       CLUTTER_DBG ("Buffering message (%u%%)", percent);
+  g_signal_emit_by_name (CLUTTER_MEDIA(video_texture), 
+                        "metadata-available", 
+                        tag_list);
+  
+  gst_tag_list_free (tag_list);
+}
 
-       g_signal_emit (video_texture, 
-                      cvt_signals[SIGNAL_BUFFERING], 
-                      0, 
-                      percent);
-       break;
-      }
+static void
+bus_message_buffering_cb (GstBus            *bus,
+                          GstMessage        *message,
+                          ClutterVideoTexture *video_texture)
+{
+  const GstStructure *str;
+  
+  str = gst_message_get_structure (message);
+  if (!str)
+    return;
 
-    case GST_MESSAGE_APPLICATION: 
-      handle_application_message (video_texture, message);
-      break;
+  if (!gst_structure_get_int (str,
+                             "buffer-percent",
+                             &video_texture->priv->buffer_percent))
+    return;
+        
+  g_object_notify (G_OBJECT (video_texture), "buffer-percent");
+}
 
-    case GST_MESSAGE_STATE_CHANGED: 
-      {
-       GstState old_state, new_state;
-       gchar   *src_name;
+static void
+bus_message_duration_cb (GstBus            *bus,
+                         GstMessage        *message,
+                         ClutterVideoTexture *video_texture)
+{
+  GstFormat format;
+  gint64 duration;
 
-       CLUTTER_DBG ("GST_MESSAGE_STATE_CHANGED");
+  gst_message_parse_duration (message,
+                             &format,
+                             &duration);
 
-       gst_message_parse_state_changed (message, 
-                                        &old_state, &new_state, NULL);
+  if (format != GST_FORMAT_TIME)
+    return;
+  
+  video_texture->priv->duration = duration / GST_SECOND;
 
-       if (old_state == new_state)
-         break;
+  g_object_notify (G_OBJECT (video_texture), "duration");
+}
 
-       /* we only care about playbin (pipeline) state changes */
-       if (GST_MESSAGE_SRC (message) != GST_OBJECT (priv->play))
-         break;
+static void
+bus_message_element_cb (GstBus            *bus,
+                        GstMessage        *message,
+                        ClutterVideoTexture *video_texture)
+{
+  const GstStructure *str;
 
-       src_name = gst_object_get_name (message->src);
+  str = gst_message_get_structure (message);
+  if (!str)
+    return;
+}
 
-       CLUTTER_DBG ("%s changed state from %s to %s", src_name,
-                    gst_element_state_get_name (old_state),
-                    gst_element_state_get_name (new_state));
+static void
+bus_message_state_change_cb (GstBus            *bus,
+                             GstMessage        *message,
+                             ClutterVideoTexture *video_texture)
+{
+  gpointer src;
+  GstState old_state, new_state;
 
-       g_free (src_name);
+  src = GST_MESSAGE_SRC (message);
+        
+  if (src != video_texture->priv->playbin)
+    return;
 
-      if (new_state <= GST_STATE_PAUSED) 
-       {
-         if (priv->update_id != 0) 
-           {
-             CLUTTER_DBG ("removing tick timeout");
-             g_source_remove (priv->update_id);
-             priv->update_id = 0;
-           }
-       } 
-      else if (new_state > GST_STATE_PAUSED) 
-       {
-         if (priv->update_id == 0) 
-           {
-             CLUTTER_DBG ("starting tick timeout");
+  gst_message_parse_state_changed (message, &old_state, &new_state, NULL);
 
-             priv->update_id = g_timeout_add (200, 
-                                              (GSourceFunc) query_timeout, 
-                                              video_texture);
-           }
+  if (old_state == GST_STATE_READY && 
+      new_state == GST_STATE_PAUSED) 
+    {
+      GstQuery *query;
+      
+      /**
+       * Determine whether we can seek.
+       **/
+      query = gst_query_new_seeking (GST_FORMAT_TIME);
+      
+      if (gst_element_query (video_texture->priv->playbin, query)) {
+       gst_query_parse_seeking (query,
+                                NULL,
+                                &video_texture->priv->can_seek,
+                                NULL,
+                                NULL);
+      } else {
+       /**
+        * Could not query for ability to seek. Determine
+        * using URI.
+        **/
+       
+       if (g_str_has_prefix (video_texture->priv->uri,
+                             "http://")) {
+         video_texture->priv->can_seek = FALSE;
+       } else {
+         video_texture->priv->can_seek = TRUE;
        }
-
-      if (old_state == GST_STATE_READY && new_state == GST_STATE_PAUSED) 
-       {
-         parse_stream_info (video_texture);
-       } 
-      else if (old_state == GST_STATE_PAUSED && new_state == GST_STATE_READY) 
+      }
+      
+      gst_query_unref (query);
+      
+      g_object_notify (G_OBJECT (video_texture), "can-seek");
+      
+      /**
+       * Determine the duration.
+       **/
+      query = gst_query_new_duration (GST_FORMAT_TIME);
+      
+      if (gst_element_query (video_texture->priv->playbin, query)) 
        {
-         priv->has_video = FALSE;
-         priv->has_audio = FALSE;
-
-         /* clean metadata cache */
-         if (priv->tagcache) 
-           {
-             gst_tag_list_free (priv->tagcache);
-             priv->tagcache = NULL;
-           }
-
-         if (priv->audiotags) 
-           {
-             gst_tag_list_free (priv->audiotags);
-             priv->audiotags = NULL;
-           }
-
-         if (priv->videotags) 
-           {
-             gst_tag_list_free (priv->videotags);
-             priv->videotags = NULL;
-           }
+         gint64 duration;
          
-         priv->video_width = 0;
-         priv->video_height = 0;
-       }
-      break;
-    }
-
-    case GST_MESSAGE_ELEMENT:
-      handle_element_message (video_texture, message);
-      break;
-
-    case GST_MESSAGE_DURATION: 
-      {
-       CLUTTER_DBG ("GST_MESSAGE_DURATION");
-       /* force _get_stream_length() to do new duration query */
-       priv->stream_length = 0;
-       if (clutter_video_texture_get_stream_length (video_texture) == 0)
-         CLUTTER_DBG ("Failed to query duration after DURATION message?!");
-       break;
-      }
-
-    case GST_MESSAGE_CLOCK_PROVIDE:
-    case GST_MESSAGE_CLOCK_LOST:
-    case GST_MESSAGE_NEW_CLOCK:
-    case GST_MESSAGE_STATE_DIRTY:
-      break;
-    default:
-      CLUTTER_DBG ("Unhandled message of type '%s' (0x%x)", 
-                  gst_message_type_get_name (msg_type), msg_type);
-      break;
-    }
-}
-
-static void
-got_time_tick (GstElement          *play, 
-              gint64               time_nanos, 
-              ClutterVideoTexture *video_texture)
-{
-  gboolean                    seekable;
-  ClutterVideoTexturePrivate *priv;
+         gst_query_parse_duration (query, NULL, &duration);
 
-  g_return_if_fail (video_texture != NULL);
-  g_return_if_fail (CLUTTER_IS_VIDEO_TEXTURE(video_texture));
-
-  priv = video_texture->priv;
-
-  priv->current_time_nanos = time_nanos;
-  priv->current_time       = (gint64) time_nanos / GST_MSECOND;
+         video_texture->priv->duration = duration / GST_SECOND;
+                        
+         g_object_notify (G_OBJECT (video_texture), "duration");
+       }
 
-  if (priv->stream_length == 0) 
-    {
-      priv->current_position = 0;
-      seekable = clutter_video_texture_is_seekable (video_texture);
-    }
-  else
-    {
-      priv->current_position =
-       (gfloat) priv->current_time / priv->stream_length;
-      seekable = TRUE;
+      gst_query_unref (query);
     }
-
-  g_signal_emit (video_texture, 
-                cvt_signals[SIGNAL_TICK], 
-                0,
-                 priv->current_time, 
-                priv->stream_length,
-                 priv->current_position,
-                 seekable);
 }
 
-static void
-playbin_got_source (GObject             *play,
-                   GParamSpec          *pspec,
-                   ClutterVideoTexture *video_texture)
-{
-  /* Called via notify::source on playbin */
-
-  ClutterVideoTexturePrivate *priv;
-  GObject                    *source = NULL;
-
-  priv = video_texture->priv;
-
-  if (priv->tagcache) 
-    {
-      gst_tag_list_free (priv->tagcache);
-      priv->tagcache = NULL;
-    }
-
-  if (priv->audiotags) 
-    {
-      gst_tag_list_free (priv->audiotags);
-      priv->audiotags = NULL;
-    }
-
-  if (priv->videotags) 
-    {
-      gst_tag_list_free (priv->videotags);
-      priv->videotags = NULL;
-    }
-
-  g_object_get (play, "source", &source, NULL);
-
-  if (!source)
-    return;
-
-  g_object_unref (source);
-}
-
-static void
-playbin_stream_info_set (GObject             *obj, 
-                        GParamSpec          *pspec, 
-                        ClutterVideoTexture *video_texture)
-{
-  ClutterVideoTexturePrivate *priv;
-  GstMessage                 *msg;
-
-  priv = video_texture->priv;  
-
-  parse_stream_info (video_texture);
-
-  msg = gst_message_new_application (GST_OBJECT (priv->play),
-                                    gst_structure_new ("notify-streaminfo", 
-                                                       NULL));
-  gst_element_post_message (priv->play, msg);
-}
-
-
 static gboolean
-poll_for_state_change_full (ClutterVideoTexture *video_texture,
-                           GstElement          *element,
-                           GstState             state, 
-                           GError             **error, 
-                           gint64               timeout)
+tick_timeout (ClutterVideoTexture *video_texture)
 {
-  GstBus                     *bus;
-  GstMessageType              events, saved_events;
-  ClutterVideoTexturePrivate *priv;
-
-  priv         = video_texture->priv;
-  bus          = gst_element_get_bus (element);
-  saved_events = priv->ignore_messages_mask;
-
-  events  = GST_MESSAGE_STATE_CHANGED | GST_MESSAGE_ERROR | GST_MESSAGE_EOS;
-
-  if (element != NULL && element == priv->play) 
-    {
-      /* we do want the main handler to process state changed messages for
-       * playbin as well, otherwise it won't hook up the timeout etc. */
-      priv->ignore_messages_mask |= (events ^ GST_MESSAGE_STATE_CHANGED);
-    } 
-  else 
-    priv->ignore_messages_mask |= events;
-
-  while (TRUE) 
-    {
-      GstMessage *message;
-      GstElement *src;
-
-      message = gst_bus_poll (bus, events, timeout);
-    
-      if (!message)
-       goto timed_out;
-    
-      src = (GstElement*)GST_MESSAGE_SRC (message);
-
-      switch (GST_MESSAGE_TYPE (message)) 
-       {
-       case GST_MESSAGE_STATE_CHANGED:
-         {
-           GstState old, new, pending;
-
-           if (src == element) 
-             {
-               gst_message_parse_state_changed (message, 
-                                                &old, &new, &pending);
-               if (new == state) 
-                 {
-                   gst_message_unref (message);
-                   goto success;
-                 }
-             }
-         }
-         break;
-       case GST_MESSAGE_ERROR:
-         {
-           gchar  *debug = NULL;
-           GError *gsterror = NULL;
-
-           gst_message_parse_error (message, &gsterror, &debug);
-
-           g_warning ("Error: %s (%s)", gsterror->message, debug);
-
-           gst_message_unref (message);
-           g_error_free (gsterror);
-           g_free (debug);
-           goto error;
-         }
-         break;
-       case GST_MESSAGE_EOS:
-         g_set_error (error, CLUTTER_VIDEO_TEXTURE_ERROR,
-                      CLUTTER_VIDEO_TEXTURE_ERROR_FILE_GENERIC,
-                      "Media file could not be played.");
-         gst_message_unref (message);
-         goto error;
-         break;
-       default:
-         g_assert_not_reached ();
-         break;
-       }
-      gst_message_unref (message);
-    }
-  
-  g_assert_not_reached ();
-
-success:
-  /* state change succeeded */
-  CLUTTER_DBG ("state change to %s succeeded", 
-              gst_element_state_get_name (state));
-
-  priv->ignore_messages_mask = saved_events;
-  return TRUE;
+  g_object_notify (G_OBJECT (video_texture), "position");
 
-timed_out:
-  /* it's taking a long time to open -- just tell totem it was ok, this allows
-   * the user to stop the loading process with the normal stop button */
-  CLUTTER_DBG ("state change to %s timed out, returning success and handling "
-              "errors asynchroneously", gst_element_state_get_name (state));
-  priv->ignore_messages_mask = saved_events;
   return TRUE;
-
-error:
-  CLUTTER_DBG ("error while waiting for state change to %s: %s",
-              gst_element_state_get_name (state),
-              (error && *error) ? (*error)->message : "unknown");
-  priv->ignore_messages_mask = saved_events;
-  return FALSE;
-}
-
-static gboolean
-poll_for_state_change (ClutterVideoTexture *video_texture, 
-                      GstElement          *element,
-                      GstState             state, 
-                      GError             **error)
-{
-  return poll_for_state_change_full (video_texture, 
-                                    element, 
-                                    state, 
-                                    error, 
-                                    GST_SECOND/4 );
 }
 
 static void
@@ -814,7 +659,6 @@ fakesink_handoff_cb (GstElement *fakesrc,
                     GstPad     *pad, 
                     gpointer    user_data)
 {
-
   GstStructure  *structure;
   int            width, height;
   GdkPixbuf     *pixb;
@@ -835,7 +679,7 @@ fakesink_handoff_cb (GstElement *fakesrc,
                                   (3 * width + 3) &~ 3,
                                   NULL,
                                   NULL);
-
+  
   if (pixb)
     {
       clutter_texture_set_pixbuf (CLUTTER_TEXTURE(user_data), pixb);
@@ -843,298 +687,61 @@ fakesink_handoff_cb (GstElement *fakesrc,
     }
 }
 
-static void 
-clutter_video_texture_finalize (GObject *object)
-{
-  ClutterVideoTexture        *self;
-  ClutterVideoTexturePrivate *priv; 
-
-  self = CLUTTER_VIDEO_TEXTURE(object); 
-  priv = self->priv;
-
-  if (priv->bus) 
-    {
-      /* make bus drop all messages to make sure none of our callbacks is ever
-       * called again (main loop might be run again to display error dialog) */
-      gst_bus_set_flushing (priv->bus, TRUE);
-
-      if (priv->sig_bus_async)
-       g_signal_handler_disconnect (priv->bus, priv->sig_bus_async);
-      
-      gst_object_unref (priv->bus);
-      priv->bus = NULL;
-    }
-
-  if (priv->mrl)
-    g_free (priv->mrl);
-  priv->mrl = NULL;
-  
-  if (priv->play != NULL && GST_IS_ELEMENT (priv->play)) 
-    {
-      gst_element_set_state (priv->play, GST_STATE_NULL);
-      gst_object_unref (priv->play);
-      priv->play = NULL;
-    }
-
-  if (priv->update_id) 
-    {
-      g_source_remove (priv->update_id);
-      priv->update_id = 0;
-    }
-
-  if (priv->tagcache) 
-    {
-      gst_tag_list_free (priv->tagcache);
-      priv->tagcache = NULL;
-    }
-
-  if (priv->audiotags) 
-    {
-      gst_tag_list_free (priv->audiotags);
-      priv->audiotags = NULL;
-    }
-
-  if (priv->videotags) 
-    {
-      gst_tag_list_free (priv->videotags);
-      priv->videotags = NULL;
-    }
-
-  if (priv->eos_id != 0)
-    g_source_remove (priv->eos_id);
-
-  g_free (priv);
-
-  self->priv = NULL;
-
-  G_OBJECT_CLASS (clutter_video_texture_parent_class)->finalize (object);
-}
-
-static void
-clutter_video_texture_set_property (GObject      *object, 
-                                   guint         property_id,
-                                   const GValue *value, 
-                                   GParamSpec   *pspec)
-{
-  switch (property_id)
-    {
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
-    }
-}
-
-static void
-clutter_video_texture_get_property (GObject    *object, 
-                                   guint       property_id,
-                                   GValue     *value, 
-                                   GParamSpec *pspec)
-{
-  ClutterVideoTexture *video_texture;
-
-  video_texture = CLUTTER_VIDEO_TEXTURE (object);
-
-  switch (property_id)
-    {
-      case PROP_POSITION:
-       g_value_set_int64 (value, 
-                          clutter_video_texture_get_position (video_texture));
-       break;
-      case PROP_STREAM_LENGTH:
-       g_value_set_int64 (value,
-           clutter_video_texture_get_stream_length (video_texture));
-       break;
-      case PROP_PLAYING:
-       g_value_set_boolean (value,
-           clutter_video_texture_is_playing (video_texture));
-       break;
-      case PROP_SEEKABLE:
-       g_value_set_boolean (value,
-           clutter_video_texture_is_seekable (video_texture));
-       break;
-      default:
-       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
-    }
-}
-
-
-static void
-clutter_video_texture_class_init (ClutterVideoTextureClass *klass)
-{
-  GObjectClass        *object_class;
-  ClutterElementClass *element_class;
-
-  object_class = (GObjectClass*)klass;
-  element_class = (ClutterElementClass*)klass;
-
-  object_class->finalize = clutter_video_texture_finalize;
-  object_class->set_property = clutter_video_texture_set_property;
-  object_class->get_property = clutter_video_texture_get_property;
-
-  /* Properties */
-  g_object_class_install_property (object_class, PROP_POSITION,
-                                  g_param_spec_int ("position", NULL, NULL,
-                                                    0, G_MAXINT, 0,
-                                                    G_PARAM_READABLE));
-  g_object_class_install_property (object_class, PROP_STREAM_LENGTH,
-                                  g_param_spec_int64 ("stream_length", NULL,
-                                                    NULL, 0, G_MAXINT64, 0,
-                                                    G_PARAM_READABLE));
-  g_object_class_install_property (object_class, PROP_PLAYING,
-                                  g_param_spec_boolean ("playing", NULL,
-                                                        NULL, FALSE,
-                                                        G_PARAM_READABLE));
-  g_object_class_install_property (object_class, PROP_SEEKABLE,
-                                  g_param_spec_boolean ("seekable", NULL,
-                                                        NULL, FALSE,
-                                                        G_PARAM_READABLE));
-
-  /* Signals */
-  cvt_signals[SIGNAL_ERROR] =
-    g_signal_new ("error",
-                 G_TYPE_FROM_CLASS (object_class),
-                 G_SIGNAL_RUN_LAST,
-                 G_STRUCT_OFFSET (ClutterVideoTextureClass, error),
-                 NULL, NULL,
-                 clutter_marshal_VOID__STRING_BOOLEAN_BOOLEAN,
-                 G_TYPE_NONE, 3, G_TYPE_STRING,
-                 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN);
-
-  cvt_signals[SIGNAL_EOS] =
-    g_signal_new ("eos",
-                 G_TYPE_FROM_CLASS (object_class),
-                 G_SIGNAL_RUN_LAST,
-                 G_STRUCT_OFFSET (ClutterVideoTextureClass, eos),
-                 NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
-
-  cvt_signals[SIGNAL_GOT_METADATA] =
-    g_signal_new ("got-metadata",
-                 G_TYPE_FROM_CLASS (object_class),
-                 G_SIGNAL_RUN_LAST,
-                 G_STRUCT_OFFSET (ClutterVideoTextureClass, got_metadata),
-                 NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
-
-  cvt_signals[SIGNAL_REDIRECT] =
-    g_signal_new ("got-redirect",
-                 G_TYPE_FROM_CLASS (object_class),
-                 G_SIGNAL_RUN_LAST,
-                 G_STRUCT_OFFSET (ClutterVideoTextureClass, got_redirect),
-                 NULL, NULL, g_cclosure_marshal_VOID__STRING,
-                 G_TYPE_NONE, 1, G_TYPE_STRING);
-
-  cvt_signals[SIGNAL_TITLE_CHANGE] =
-    g_signal_new ("title-change",
-                 G_TYPE_FROM_CLASS (object_class),
-                 G_SIGNAL_RUN_LAST,
-                 G_STRUCT_OFFSET (ClutterVideoTextureClass, title_change),
-                 NULL, NULL,
-                 g_cclosure_marshal_VOID__STRING,
-                 G_TYPE_NONE, 1, G_TYPE_STRING);
-
-  cvt_signals[SIGNAL_CHANNELS_CHANGE] =
-    g_signal_new ("channels-change",
-                 G_TYPE_FROM_CLASS (object_class),
-                 G_SIGNAL_RUN_LAST,
-                 G_STRUCT_OFFSET (ClutterVideoTextureClass, channels_change),
-                 NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
-
-  cvt_signals[SIGNAL_TICK] =
-    g_signal_new ("tick",
-                 G_TYPE_FROM_CLASS (object_class),
-                 G_SIGNAL_RUN_LAST,
-                 G_STRUCT_OFFSET (ClutterVideoTextureClass, tick),
-                 NULL, NULL,
-                 clutter_marshal_VOID__INT64_INT64_FLOAT_BOOLEAN,
-                 G_TYPE_NONE, 4, G_TYPE_INT64, G_TYPE_INT64, G_TYPE_FLOAT,
-                  G_TYPE_BOOLEAN);
-
-  cvt_signals[SIGNAL_BUFFERING] =
-    g_signal_new ("buffering",
-                 G_TYPE_FROM_CLASS (object_class),
-                 G_SIGNAL_RUN_LAST,
-                 G_STRUCT_OFFSET (ClutterVideoTextureClass, buffering),
-                 NULL, NULL,
-                 g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
-
-  cvt_signals[SIGNAL_SPEED_WARNING] =
-    g_signal_new ("speed-warning",
-                 G_TYPE_FROM_CLASS (object_class),
-                 G_SIGNAL_RUN_LAST,
-                 G_STRUCT_OFFSET (ClutterVideoTextureClass, speed_warning),
-                 NULL, NULL,
-                 g_cclosure_marshal_VOID__VOID,
-                 G_TYPE_NONE, 0);
-
-}
-
-
-static void
-clutter_video_texture_init (ClutterVideoTexture *video_texture)
+static gboolean
+lay_pipeline (ClutterVideoTexture *video_texture)
 {
   ClutterVideoTexturePrivate *priv;
-  GstElement                 *audio_sink, *video_sink, *bin, *capsfilter;
-  GstCaps                    *filtercaps;
-  GstPad                     *ghost_pad;
+  GstElement                 *audio_sink = NULL;
+  GstElement                 *video_sink, *video_bin, *video_capsfilter;
+  GstCaps                    *video_filtercaps;
+  GstPad                     *video_ghost_pad;
 
-  priv                 = g_new0 (ClutterVideoTexturePrivate, 1);
-  video_texture->priv  = priv;
+  priv = video_texture->priv;
 
-  priv->ratio_type     = CLUTTER_VIDEO_TEXTURE_AUTO;
+  priv->playbin = gst_element_factory_make ("playbin", "playbin");
 
-  priv->play = gst_element_factory_make ("playbin", "play");
-  
-  if (!priv->play) 
+  if (!priv->playbin) 
     {
-      g_warning ("Could not create element 'playbin'");
-      return;
+      g_warning ("Unable to create playbin GST element.");
+      return FALSE;
     }
 
-  priv->bus = gst_element_get_bus (priv->play);
-  gst_bus_add_signal_watch (priv->bus);
-  priv->sig_bus_async = g_signal_connect (priv->bus, 
-                                         "message", 
-                                         G_CALLBACK (bus_message_cb),
-                                         video_texture);
-
   audio_sink = gst_element_factory_make ("gconfaudiosink", "audio-sink");
-
-  if (audio_sink == NULL) 
+  if (!audio_sink) 
     {
-      g_warning ("Could not create element 'gconfaudiosink' trying autosink");
       audio_sink = gst_element_factory_make ("autoaudiosink", "audio-sink");
-
-      if (audio_sink == NULL)
+      if (!audio_sink) 
        {
-         g_warning ("Could not create element 'autoaudiosink' "
-                    "trying fakesink");
-         audio_sink = gst_element_factory_make ("fakesink",  
-                                                "audio-fake-sink");
-         if (audio_sink == NULL)
-           {
-             g_warning ("Could not create element 'fakesink' for audio, giving up. ");
-           }
+         audio_sink = gst_element_factory_make ("alsasink", "audio-sink");
+         g_warning ("Could not create a GST audio_sink. "
+                    "Audio unavailable.");
+
+         if (!audio_sink)      /* Need to bother ? */
+           audio_sink = gst_element_factory_make ("fakesink", "audio-sink");
        }
     }
-  
-  priv->audio_sink = audio_sink;
 
   video_sink = gst_element_factory_make ("fakesink", "fakesink");
 
   if (video_sink == NULL) 
     {
       g_warning ("Could not create element 'fakesink' for video playback");
-      return;
+      priv->playbin = NULL;
+      return FALSE;
     }
 
-  bin = gst_bin_new  ("video-bin");
+  video_bin = gst_bin_new  ("video-bin");
 
-  capsfilter = gst_element_factory_make ("capsfilter", "vfilter");
+  video_capsfilter = gst_element_factory_make ("capsfilter", 
+                                              "video-capsfilter");
 
-  filtercaps 
+  video_filtercaps 
     = gst_caps_new_simple("video/x-raw-rgb",
                          "bpp", G_TYPE_INT, 24,
                          "depth", G_TYPE_INT, 24,
                          "endianness", G_TYPE_INT, G_BIG_ENDIAN, 
-                         "red_mask", G_TYPE_INT, 0xff0000 /* >> 8 for 24bpp */, 
+                         /* >> 8 for 24bpp */ 
+                         "red_mask", G_TYPE_INT, 0xff0000,
                          "green_mask", G_TYPE_INT, 0xff00,
                          "blue_mask", G_TYPE_INT,  0xff,
                          "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
@@ -1143,711 +750,114 @@ clutter_video_texture_init (ClutterVideoTexture *video_texture)
                          0, 1, G_MAXINT, 1, 
                          NULL);
 
-  g_object_set(G_OBJECT(capsfilter), "caps", filtercaps, NULL);
+  g_object_set(G_OBJECT(video_capsfilter), 
+              "caps", video_filtercaps, 
+              NULL);
 
-  gst_bin_add(GST_BIN(bin), capsfilter);
-  gst_bin_add(GST_BIN(bin), video_sink);
+  gst_bin_add(GST_BIN(video_bin), video_capsfilter);
+  gst_bin_add(GST_BIN(video_bin), video_sink);
 
-  gst_element_link (capsfilter, video_sink);
+  gst_element_link (video_capsfilter, video_sink);
 
-  ghost_pad = gst_ghost_pad_new ("sink", 
-                                gst_element_get_pad (capsfilter, "sink"));
-
-  gst_element_add_pad (bin, ghost_pad);
+  video_ghost_pad = gst_ghost_pad_new ("sink", 
+                                      gst_element_get_pad (video_capsfilter, 
+                                                           "sink"));
+  gst_element_add_pad (video_bin, video_ghost_pad);
 
   g_object_set (G_OBJECT(video_sink), 
                "signal-handoffs", TRUE, 
                "sync", TRUE,
                NULL);
 
-  g_signal_connect(G_OBJECT (video_sink), "handoff",
-                  G_CALLBACK(fakesink_handoff_cb), video_texture);
-
-  priv->video_sink = bin;
-
-  if (priv->video_sink)
-    g_object_set (priv->play, "video-sink", bin, NULL);
-
-  if (priv->audio_sink)
-    g_object_set (priv->play, "audio-sink", audio_sink, NULL);
-  
-  g_signal_connect (priv->play, "notify::source",
-                   G_CALLBACK (playbin_got_source), video_texture);
-  g_signal_connect (priv->play, "notify::stream-info",
-                   G_CALLBACK (playbin_stream_info_set), video_texture);
-  return;
-}
-
-ClutterElement*
-clutter_video_texture_new (void)
-{
-  ClutterVideoTexture        *video_texture;
-
-  video_texture = g_object_new (CLUTTER_TYPE_VIDEO_TEXTURE, 
-                               "tiled", FALSE, 
-                               "pixel-format", GL_RGB,
-                               NULL);
-
-  return CLUTTER_ELEMENT(video_texture);
-}
-
-gboolean
-clutter_video_texture_open (ClutterVideoTexture *video_texture,
-                           const gchar         *mrl, 
-                           const gchar         *subtitle_uri, 
-                           GError             **error)
-{
-  ClutterVideoTexturePrivate *priv;
-  gboolean                    ret;
-
-  priv = video_texture->priv;
-
-  g_return_val_if_fail (video_texture != NULL, FALSE);
-  g_return_val_if_fail (mrl != NULL, FALSE);
-  g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE(video_texture), FALSE);
-  g_return_val_if_fail (priv->play != NULL, FALSE);
-  
-  if (priv->mrl && strcmp (priv->mrl, mrl) == 0) 
-    return TRUE;
-
-  /* this allows non-URI type of files in the thumbnailer and so on */
-  if (priv->mrl)
-    g_free (priv->mrl);
-
-  if (mrl[0] == '/') 
-    {
-      priv->mrl = g_strdup_printf ("file://%s", mrl);
-    }
-  else 
-    {
-      if (strchr (mrl, ':')) 
-       {
-         priv->mrl = g_strdup (mrl);
-       } 
-      else 
-       {
-         gchar *cur_dir = g_get_current_dir ();
-         if (!cur_dir) 
-           {
-             g_set_error (error, CLUTTER_VIDEO_TEXTURE_ERROR,
-                          CLUTTER_VIDEO_TEXTURE_ERROR_GENERIC,
-                          "Failed to retrieve working directory");
-             return FALSE;
-           }
-         priv->mrl = g_strdup_printf ("file://%s/%s", cur_dir, mrl);
-         g_free (cur_dir);
-       }
-    }
-
-  priv->got_redirect = FALSE;
-  priv->has_video    = FALSE;
-  priv->has_audio    = FALSE;
-  priv->stream_length = 0;
-  
-  if (g_strrstr (priv->mrl, "#subtitle:")) 
-    {
-      gchar **uris;
-      gchar *subtitle_uri;
-
-      uris = g_strsplit (priv->mrl, "#subtitle:", 2);
-      /* Try to fix subtitle uri if needed */
-      if (uris[1][0] == '/') 
-       {
-         subtitle_uri = g_strdup_printf ("file://%s", uris[1]);
-       }
-      else 
-       {
-         if (strchr (uris[1], ':')) 
-           {
-             subtitle_uri = g_strdup (uris[1]);
-           } 
-         else 
-           {
-             gchar *cur_dir = g_get_current_dir ();
-             if (!cur_dir) 
-               {
-                 g_set_error (error, CLUTTER_VIDEO_TEXTURE_ERROR,
-                              CLUTTER_VIDEO_TEXTURE_ERROR_GENERIC,
-                              "Failed to retrieve working directory");
-                 return FALSE;
-               }
-
-             subtitle_uri = g_strdup_printf ("file://%s/%s", 
-                                             cur_dir, uris[1]);
-             g_free (cur_dir);
-           }
-       }
-
-      g_object_set (priv->play, 
-                   "uri", priv->mrl,
-                   "suburi", subtitle_uri, 
-                   NULL);
-      g_free (subtitle_uri);
-      g_strfreev (uris);
-    } 
-  else 
-    {
-      g_object_set (priv->play, 
-                   "uri", priv->mrl,
-                   "suburi", subtitle_uri, 
-                   NULL);
-    }
-  
-  gst_element_set_state (priv->play, GST_STATE_PAUSED);
-
-  ret = poll_for_state_change (video_texture, 
-                              priv->play, 
-                              GST_STATE_PAUSED, 
-                              NULL);
-
-  if (!ret) 
-    {
-      priv->ignore_messages_mask |= GST_MESSAGE_ERROR;
-      stop_play_pipeline (video_texture);
-      g_free (priv->mrl);
-      priv->mrl = NULL;
-    }
-  else
-    g_signal_emit (video_texture, cvt_signals[SIGNAL_CHANNELS_CHANGE], 0);
-
-  return ret;
-}
-
-gboolean
-clutter_video_texture_play (ClutterVideoTexture *video_texture, 
-                           GError             ** error)
-{
-  ClutterVideoTexturePrivate *priv;
-  gboolean                    ret;
-
-  priv = video_texture->priv;
-
-  g_return_val_if_fail (video_texture != NULL, FALSE);
-  g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE(video_texture), FALSE);
-  g_return_val_if_fail (priv->play != NULL, FALSE);
-
-  gst_element_set_state (priv->play, GST_STATE_PLAYING); 
-
-  ret = poll_for_state_change (video_texture, 
-                              priv->play, 
-                              GST_STATE_PLAYING, 
-                              error);
-  return ret;
-}
-
-void
-clutter_video_texture_pause (ClutterVideoTexture *video_texture)
-{
-  g_return_if_fail (video_texture != NULL);
-  g_return_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture));
-  g_return_if_fail (GST_IS_ELEMENT (video_texture->priv->play));
-
-  CLUTTER_DBG ("Pausing");
-
-  gst_element_set_state (GST_ELEMENT (video_texture->priv->play), 
-                        GST_STATE_PAUSED);
-}
-
-
-gboolean
-clutter_video_texture_can_direct_seek (ClutterVideoTexture *video_texture)
-{
-  g_return_val_if_fail (video_texture != NULL, FALSE);
-  g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), FALSE);
-  g_return_val_if_fail (GST_IS_ELEMENT (video_texture->priv->play), FALSE);
-
-  if (!video_texture->priv->mrl)
-    return FALSE;
-
-  /* (instant seeking only make sense with video, hence no cdda:// here) */
-  if (g_str_has_prefix (video_texture->priv->mrl, "file://") ||
-      g_str_has_prefix (video_texture->priv->mrl, "dvd://") ||
-      g_str_has_prefix (video_texture->priv->mrl, "vcd://"))
-    return TRUE;
-
-  return FALSE;
-}
-
-gboolean
-clutter_video_texture_seek_time (ClutterVideoTexture *video_texture, 
-                                gint64               time, 
-                                GError             **gerror)
-{
-  g_return_val_if_fail (video_texture != NULL, FALSE);
-  g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), FALSE);
-  g_return_val_if_fail (GST_IS_ELEMENT (video_texture->priv->play), FALSE);
-
-  got_time_tick (video_texture->priv->play, time * GST_MSECOND, video_texture);
-  
-  gst_element_seek (video_texture->priv->play, 
-                   1.0,
-                   GST_FORMAT_TIME, 
-                   GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT,
-                   GST_SEEK_TYPE_SET, 
-                   time * GST_MSECOND,
-                   GST_SEEK_TYPE_NONE, 
-                   GST_CLOCK_TIME_NONE);
-
-  gst_element_get_state (video_texture->priv->play, 
-                        NULL, NULL, 100 * GST_MSECOND);
-  return TRUE;
-}
-
-gboolean
-clutter_video_texture_seek (ClutterVideoTexture *video_texture, 
-                           float                position, 
-                           GError             **error)
-{
-  gint64 seek_time, length_nanos;
+  g_signal_connect(G_OBJECT (video_sink), 
+                  "handoff",
+                  G_CALLBACK(fakesink_handoff_cb), 
+                  video_texture);
 
-  g_return_val_if_fail (video_texture != NULL, FALSE);
-  g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), FALSE);
-  g_return_val_if_fail (GST_IS_ELEMENT (video_texture->priv->play), FALSE);
-
-  length_nanos = (gint64) (video_texture->priv->stream_length * GST_MSECOND);
-  seek_time    = (gint64) (length_nanos * position);
-
-  return clutter_video_texture_seek_time (video_texture, 
-                                         seek_time / GST_MSECOND, error);
-}
-
-static void
-stop_play_pipeline (ClutterVideoTexture *video_texture)
-{
-  GstElement *playbin = video_texture->priv->play;
-  GstState    current_state;
-
-  /* first go to ready, that way our state change handler gets to see
-   * our state change messages (before the bus goes to flushing) and
-   * cleans up */
-  gst_element_get_state (playbin, &current_state, NULL, 0);
-
-  if (current_state > GST_STATE_READY) 
-    {
-      GError *err = NULL;
-
-      gst_element_set_state (playbin, GST_STATE_READY);
-      poll_for_state_change_full (video_texture, 
-                                 playbin, 
-                                 GST_STATE_READY, &err, -1);
-      if (err)
-       g_error_free (err);
-    }
-
-  /* now finally go to null state */
-  gst_element_set_state (playbin, GST_STATE_NULL);
-  gst_element_get_state (playbin, NULL, NULL, -1);
-}
-
-void
-clutter_video_texture_stop (ClutterVideoTexture *video_texture)
-{
-  g_return_if_fail (video_texture != NULL);
-  g_return_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture));
-  g_return_if_fail (GST_IS_ELEMENT (video_texture->priv->play));
-
-  stop_play_pipeline (video_texture);
-  
-  /* Reset position to 0 when stopping */
-  got_time_tick (GST_ELEMENT (video_texture->priv->play), 0, video_texture);
-}
+  g_object_set (G_OBJECT (priv->playbin),
+               "video-sink", video_bin,
+               "audio-sink", audio_sink,
+               NULL);
 
-gboolean
-clutter_video_texture_can_set_volume (ClutterVideoTexture *video_texture)
-{
-  g_return_val_if_fail (video_texture != NULL, FALSE);
-  g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), FALSE);
-  g_return_val_if_fail (GST_IS_ELEMENT (video_texture->priv->play), FALSE);
-  
   return TRUE;
 }
 
-void
-clutter_video_texture_set_volume (ClutterVideoTexture *video_texture, 
-                                 int                  volume)
-{
-  g_return_if_fail (video_texture != NULL);
-  g_return_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture));
-  g_return_if_fail (GST_IS_ELEMENT (video_texture->priv->play));
-
-  if (clutter_video_texture_can_set_volume (video_texture) != FALSE)
-  {
-    volume = CLAMP (volume, 0, 100);
-    g_object_set (video_texture->priv->play, "volume",
-                 (gdouble) (1. * volume / 100), NULL);
-  }
-}
-
-int
-clutter_video_texture_get_volume (ClutterVideoTexture *video_texture)
-{
-  gdouble vol;
-
-  g_return_val_if_fail (video_texture != NULL, -1);
-  g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), -1);
-  g_return_val_if_fail (GST_IS_ELEMENT (video_texture->priv->play), -1);
-
-  g_object_get (G_OBJECT (video_texture->priv->play), "volume", &vol, NULL);
-
-  return (gint) (vol * 100 + 0.5);
-}
-
-gint64
-clutter_video_texture_get_current_time (ClutterVideoTexture *video_texture)
-{
-  g_return_val_if_fail (video_texture != NULL, -1);
-  g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), -1);
-
-  return video_texture->priv->current_time;
-}
-
-gint64
-clutter_video_texture_get_stream_length (ClutterVideoTexture *video_texture)
-{
-  ClutterVideoTexturePrivate *priv;
-
-  g_return_val_if_fail (video_texture != NULL, -1);
-  g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), -1);
-
-  priv = video_texture->priv;
-
-  if (priv->stream_length == 0  && priv->play != NULL) 
-    {
-      GstFormat fmt = GST_FORMAT_TIME;
-      gint64    len = -1;
-
-      if (gst_element_query_duration (priv->play, &fmt, &len) && len != -1)
-       priv->stream_length = len / GST_MSECOND;
-    }
-
-  return priv->stream_length;
-}
-
-gboolean
-clutter_video_texture_is_playing (ClutterVideoTexture *video_texture)
-{
-  GstState cur, pending;
-
-  g_return_val_if_fail (video_texture != NULL, FALSE);
-  g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), FALSE);
-  g_return_val_if_fail (GST_IS_ELEMENT (video_texture->priv->play), FALSE);
-
-  gst_element_get_state (video_texture->priv->play, &cur, &pending, 0);
-
-  if (cur == GST_STATE_PLAYING || pending == GST_STATE_PLAYING)
-    return TRUE;
-
-  return FALSE;
-}
-
-gboolean
-clutter_video_texture_is_seekable (ClutterVideoTexture *video_texture)
-{
-  gboolean res;
-
-  g_return_val_if_fail (video_texture != NULL, FALSE);
-  g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), FALSE);
-  g_return_val_if_fail (GST_IS_ELEMENT (video_texture->priv->play), FALSE);
-
-  if (video_texture->priv->stream_length == 0) 
-    res = (clutter_video_texture_get_stream_length (video_texture) > 0);
-  else 
-    res = (video_texture->priv->stream_length > 0);
-
-  return res;
-}
-
-float
-clutter_video_texture_get_position (ClutterVideoTexture  *video_texture)
-{
-  g_return_val_if_fail (video_texture != NULL, -1);
-  g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), -1);
-
-  return video_texture->priv->current_position;
-}
-
-void
-clutter_video_texture_set_aspect_ratio (ClutterVideoTexture  *video_texture,
-                                       ClutterVideoTextureAspectRatio ratio)
-{
-  g_return_if_fail (video_texture != NULL);
-  g_return_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture));
-
-  video_texture->priv->ratio_type = ratio;
-  got_video_size (video_texture);
-}
-
-ClutterVideoTextureAspectRatio
-clutter_video_texture_get_aspect_ratio (ClutterVideoTexture  *video_texture)
-{
-  g_return_val_if_fail (video_texture != NULL, 0);
-  g_return_val_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture), 0);
-
-  return video_texture->priv->ratio_type;
-}
-
-/* Metadata */
-
-static const struct _metadata_map_info 
-{
-  ClutterVideoTextureMetadataType type;
-  const gchar *str;
-} metadata_str_map[] = {
-  { CLUTTER_INFO_TITLE,        "title" },
-  { CLUTTER_INFO_ARTIST,       "artist" },
-  { CLUTTER_INFO_YEAR,         "year" },
-  { CLUTTER_INFO_ALBUM,        "album" },
-  { CLUTTER_INFO_DURATION,     "duration" },
-  { CLUTTER_INFO_TRACK_NUMBER, "track-number" },
-  { CLUTTER_INFO_HAS_VIDEO,    "has-video" },
-  { CLUTTER_INFO_DIMENSION_X,  "dimension-x" },
-  { CLUTTER_INFO_DIMENSION_Y,  "dimension-y" },
-  { CLUTTER_INFO_VIDEO_BITRATE,"video-bitrate" },
-  { CLUTTER_INFO_VIDEO_CODEC,  "video-codec" },
-  { CLUTTER_INFO_FPS,          "fps" },
-  { CLUTTER_INFO_HAS_AUDIO,    "has-audio" },
-  { CLUTTER_INFO_AUDIO_BITRATE,"audio-bitrate" },
-  { CLUTTER_INFO_AUDIO_CODEC,  "audio-codec" }
-};
-
-static const gchar*
-get_metadata_type_name (ClutterVideoTextureMetadataType type)
-{
-  guint i;
-  for (i = 0; i < G_N_ELEMENTS (metadata_str_map); ++i) 
-    {
-      if (metadata_str_map[i].type == type)
-       return metadata_str_map[i].str;
-    }
-  return "unknown";
-}
-
 static void
-get_metadata_string (ClutterVideoTexture            *video_texture,
-                    ClutterVideoTextureMetadataType type,
-                    GValue                         *value)
+clutter_video_texture_init (ClutterVideoTexture *video_texture)
 {
   ClutterVideoTexturePrivate *priv;
-  char                       *string = NULL;
-  gboolean                    res = FALSE;
-
-  priv = video_texture->priv;
+  GstBus                     *bus;
 
-  g_value_init (value, G_TYPE_STRING);
+  priv                 = g_new0 (ClutterVideoTexturePrivate, 1);
+  video_texture->priv  = priv;
 
-  if (priv->play == NULL || priv->tagcache == NULL)
+  if (!lay_pipeline(video_texture))
     {
-      g_value_set_string (value, NULL);
+      g_warning("Failed to initiate suitable playback pipeline.");
       return;
     }
 
-  switch (type)
-    {
-    case CLUTTER_INFO_TITLE:
-      res = gst_tag_list_get_string_index (priv->tagcache,
-                                          GST_TAG_TITLE, 0, &string);
-      break;
-    case CLUTTER_INFO_ARTIST:
-      res = gst_tag_list_get_string_index (priv->tagcache,
-                                          GST_TAG_ARTIST, 0, &string);
-      break;
-    case CLUTTER_INFO_YEAR: 
-      {
-       GDate *date;
-       if ((res = gst_tag_list_get_date (priv->tagcache,
-                                         GST_TAG_DATE, &date))) 
-         {
-           string = g_strdup_printf ("%d", g_date_get_year (date));
-           g_date_free (date);
-         }
-       break;
-      }
-    case CLUTTER_INFO_ALBUM:
-      res = gst_tag_list_get_string_index (priv->tagcache,
-                                          GST_TAG_ALBUM, 0, &string);
-      break;
-    case CLUTTER_INFO_VIDEO_CODEC:
-      res = gst_tag_list_get_string (priv->tagcache,
-                                    GST_TAG_VIDEO_CODEC, &string);
-      break;
-    case CLUTTER_INFO_AUDIO_CODEC:
-      res = gst_tag_list_get_string (priv->tagcache,
-                                    GST_TAG_AUDIO_CODEC, &string);
-      break;
-    default:
-      g_assert_not_reached ();
-    }
+  bus = gst_pipeline_get_bus (GST_PIPELINE (priv->playbin));
 
-  if (res) 
-    {
-      g_value_take_string (value, string);
-      CLUTTER_DBG ("%s = '%s'", get_metadata_type_name (type), string);
-    } 
-  else
-    g_value_set_string (value, NULL);
+  gst_bus_add_signal_watch (bus);
 
-  return;
-}
+  g_signal_connect_object (bus,
+                          "message::error",
+                          G_CALLBACK (bus_message_error_cb),
+                          video_texture,
+                          0);
 
-static void
-get_metadata_int (ClutterVideoTexture            *video_texture,
-                 ClutterVideoTextureMetadataType type,
-                 GValue                         *value)
-{
-  ClutterVideoTexturePrivate *priv;
-  int                         integer = 0;
-
-  priv = video_texture->priv;
-
-  g_value_init (value, G_TYPE_INT);
-
-  if (priv->play == NULL)
-    {
-      g_value_set_int (value, 0);
-      return;
-    }
-
-  switch (type)
-    {
-    case CLUTTER_INFO_DURATION:
-      integer = clutter_video_texture_get_stream_length (video_texture) / 1000;
-      break;
-    case CLUTTER_INFO_TRACK_NUMBER:
-      if (!gst_tag_list_get_uint (priv->tagcache,
-                                 GST_TAG_TRACK_NUMBER, (guint *) &integer))
-        integer = 0;
-      break;
-    case CLUTTER_INFO_DIMENSION_X:
-      integer = priv->video_width;
-      break;
-    case CLUTTER_INFO_DIMENSION_Y:
-      integer = priv->video_height;
-      break;
-    case CLUTTER_INFO_FPS:
-      if (priv->video_fps_d > 0) 
-       {
-         /* Round up/down to the nearest integer framerate */
-         integer = (priv->video_fps_n + priv->video_fps_d/2) /
-           priv->video_fps_d;
-       }
-      else
-        integer = 0;
-      break;
-    case CLUTTER_INFO_AUDIO_BITRATE:
-      if (priv->audiotags == NULL)
-        break;
-      if (gst_tag_list_get_uint (priv->audiotags, GST_TAG_BITRATE,
-          (guint *)&integer) ||
-          gst_tag_list_get_uint (priv->audiotags, GST_TAG_NOMINAL_BITRATE,
-          (guint *)&integer)) {
-        integer /= 1000;
-      }
-      break;
-    case CLUTTER_INFO_VIDEO_BITRATE:
-      if (priv->videotags == NULL)
-        break;
-      if (gst_tag_list_get_uint (priv->videotags, GST_TAG_BITRATE,
-                                (guint *)&integer) ||
-          gst_tag_list_get_uint (priv->videotags, GST_TAG_NOMINAL_BITRATE,
-                                (guint *)&integer)) {
-        integer /= 1000;
-      }
-      break;
-    default:
-      g_assert_not_reached ();
-    }
+  g_signal_connect_object (bus,
+                          "message::eos",
+                          G_CALLBACK (bus_message_eos_cb),
+                          video_texture,
+                          0);
 
-  g_value_set_int (value, integer);
-  CLUTTER_DBG ("%s = %d", get_metadata_type_name (type), integer);
-
-  return;
-}
+  g_signal_connect_object (bus,
+                          "message::tag",
+                          G_CALLBACK (bus_message_tag_cb),
+                          video_texture,
+                          0);
 
-static void
-get_metadata_bool (ClutterVideoTexture            *video_texture,
-                  ClutterVideoTextureMetadataType type,
-                  GValue                         *value)
-{
-  ClutterVideoTexturePrivate *priv;
-  gboolean                    boolean = FALSE;
+  g_signal_connect_object (bus,
+                          "message::buffering",
+                          G_CALLBACK (bus_message_buffering_cb),
+                          video_texture,
+                          0);
 
-  priv = video_texture->priv;
+  g_signal_connect_object (bus,
+                          "message::duration",
+                          G_CALLBACK (bus_message_duration_cb),
+                          video_texture,
+                          0);
 
-  g_value_init (value, G_TYPE_BOOLEAN);
+  g_signal_connect_object (bus,
+                          "message::element",
+                          G_CALLBACK (bus_message_element_cb),
+                          video_texture,
+                          0);
 
-  if (priv->play == NULL) 
-    {
-      g_value_set_boolean (value, FALSE);
-      return;
-    }
+  g_signal_connect_object (bus,
+                          "message::state-changed",
+                          G_CALLBACK (bus_message_state_change_cb),
+                          video_texture,
+                          0);
 
-  switch (type)
-    {
-    case CLUTTER_INFO_HAS_VIDEO:
-      boolean = priv->has_video;
-      /* if properties dialog, show the metadata we
-       * have even if we cannot decode the stream */
-      if (!boolean
-         && priv->tagcache != NULL 
-         && gst_structure_has_field ((GstStructure *) priv->tagcache,
-                                     GST_TAG_VIDEO_CODEC)) 
-        boolean = TRUE;
-      break;
-    case CLUTTER_INFO_HAS_AUDIO:
-      boolean = priv->has_audio;
-      /* if properties dialog, show the metadata we
-       * have even if we cannot decode the stream */
-      if (!boolean
-         && priv->tagcache != NULL 
-         && gst_structure_has_field ((GstStructure *) priv->tagcache,
-                                     GST_TAG_AUDIO_CODEC)) 
-        boolean = TRUE;
-      break;
-    default:
-      g_assert_not_reached ();
-  }
+  gst_object_unref (GST_OBJECT (bus));
 
-  g_value_set_boolean (value, boolean);
-  CLUTTER_DBG ("%s = %s", get_metadata_type_name (type), 
-                                        (boolean) ? "yes" : "no");
   return;
 }
 
-void
-clutter_video_texture_get_metadata (ClutterVideoTexture *video_texture,
-                                   ClutterVideoTextureMetadataType type,
-                                   GValue                         *value)
+ClutterElement*
+clutter_video_texture_new (void)
 {
-  g_return_if_fail (video_texture != NULL);
-  g_return_if_fail (CLUTTER_IS_VIDEO_TEXTURE (video_texture));
-  g_return_if_fail (GST_IS_ELEMENT (video_texture->priv->play));
+  ClutterVideoTexture        *video_texture;
 
-  switch (type)
-    {
-    case CLUTTER_INFO_TITLE:
-    case CLUTTER_INFO_ARTIST:
-    case CLUTTER_INFO_YEAR:
-    case CLUTTER_INFO_ALBUM:
-    case CLUTTER_INFO_VIDEO_CODEC:
-    case CLUTTER_INFO_AUDIO_CODEC:
-      get_metadata_string (video_texture, type, value);
-      break;
-    case CLUTTER_INFO_DURATION:
-    case CLUTTER_INFO_DIMENSION_X:
-    case CLUTTER_INFO_DIMENSION_Y:
-    case CLUTTER_INFO_FPS:
-    case CLUTTER_INFO_AUDIO_BITRATE:
-    case CLUTTER_INFO_VIDEO_BITRATE:
-    case CLUTTER_INFO_TRACK_NUMBER:
-      get_metadata_int (video_texture, type, value);
-      break;
-    case CLUTTER_INFO_HAS_VIDEO:
-    case CLUTTER_INFO_HAS_AUDIO:
-      get_metadata_bool (video_texture, type, value);
-      break;
-    default:
-      g_return_if_reached ();
-    }
+  video_texture = g_object_new (CLUTTER_TYPE_VIDEO_TEXTURE, 
+                               "tiled", FALSE, 
+                               "pixel-format", GL_RGB,
+                               NULL);
 
-  return;
+  return CLUTTER_ELEMENT(video_texture);
 }
+
index 94e6b63..29cbd70 100644 (file)
@@ -1,9 +1,35 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Authored By Matthew Allum  <mallum@openedhand.com>
+ *
+ * Copyright (C) 2006 OpenedHand
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
 #ifndef _HAVE_CLUTTER_VIDEO_TEXTURE_H
 #define _HAVE_CLUTTER_VIDEO_TEXTURE_H
 
 #include <glib-object.h>
 #include <clutter/clutter-element.h>
 #include <clutter/clutter-texture.h>
+#include <clutter/clutter-media.h>
 #include <gdk-pixbuf/gdk-pixbuf.h>
 
 G_BEGIN_DECLS
@@ -31,58 +57,10 @@ G_BEGIN_DECLS
   CLUTTER_TYPE_VIDEO_TEXTURE, ClutterVideoTextureClass))
 
 typedef struct ClutterVideoTexturePrivate ClutterVideoTexturePrivate ;
-typedef struct _ClutterVideoTexture ClutterVideoTexture;
-typedef struct _ClutterVideoTextureClass ClutterVideoTextureClass;
-
-
-#define CLUTTER_VIDEO_TEXTURE_ERROR clutter_video_texture_error_quark()
+typedef struct _ClutterVideoTexture       ClutterVideoTexture;
+typedef struct _ClutterVideoTextureClass  ClutterVideoTextureClass;
 
-typedef enum
-{
-  /* Plugins */
-  CLUTTER_VIDEO_TEXTURE_ERROR_AUDIO_PLUGIN,
-  CLUTTER_VIDEO_TEXTURE_ERROR_NO_PLUGIN_FOR_FILE,
-  CLUTTER_VIDEO_TEXTURE_ERROR_VIDEO_PLUGIN,
-  CLUTTER_VIDEO_TEXTURE_ERROR_AUDIO_BUSY,
-       
-  /* File */
-  CLUTTER_VIDEO_TEXTURE_ERROR_BROKEN_FILE,
-  CLUTTER_VIDEO_TEXTURE_ERROR_FILE_GENERIC,
-  CLUTTER_VIDEO_TEXTURE_ERROR_FILE_PERMISSION,
-  CLUTTER_VIDEO_TEXTURE_ERROR_FILE_ENCRYPTED,
-  CLUTTER_VIDEO_TEXTURE_ERROR_FILE_NOT_FOUND,
-       
-  /* Devices */
-  CLUTTER_VIDEO_TEXTURE_ERROR_DVD_ENCRYPTED,
-  CLUTTER_VIDEO_TEXTURE_ERROR_INVALID_DEVICE,
-       
-  /* Network */
-  CLUTTER_VIDEO_TEXTURE_ERROR_UNKNOWN_HOST,
-  CLUTTER_VIDEO_TEXTURE_ERROR_NETWORK_UNREACHABLE,
-  CLUTTER_VIDEO_TEXTURE_ERROR_CONNECTION_REFUSED,
-       
-  /* Generic */
-  CLUTTER_VIDEO_TEXTURE_ERROR_UNVALID_LOCATION,
-  CLUTTER_VIDEO_TEXTURE_ERROR_GENERIC,
-  CLUTTER_VIDEO_TEXTURE_ERROR_CODEC_NOT_HANDLED,
-  CLUTTER_VIDEO_TEXTURE_ERROR_AUDIO_ONLY,
-  CLUTTER_VIDEO_TEXTURE_ERROR_CANNOT_CAPTURE,
-  CLUTTER_VIDEO_TEXTURE_ERROR_READ_ERROR,
-  CLUTTER_VIDEO_TEXTURE_ERROR_PLUGIN_LOAD,
-  CLUTTER_VIDEO_TEXTURE_ERROR_STILL_IMAGE,
-  CLUTTER_VIDEO_TEXTURE_ERROR_EMPTY_FILE
-} ClutterVideoTextureError;
-
-GQuark clutter_video_texture_error_quark (void);
-
-typedef enum
-{
-  CLUTTER_VIDEO_TEXTURE_AUTO,
-  CLUTTER_VIDEO_TEXTURE_SQUARE,
-  CLUTTER_VIDEO_TEXTURE_FOURBYTHREE,
-  CLUTTER_VIDEO_TEXTURE_ANAMORPHIC,
-  CLUTTER_VIDEO_TEXTURE_DVB
-} ClutterVideoTextureAspectRatio;
+/* #define CLUTTER_VIDEO_TEXTURE_ERROR clutter_video_texture_error_quark() */
 
 struct _ClutterVideoTexture
 {
@@ -94,20 +72,20 @@ struct _ClutterVideoTextureClass
 {
   ClutterTextureClass parent_class;
 
-  void (*error) (ClutterVideoTexture *cvt, const char *message,
-                gboolean playback_stopped, gboolean fatal);
-  void (*eos) (ClutterVideoTexture *cvt);
-  void (*got_metadata) (ClutterVideoTexture *cvt);
-  void (*got_redirect) (ClutterVideoTexture *cvt, const char *mrl);
-  void (*title_change) (ClutterVideoTexture *cvt, const char *title);
-  void (*channels_change) (ClutterVideoTexture *cvt);
-  void (*tick) (ClutterVideoTexture *cvt, 
-               gint64 current_time, 
-               gint64 stream_length,
-               float current_position, 
-               gboolean seekable);
-  void (*buffering) (ClutterVideoTexture *cvt, guint progress);
-  void (*speed_warning) (ClutterVideoTexture *cvt);
+  /* Signals */
+  void (* tag_list_available) (ClutterVideoTexture *video_texture,
+                              GstTagList          *tag_list);
+  void (* eos)                (ClutterVideoTexture *video_texture);
+  void (* error)              (ClutterVideoTexture *video_texture,
+                              GError              *error);
+
+  /* Future padding */
+  void (* _clutter_reserved1) (void);
+  void (* _clutter_reserved2) (void);
+  void (* _clutter_reserved3) (void);
+  void (* _clutter_reserved4) (void);
+  void (* _clutter_reserved5) (void);
+  void (* _clutter_reserved6) (void);
 }; 
 
 GType clutter_video_texture_get_type (void);
@@ -115,99 +93,6 @@ GType clutter_video_texture_get_type (void);
 ClutterElement*
 clutter_video_texture_new (void);
 
-gboolean
-clutter_video_texture_open (ClutterVideoTexture *video_texture,
-                           const gchar         *mrl, 
-                           const gchar         *subtitle_uri, 
-                           GError             **error);
-
-gboolean
-clutter_video_texture_play (ClutterVideoTexture *video_texture, 
-                           GError             ** error);
-
-void
-clutter_video_texture_pause (ClutterVideoTexture *video_texture);
-
-gboolean
-clutter_video_texture_can_direct_seek (ClutterVideoTexture *video_texture);
-
-gboolean
-clutter_video_texture_seek_time (ClutterVideoTexture *video_texture, 
-                                gint64               time, 
-                                GError             **gerror);
-
-gboolean
-clutter_video_texture_seek (ClutterVideoTexture *video_texture, 
-                           float                position, 
-                           GError             **error);
-
-void
-clutter_video_texture_stop (ClutterVideoTexture *video_texture);
-
-gboolean
-clutter_video_texture_can_set_volume (ClutterVideoTexture *video_texture);
-
-void
-clutter_video_texture_set_volume (ClutterVideoTexture *video_texture, 
-                                 int                  volume);
-int
-clutter_video_texture_get_volume (ClutterVideoTexture *video_texture);
-
-gint64
-clutter_video_texture_get_current_time (ClutterVideoTexture *video_texture);
-
-gint64
-clutter_video_texture_get_stream_length (ClutterVideoTexture *video_texture);
-
-gboolean
-clutter_video_texture_is_playing (ClutterVideoTexture *video_texture);
-
-gboolean
-clutter_video_texture_is_seekable (ClutterVideoTexture * video_texture);
-
-float
-clutter_video_texture_get_position (ClutterVideoTexture  *video_texture);
-
-void
-clutter_video_texture_set_aspect_ratio (ClutterVideoTexture  *video_texture,
-                                       ClutterVideoTextureAspectRatio ratio);
-
-ClutterVideoTextureAspectRatio
-clutter_video_texture_get_aspect_ratio (ClutterVideoTexture  *video_texture);
-
-/* Metadata 
- * FIXME: This should probably go in some kind of genric 'Media' class
- *        You would open the media, get a media object and then pass 
- *        that to the video texture. media object could handle being
- *        just a metadata reader etc...
-*/
-typedef enum 
-{
-    CLUTTER_INFO_TITLE,
-    CLUTTER_INFO_ARTIST,
-    CLUTTER_INFO_YEAR,
-    CLUTTER_INFO_ALBUM,
-    CLUTTER_INFO_DURATION,
-    CLUTTER_INFO_TRACK_NUMBER,
-    /* Video */
-    CLUTTER_INFO_HAS_VIDEO,
-    CLUTTER_INFO_DIMENSION_X,
-    CLUTTER_INFO_DIMENSION_Y,
-    CLUTTER_INFO_VIDEO_BITRATE,
-    CLUTTER_INFO_VIDEO_CODEC,
-    CLUTTER_INFO_FPS,
-    /* Audio */
-    CLUTTER_INFO_HAS_AUDIO,
-    CLUTTER_INFO_AUDIO_BITRATE,
-    CLUTTER_INFO_AUDIO_CODEC,
-} ClutterVideoTextureMetadataType;
-
-
-void
-clutter_video_texture_get_metadata (ClutterVideoTexture *video_texture,
-                                   ClutterVideoTextureMetadataType type,
-                                   GValue                         *value);
-
 G_END_DECLS
 
 #endif
index 9b6cd64..5110321 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "clutter-keysyms.h" 
 #include "clutter-main.h"
+#include "clutter-media.h"
 #include "clutter-color.h"
 #include "clutter-util.h"
 #include "clutter-event.h"
index e2f2fe1..a6631ef 100644 (file)
@@ -2,19 +2,6 @@
 
 ClutterElement *rect; /* um... */
 
-gboolean 
-foo (gpointer data)
-{
-  static int i = 0;
-
-  clutter_element_set_opacity (CLUTTER_ELEMENT(data), i);
-
-  i += 10;
-
-  if (i>255) i = 0;
-
-  return TRUE;
-}
 
 void input_cb (ClutterStage *stage, 
               ClutterEvent *event,
@@ -27,12 +14,12 @@ void input_cb (ClutterStage *stage,
     {
       if (paused)
        {
-         clutter_video_texture_play (vtex, NULL);
+         clutter_media_set_playing (CLUTTER_MEDIA(vtex), TRUE);
          paused = 0;
        }
       else
        {
-         clutter_video_texture_pause (vtex);
+         clutter_media_set_playing (CLUTTER_MEDIA(vtex), FALSE);
          paused = 1;
        }
     }
@@ -67,29 +54,30 @@ size_change (ClutterTexture *texture,
                            stage_geom.width,
                            new_height);
 
-  clutter_element_set_opacity (CLUTTER_ELEMENT (texture), 50);
+  // clutter_element_set_opacity (CLUTTER_ELEMENT (texture), 50);
 
   printf("*** Pos set to +%i+%i , %ix%i ***\n", 
         0, new_y, stage_geom.width, new_height);
 }
 
 void 
-tick (ClutterVideoTexture *cvt, 
-      gint64              current_time, 
-      gint64              stream_length,
-      float               current_position, 
-      gboolean            seekable,
-      gpointer            userdata)
+tick (GObject      *object,
+      GParamSpec   *pspec,
+      ClutterLabel *label)
 {
-  gint          w, h;
-  gchar         buf[256];
-  ClutterLabel *label = CLUTTER_LABEL(userdata);
+  ClutterVideoTexture *vtex;
+  gint                 w, h, position, duration;
+  gchar                buf[256];
+
+  vtex = CLUTTER_VIDEO_TEXTURE(object);
 
-  g_snprintf(buf, 256, "%lli/%lli secs", 
-            current_time / 1000,
-            stream_length / 1000); 
+  position = clutter_media_get_position (CLUTTER_MEDIA(vtex));
+  duration = clutter_media_get_duration (CLUTTER_MEDIA(vtex));
+
+  g_snprintf(buf, 256, "%i / %i", position, duration);
 
   clutter_label_set_text (label, buf);
+
   clutter_texture_get_base_size (CLUTTER_TEXTURE(label), &w, &h);
   clutter_element_set_size(rect, w+10, h+10);
 }
@@ -99,8 +87,8 @@ main (int argc, char *argv[])
 {
   ClutterElement        *label, *vtexture, *ctexture;
   ClutterElement        *stage;
-  ClutterColor           rect_color = { 0xde, 0xde, 0xdf, 0xaa };
-  ClutterColor           stage_color = { 0xff, 0xff, 0xff, 0x00 };
+  ClutterColor           rect_color =  { 0xde, 0xde, 0xdf, 0xaa };
+  ClutterColor           stage_color = { 0x00, 0x00, 0x00, 0x00 };
   GError                *err = NULL;
 
   if (argc < 2)
@@ -110,6 +98,8 @@ main (int argc, char *argv[])
 
   vtexture = clutter_video_texture_new ();
 
+  clutter_media_set_filename(CLUTTER_MEDIA(vtexture), argv[1]);
+
   stage = clutter_stage_get_default ();
 
   /* Broken..
@@ -117,8 +107,6 @@ main (int argc, char *argv[])
   g_object_set(vtexture, "repeat-y", TRUE, NULL);
   */
 
-  printf("tiled okey\n");
-
   if (vtexture == NULL || err != NULL)
     {
       g_error("failed to create vtexture, err: %s", err->message);
@@ -133,39 +121,27 @@ main (int argc, char *argv[])
   clutter_element_set_position(rect, 5, 5);
 
   ctexture = clutter_clone_texture_new (CLUTTER_TEXTURE(vtexture));
+  clutter_element_set_opacity (CLUTTER_ELEMENT (ctexture), 100);
 
   clutter_element_set_size (ctexture, 640, 50);
   clutter_element_set_position (ctexture, 0, 430);
 
-  /*
-  clutter_element_set_clip (CLUTTER_ELEMENT(clutter_stage()), 
-                           0, 0, 100, 100);
-  */
-
-  clutter_video_texture_open(CLUTTER_VIDEO_TEXTURE(vtexture), 
-                            argv[1],
-                            NULL,
-                            NULL);
-
-  clutter_group_add (CLUTTER_GROUP (stage), vtexture);
-  clutter_group_add (CLUTTER_GROUP (stage), rect);
-  clutter_group_add (CLUTTER_GROUP (stage), label);
-  clutter_group_add (CLUTTER_GROUP (stage), ctexture);
+  clutter_group_add_many (CLUTTER_GROUP (stage), 
+                         vtexture, rect, label, ctexture, NULL);
 
   clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); 
 
   g_signal_connect (stage, "input-event",
                    G_CALLBACK (input_cb), 
                    vtexture);
-
   clutter_group_show_all (CLUTTER_GROUP (stage));
 
+  clutter_media_set_playing (CLUTTER_MEDIA(vtexture), TRUE);
 
-  if (!clutter_video_texture_play(CLUTTER_VIDEO_TEXTURE(vtexture), NULL))
-      g_error("failed to play vtexture");
-
-  g_signal_connect (vtexture, "tick",
-                   G_CALLBACK (tick), 
+  g_signal_connect (CLUTTER_MEDIA(vtexture),
+                   "notify::position",
+                   G_CALLBACK (tick),
                    label);
 
   g_object_set (G_OBJECT(vtexture), "sync-size", FALSE, NULL);
@@ -174,8 +150,6 @@ main (int argc, char *argv[])
                    "size-change",
                    G_CALLBACK (size_change), NULL);
 
-  /* g_timeout_add (100, foo, vtexture); */
-
   clutter_main();
 
   g_object_unref (stage);
index f57f3a4..ab4fd85 100644 (file)
@@ -254,17 +254,14 @@ main (int argc, char *argv[])
       g_error("failed to create vtexture, err: %s", err->message);
     }
 
-  clutter_video_texture_open(CLUTTER_VIDEO_TEXTURE(vtexture), 
-                            argv[1],
-                            NULL,
-                            NULL);
+
+  clutter_media_set_filename (CLUTTER_MEDIA(vtexture), argv[1]);
 
   clutter_group_add (CLUTTER_GROUP (stage), texture);
   clutter_group_add (CLUTTER_GROUP (stage), vtexture);
   clutter_group_show_all (CLUTTER_GROUP (stage));
 
-  if (!clutter_video_texture_play(CLUTTER_VIDEO_TEXTURE(vtexture), NULL))
-      g_error("failed to play vtexture");
+  clutter_media_set_playing(CLUTTER_MEDIA(vtexture), TRUE);
 
   clutter_main();