[clutter-gst] Break API and concepts around VideoTexture



commit 43c904845e0e804b48f1dc5d800ad097c5d938f0
Author: Lionel Landwerlin <llandwerlin gmail com>
Date:   Tue Feb 12 18:07:27 2013 +0000

    Break API and concepts around VideoTexture

 clutter-gst/Makefile.am                            |   23 +-
 clutter-gst/clutter-gst-actor.c                    |  804 +----
 clutter-gst/clutter-gst-actor.h                    |   57 +-
 clutter-gst/clutter-gst-camera-actor.h             |  216 --
 ...ter-gst-camera-actor.c => clutter-gst-camera.c} | 1186 ++++----
 clutter-gst/clutter-gst-camera.h                   |  208 ++
 clutter-gst/clutter-gst-playback.c                 | 2799 ++++++++++++++++
 clutter-gst/clutter-gst-playback.h                 |  116 +
 clutter-gst/clutter-gst-player.c                   | 3363 ++------------------
 clutter-gst/clutter-gst-player.h                   |  181 +-
 clutter-gst/clutter-gst-private.h                  |    7 +
 clutter-gst/clutter-gst-types.c                    |   75 +
 clutter-gst/clutter-gst-types.h                    |   21 +
 clutter-gst/clutter-gst-util.c                     |   29 +-
 clutter-gst/clutter-gst-video-actor.c              |  184 --
 clutter-gst/clutter-gst-video-actor.h              |  113 -
 clutter-gst/clutter-gst-video-sink.c               |  494 ++--
 clutter-gst/clutter-gst-video-sink.h               |    2 +
 clutter-gst/clutter-gst.h                          |    5 +-
 configure.ac                                       |    2 +
 examples/camera-player.c                           |   94 +-
 examples/video-player.c                            |   66 +-
 examples/video-sink.c                              |   47 +-
 tests/test-start-stop.c                            |   45 +-
 tests/test-video-actor-new-unref-loop.c            |    2 +-
 25 files changed, 4709 insertions(+), 5430 deletions(-)
---
diff --git a/clutter-gst/Makefile.am b/clutter-gst/Makefile.am
index 49f1763..2feae3d 100644
--- a/clutter-gst/Makefile.am
+++ b/clutter-gst/Makefile.am
@@ -25,11 +25,10 @@ source_h =                                  \
        $(srcdir)/clutter-gst-types.h           \
        $(srcdir)/clutter-gst-util.h            \
        $(srcdir)/clutter-gst-version.h         \
-       $(srcdir)/clutter-gst-actor.h   \
-       $(srcdir)/clutter-gst-video-sink.h      \
-       $(srcdir)/clutter-gst-video-actor.h     \
-       $(srcdir)/clutter-gst-camera-actor.h    \
+       $(srcdir)/clutter-gst-actor.h           \
+       $(srcdir)/clutter-gst-camera.h          \
        $(srcdir)/clutter-gst-camera-device.h   \
+       $(srcdir)/clutter-gst-playback.h        \
        $(srcdir)/clutter-gst-player.h          \
        $(NULL)
 
@@ -41,13 +40,13 @@ source_priv_h =                                     \
 
 source_c =                                     \
        $(srcdir)/clutter-gst-debug.c           \
+       $(srcdir)/clutter-gst-types.c           \
        $(srcdir)/clutter-gst-marshal.c         \
        $(srcdir)/clutter-gst-player.c          \
        $(srcdir)/clutter-gst-actor.c           \
-       $(srcdir)/clutter-gst-video-sink.c      \
-       $(srcdir)/clutter-gst-video-actor.c     \
-       $(srcdir)/clutter-gst-camera-actor.c    \
+       $(srcdir)/clutter-gst-camera.c          \
        $(srcdir)/clutter-gst-camera-device.c   \
+       $(srcdir)/clutter-gst-playback.c        \
        $(srcdir)/clutter-gst-util.c            \
        $(glib_enum_c)                          \
        $(NULL)
@@ -102,8 +101,7 @@ cluttergstheaders_HEADERS = $(source_h) $(glib_enum_h)
 #
 
 plugin_source_c =                              \
-       $(srcdir)/clutter-gst-plugin.c  \
-       $(srcdir)/clutter-gst-video-sink.c      \
+       $(srcdir)/clutter-gst-plugin.c          \
        $(srcdir)/clutter-gst-auto-video-sink.c \
        $(srcdir)/clutter-gst-auto-video-sink.h \
        $(NULL)
@@ -139,7 +137,9 @@ ClutterGst- CLUTTER_GST_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libclutter-gs
                --add-include-path=$(srcdir) --add-include=path=. \
                --c-include="clutter-gst/clutter-gst.h" \
                --include=GObject-2.0 \
+               --include=Cogl-1.0 \
                --include=Clutter-1.0 \
+               --include=GdkPixbuf-2.0 \
                --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-1.0` \
                --include=Gst-1.0 \
                --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-base-1.0` \
@@ -148,12 +148,16 @@ ClutterGst- CLUTTER_GST_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libclutter-gs
                --include=GstVideo-1.0 \
                --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-audio-1.0` \
                --include=GstAudio-1.0 \
+               --add-include-path=`$(PKG_CONFIG) --variable=girdir gstreamer-pbutils-1.0` \
+               --include=GstPbutils-1.0 \
                --add-init-section="clutter_gst_init(0,NULL);" \
                --library=libclutter-gst- CLUTTER_GST_API_VERSION@.la \
                --libtool="$(top_builddir)/libtool" \
                --output $@ \
                --pkg gobject-2.0 \
+               --pkg cogl-1.0 \
                --pkg clutter-1.0 \
+               --pkg gdk-pixbuf-2.0 \
                --pkg gstreamer-1.0 \
                --pkg gstreamer-base-1.0 \
                --pkg-export clutter-gst- CLUTTER_GST_API_VERSION@ \
@@ -178,6 +182,7 @@ typelibs_DATA = $(BUILT_GIRSOURCES:.gir=.typelib)
                --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-base-1.0` \
                --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-video-1.0` \
                --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-audio-1.0` \
+               --includedir=`$(PKG_CONFIG) --variable=girdir gstreamer-pbutils-1.0` \
                $(INTROSPECTION_COMPILER_OPTS) $< -o $(builddir)/$(@F)
 
 CLEANFILES += $(BUILT_GIRSOURCES) $(typelibs_DATA)
diff --git a/clutter-gst/clutter-gst-actor.c b/clutter-gst/clutter-gst-actor.c
index b36c01a..c33fe35 100644
--- a/clutter-gst/clutter-gst-actor.c
+++ b/clutter-gst/clutter-gst-actor.c
@@ -11,7 +11,7 @@
  *             Andre Moreira Magalhaes <andre magalhaes collabora co uk>
  *
  * Copyright (C) 2006 OpenedHand
- * Copyright (C) 2010, 2011 Intel Corporation
+ * Copyright (C) 2010-2013 Intel Corporation
  * Copyright (C) 2012 Collabora Ltd. <http://www.collabora.co.uk/>
  *
  * This library is free software; you can redistribute it and/or
@@ -56,365 +56,73 @@
 
 struct _ClutterGstActorPrivate
 {
-  CoglPipeline *pipeline;
-
-  /* width / height (in pixels) of the frame data before applying the pixel
-   * aspect ratio */
-  gint buffer_width;
-  gint buffer_height;
-
-  /* Pixel aspect ration is par_n / par_d. this is set by the sink */
-  guint par_n, par_d;
-
-  /* natural width / height (in pixels) of the actor (after par applied) */
-  guint texture_width;
-  guint texture_height;
-
-  CoglHandle idle_material;
-  CoglColor idle_color_unpre;
+  ClutterGstPlayer *player;
+  ClutterGstFrame  *frame;
 };
 
 static CoglPipeline *texture_template_pipeline = NULL;
 
 enum {
   PROP_0,
-  PROP_TEXTURE,
-  PROP_MATERIAL,
-  PROP_IDLE,
-  PROP_IDLE_MATERIAL,
-  PROP_PAR
-};
 
-enum
-{
-  SIZE_CHANGE,
-  LAST_SIGNAL
+  PROP_PLAYER
 };
 
-static int actor_signals[LAST_SIGNAL] = { 0 };
-
 G_DEFINE_TYPE (ClutterGstActor, clutter_gst_actor, CLUTTER_TYPE_ACTOR)
 
-/* Clutter 1.4 has this symbol, we don't want to depend on 1.4 just for that
- * just yet */
-static void
-_cogl_color_unpremultiply (CoglColor *color)
-{
-  gfloat alpha;
-
-  alpha = cogl_color_get_alpha (color);
-
-  if (alpha != 0)
-    {
-      gfloat red, green, blue;
-
-      red = cogl_color_get_red (color);
-      green = cogl_color_get_green (color);
-      blue = cogl_color_get_blue (color);
-
-      red = red / alpha;
-      green = green / alpha;
-      blue = blue / alpha;
-
-      cogl_color_set_from_4f (color, red, green, blue, alpha);
-    }
-}
-
-/* Clutter 1.4 has this symbol, we don't want to depend on 1.4 just for that
- * just yet */
-static void
-_cogl_color_set_alpha_byte (CoglColor     *color,
-                            unsigned char  alpha)
-{
-  unsigned char red, green, blue;
-
-  red = cogl_color_get_red_byte (color);
-  green = cogl_color_get_green_byte (color);
-  blue = cogl_color_get_blue_byte (color);
-
-  cogl_color_set_from_4ub (color, red, green, blue, alpha);
-}
-
 static void
-texture_free_gl_resources (ClutterGstActor *actor)
+clutter_gst_actor_paint_frame (ClutterGstActor *self,
+                               ClutterGstFrame *frame)
 {
-  ClutterGstActorPrivate *priv = actor->priv;
-
-  if (priv->pipeline != NULL)
-    {
-      /* We want to keep the layer so that the filter settings will
-         remain but we want to free its resources so we clear the
-         texture handle */
-      cogl_pipeline_set_layer_texture (priv->pipeline, 0, NULL);
-    }
-}
-
-static void
-gen_texcoords_and_draw_cogl_rectangle (ClutterActor *actor)
-{
-  ClutterActorBox box;
-
-  clutter_actor_get_allocation_box (actor, &box);
-
-  cogl_rectangle_with_texture_coords (0, 0,
-                                      box.x2 - box.x1,
-                                      box.y2 - box.y1,
-                                      0, 0, 1.0, 1.0);
-}
-
-static void
-create_black_idle_material (ClutterGstActor *actor)
-{
-  ClutterGstActorPrivate *priv = actor->priv;
-
-  priv->idle_material = cogl_material_new ();
-  cogl_color_set_from_4ub (&priv->idle_color_unpre, 0, 0, 0, 0xff);
-  cogl_material_set_color (priv->idle_material, &priv->idle_color_unpre);
-}
-
-/*
- * ClutterActor implementation
- */
-
-static gboolean
-clutter_gst_actor_get_paint_volume (ClutterActor       *actor,
-                                    ClutterPaintVolume *volume)
-{
-  ClutterGstActorPrivate *priv = CLUTTER_GST_ACTOR (actor)->priv;
+  ClutterGstActorPrivate *priv = self->priv;
   ClutterActorBox box;
-
-  if (priv->pipeline == NULL)
-    return FALSE;
-
-  if (priv->buffer_width == 0 || priv->buffer_height == 0)
-    return FALSE;
-
-  /* calling clutter_actor_get_allocation_* can potentially be very
-   * expensive, as it can result in a synchronous full stage relayout
-   * and redraw
-   */
-  if (!clutter_actor_has_allocation (actor))
-    return FALSE;
-
-  clutter_actor_get_allocation_box (actor, &box);
-
-  /* we only set the width and height, as the paint volume is defined
-   * to be relative to the actor's modelview, which means that the
-   * allocation's origin has already been applied
-   */
-  clutter_paint_volume_set_width (volume, box.x2 - box.x1);
-  clutter_paint_volume_set_height (volume, box.y2 - box.y1);
-
-  return TRUE;
-}
-
-static void
-clutter_gst_actor_get_natural_size (ClutterGstActor *actor,
-                                    gfloat          *width,
-                                    gfloat          *height)
-{
-  ClutterGstActorPrivate *priv = actor->priv;
-  guint dar_n, dar_d;
-  gboolean ret;
-
-  /* we cache texture_width and texture_height */
-
-  if (G_UNLIKELY (priv->buffer_width == 0 || priv->buffer_height == 0))
-    {
-      /* we don't know the size of the frames yet default to 0,0 */
-      priv->texture_width = 0;
-      priv->texture_height = 0;
-    }
-  else if (G_UNLIKELY (priv->texture_width == 0 || priv->texture_height == 0))
-    {
-      CLUTTER_GST_NOTE (ASPECT_RATIO, "frame is %dx%d with par %d/%d",
-                        priv->buffer_width, priv->buffer_height,
-                        priv->par_n, priv->par_d);
-
-      ret = gst_video_calculate_display_ratio (&dar_n, &dar_d,
-                                               priv->buffer_width,
-                                               priv->buffer_height,
-                                               priv->par_n, priv->par_d,
-                                               1, 1);
-      if (ret == FALSE)
-        dar_n = dar_d = 1;
-
-      if (priv->buffer_height % dar_d == 0)
-        {
-          priv->texture_width = gst_util_uint64_scale (priv->buffer_height,
-                                                       dar_n, dar_d);
-          priv->texture_height = priv->buffer_height;
-        }
-      else if (priv->buffer_width % dar_n == 0)
-        {
-          priv->texture_width = priv->buffer_width;
-          priv->texture_height = gst_util_uint64_scale (priv->buffer_width,
-                                                        dar_d, dar_n);
-
-        }
-      else
-        {
-          priv->texture_width = gst_util_uint64_scale (priv->buffer_height,
-                                                       dar_n, dar_d);
-          priv->texture_height = priv->buffer_height;
-        }
-
-      CLUTTER_GST_NOTE (ASPECT_RATIO,
-                        "final size is %dx%d (calculated par is %d/%d)",
-                        priv->texture_width, priv->texture_height,
-                        dar_n, dar_d);
-    }
-
-  if (width)
-    *width = (gfloat)priv->texture_width;
-
-  if (height)
-    *height = (gfloat)priv->texture_height;
-}
-
-static void
-clutter_gst_actor_get_preferred_width (ClutterActor *self,
-                                       gfloat        for_height,
-                                       gfloat       *min_width_p,
-                                       gfloat       *natural_width_p)
-{
-  ClutterGstActor *actor = CLUTTER_GST_ACTOR (self);
-  ClutterGstActorPrivate *priv = actor->priv;
-  gfloat natural_width, natural_height;
-
-  /* Min request is always 0 since we can scale down or clip */
-  if (min_width_p)
-    *min_width_p = 0;
-
-  if (natural_width_p)
-    {
-      clutter_gst_actor_get_natural_size (actor,
-                                          &natural_width,
-                                          &natural_height);
-
-      if (for_height < 0 ||
-          priv->buffer_height <= 0)
-        {
-          *natural_width_p = natural_width;
-        }
-      else
-        {
-          gfloat ratio =  natural_width /  natural_height;
-
-          *natural_width_p = ratio * for_height;
-        }
-    }
-}
-
-static void
-clutter_gst_actor_get_preferred_height (ClutterActor *self,
-                                        gfloat        for_width,
-                                        gfloat       *min_height_p,
-                                        gfloat       *natural_height_p)
-{
-  ClutterGstActor *actor = CLUTTER_GST_ACTOR (self);
-  ClutterGstActorPrivate *priv = actor->priv;
-  gfloat natural_width, natural_height;
-
-  /* Min request is always 0 since we can scale down or clip */
-  if (min_height_p)
-    *min_height_p = 0;
-
-  if (natural_height_p)
-    {
-      clutter_gst_actor_get_natural_size (actor,
-                                          &natural_width,
-                                          &natural_height);
-
-      if (for_width < 0 ||
-          priv->buffer_width <= 0)
-        {
-          *natural_height_p = natural_height;
-        }
-      else
-        {
-          gfloat ratio = natural_height / natural_width;
-
-          *natural_height_p = ratio * for_width;
-        }
-    }
+  guint8 paint_opacity;
+
+  clutter_actor_get_allocation_box (CLUTTER_ACTOR (self), &box);
+  paint_opacity = clutter_actor_get_paint_opacity (CLUTTER_ACTOR (self));
+  cogl_pipeline_set_color4ub (priv->frame->pipeline,
+                              paint_opacity,
+                              paint_opacity,
+                              paint_opacity,
+                              paint_opacity);
+  cogl_set_source (frame->pipeline);
+
+  cogl_rectangle (0, 0, box.x2 - box.x1, box.y2 - box.y1);
 }
 
 static void
 clutter_gst_actor_paint (ClutterActor *actor)
 {
-  ClutterGstActorPrivate *priv = CLUTTER_GST_ACTOR (actor)->priv;
-  gboolean is_idle;
+  ClutterGstActor *self = CLUTTER_GST_ACTOR (actor);
+  ClutterGstActorPrivate *priv = self->priv;
 
-  is_idle = clutter_gst_actor_is_idle (CLUTTER_GST_ACTOR (actor));
-  if (G_UNLIKELY (is_idle) || !priv->pipeline)
+  if (priv->player)
     {
-      CoglColor *color;
-      gfloat alpha;
+      ClutterGstFrame *frame = clutter_gst_player_get_frame (priv->player);
 
-      /* blend the alpha of the idle material with the actor's opacity */
-      color = cogl_color_copy (&priv->idle_color_unpre);
-      alpha = clutter_actor_get_paint_opacity (actor) *
-              cogl_color_get_alpha_byte (color) / 0xff;
-      _cogl_color_set_alpha_byte (color, alpha);
-      cogl_color_premultiply (color);
-      cogl_material_set_color (priv->idle_material, color);
-
-      cogl_set_source (priv->idle_material);
-
-      /* draw */
-      gen_texcoords_and_draw_cogl_rectangle (actor);
-    }
-  else
-    {
-      guint8 paint_opacity;
-
-      paint_opacity = clutter_actor_get_paint_opacity (actor);
-      cogl_pipeline_set_color4ub (priv->pipeline,
-                                  paint_opacity,
-                                  paint_opacity,
-                                  paint_opacity,
-                                  paint_opacity);
-      cogl_set_source (priv->pipeline);
-
-      gen_texcoords_and_draw_cogl_rectangle (actor);
+      if (frame)
+        CLUTTER_GST_ACTOR_GET_CLASS (self)->paint_frame (self, frame);
     }
 }
 
 /*
- * ClutterGstActor implementation
- */
-
-static gboolean
-clutter_gst_actor_is_idle_impl (ClutterGstActor *actor)
-{
-  ClutterGstActorPrivate *priv = actor->priv;
-
-  return !priv->pipeline;
-}
-
-/*
  * GObject implementation
  */
 
 static void
-clutter_gst_actor_finalize (GObject *object)
+clutter_gst_actor_dispose (GObject *object)
 {
-  ClutterGstActor *actor = CLUTTER_GST_ACTOR (object);
-  ClutterGstActorPrivate *priv = actor->priv;
+  ClutterGstActorPrivate *priv = CLUTTER_GST_ACTOR (object)->priv;
 
-  texture_free_gl_resources (actor);
+  g_clear_object (&priv->player);
 
-  if (priv->pipeline != NULL)
+  if (priv->frame)
     {
-      cogl_object_unref (priv->pipeline);
-      priv->pipeline = NULL;
+      g_boxed_free (CLUTTER_GST_TYPE_FRAME, priv->frame);
+      priv->frame = NULL;
     }
 
-  if (priv->idle_material != COGL_INVALID_HANDLE)
-    cogl_handle_unref (priv->idle_material);
-
-  G_OBJECT_CLASS (clutter_gst_actor_parent_class)->finalize (object);
+  G_OBJECT_CLASS (clutter_gst_actor_parent_class)->dispose (object);
 }
 
 static void
@@ -428,20 +136,11 @@ clutter_gst_actor_get_property (GObject    *object,
 
   switch (property_id)
     {
-    case PROP_TEXTURE:
-      g_value_set_boxed (value, clutter_gst_actor_get_cogl_texture (actor));
-      break;
-    case PROP_MATERIAL:
-      g_value_set_boxed (value, clutter_gst_actor_get_cogl_material (actor));
-      break;
-    case PROP_IDLE:
-      g_value_set_boolean (value, clutter_gst_actor_is_idle (actor));
-      break;
-    case PROP_IDLE_MATERIAL:
-      g_value_set_boxed (value, priv->idle_material);
-      break;
-    case PROP_PAR:
-      gst_value_set_fraction (value, priv->par_n, priv->par_d);
+    /* case PROP_PAR: */
+    /*   gst_value_set_fraction (value, priv->par_n, priv->par_d); */
+    /*   break; */
+    case PROP_PLAYER:
+      g_value_set_object (value, priv->player);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -459,18 +158,13 @@ clutter_gst_actor_set_property (GObject      *object,
 
   switch (property_id)
     {
-    case PROP_TEXTURE:
-      clutter_gst_actor_set_cogl_texture (actor, g_value_get_boxed (value));
-      break;
-    case PROP_MATERIAL:
-      clutter_gst_actor_set_cogl_material (actor, g_value_get_boxed (value));
-      break;
-    case PROP_IDLE_MATERIAL:
-      clutter_gst_actor_set_idle_material (actor, g_value_get_boxed (value));
-      break;
-    case PROP_PAR:
-      priv->par_n = gst_value_get_fraction_numerator (value);
-      priv->par_d = gst_value_get_fraction_denominator (value);
+    /* case PROP_PAR: */
+    /*   priv->par_n = gst_value_get_fraction_numerator (value); */
+    /*   priv->par_d = gst_value_get_fraction_denominator (value); */
+    /*   break; */
+    case PROP_PLAYER:
+      g_clear_object (&priv->player);
+      priv->player = g_value_dup_object (value);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -486,92 +180,27 @@ clutter_gst_actor_class_init (ClutterGstActorClass *klass)
 
   g_type_class_add_private (klass, sizeof (ClutterGstActorPrivate));
 
-  klass->is_idle = clutter_gst_actor_is_idle_impl;
-
-  object_class->finalize = clutter_gst_actor_finalize;
+  object_class->dispose = clutter_gst_actor_dispose;
   object_class->set_property = clutter_gst_actor_set_property;
   object_class->get_property = clutter_gst_actor_get_property;
 
-  actor_class->get_paint_volume = clutter_gst_actor_get_paint_volume;
-  actor_class->get_preferred_width = clutter_gst_actor_get_preferred_width;
-  actor_class->get_preferred_height = clutter_gst_actor_get_preferred_height;
   actor_class->paint = clutter_gst_actor_paint;
 
-  /**
-   * ClutterGstActor:idle:
-   *
-   * Whether the #ClutterGstActor is in idle mode.
-   */
-  pspec = g_param_spec_boolean ("idle",
-                                "Idle",
-                                "Idle state of the actor",
-                                TRUE,
-                                CLUTTER_GST_PARAM_READABLE);
-  g_object_class_install_property (object_class, PROP_IDLE, pspec);
-
-  /**
-   * ClutterGstActor:texture:
-   *
-   * Texture to use for drawing when not in idle.
-   */
-  pspec = g_param_spec_boxed ("texture",
-                              "Texture",
-                              "Texture to use for drawing when not in idle",
-                              COGL_TYPE_HANDLE,
-                              CLUTTER_GST_PARAM_READWRITE);
-  g_object_class_install_property (object_class, PROP_TEXTURE, pspec);
-
-  /**
-   * ClutterGstActor:material:
-   *
-   * Material to use for drawing when not in idle.
-   */
-  pspec = g_param_spec_boxed ("material",
-                              "Material",
-                              "Material to use for drawing when not in idle",
-                              COGL_TYPE_HANDLE,
-                              CLUTTER_GST_PARAM_READWRITE);
-  g_object_class_install_property (object_class, PROP_MATERIAL, pspec);
-
-  /**
-   * ClutterGstActor:idle-material:
-   *
-   * Material to use for drawing when in idle.
-   */
-  pspec = g_param_spec_boxed ("idle-material",
-                              "Idle material",
-                              "Material to use for drawing when in idle",
-                              COGL_TYPE_HANDLE,
-                              CLUTTER_GST_PARAM_READWRITE);
-  g_object_class_install_property (object_class, PROP_IDLE_MATERIAL, pspec);
-
-  pspec = gst_param_spec_fraction ("pixel-aspect-ratio",
-                                   "Pixel Aspect Ratio",
-                                   "Pixel aspect ratio of incoming frames",
-                                   1, 100, 100, 1, 1, 1,
-                                   CLUTTER_GST_PARAM_READWRITE);
-  g_object_class_install_property (object_class, PROP_PAR, pspec);
-
-  /**
-   * ClutterGstActor::size-change:
-   * @actor: the actor which received the signal
-   * @width: the width of the new actor
-   * @height: the height of the new actor
-   *
-   * The ::size-change signal is emitted each time the size of the
-   * pixbuf used by @actor changes. The new size is given as
-   * argument to the callback.
-   */
-  actor_signals[SIZE_CHANGE] =
-    g_signal_new ("size-change",
-                  G_TYPE_FROM_CLASS (object_class),
-                  G_SIGNAL_RUN_LAST,
-                  G_STRUCT_OFFSET (ClutterGstActorClass, size_change),
-                  NULL, NULL,
-                  _clutter_gst_marshal_VOID__INT_INT,
-                  G_TYPE_NONE, 2,
-                  G_TYPE_INT,
-                  G_TYPE_INT);
+  klass->paint_frame = clutter_gst_actor_paint_frame;
+
+  /* pspec = gst_param_spec_fraction ("pixel-aspect-ratio", */
+  /*                                  "Pixel Aspect Ratio", */
+  /*                                  "Pixel aspect ratio of incoming frames", */
+  /*                                  1, 100, 100, 1, 1, 1, */
+  /*                                  CLUTTER_GST_PARAM_READWRITE); */
+  /* g_object_class_install_property (object_class, PROP_PAR, pspec); */
+
+  pspec = g_param_spec_object ("player",
+                               "Player",
+                               "Player",
+                               G_TYPE_OBJECT,
+                               CLUTTER_GST_PARAM_READWRITE);
+  g_object_class_install_property (object_class, PROP_PLAYER, pspec);
 }
 
 static void
@@ -586,65 +215,23 @@ idle_cb (ClutterGstActor *actor,
 static void
 clutter_gst_actor_init (ClutterGstActor *actor)
 {
-  ClutterGstActorPrivate *priv;
-
-  actor->priv = priv =
-    G_TYPE_INSTANCE_GET_PRIVATE (actor,
-                                 CLUTTER_GST_TYPE_ACTOR,
-                                 ClutterGstActorPrivate);
-
-  create_black_idle_material (actor);
-
-  if (G_UNLIKELY (texture_template_pipeline == NULL))
-    {
-      CoglPipeline *pipeline;
-      CoglContext *ctx =
-        clutter_backend_get_cogl_context (clutter_get_default_backend ());
-
-      texture_template_pipeline = cogl_pipeline_new (ctx);
-      pipeline = COGL_PIPELINE (texture_template_pipeline);
-      cogl_pipeline_set_layer_null_texture (pipeline,
-                                            0, /* layer_index */
-                                            COGL_TEXTURE_TYPE_2D);
-    }
-
-  g_assert (texture_template_pipeline != NULL);
-  priv->pipeline = cogl_pipeline_copy (texture_template_pipeline);
-
-  priv->par_n = priv->par_d = 1;
-
-  g_signal_connect (actor, "notify::idle",
-                    G_CALLBACK (idle_cb),
-                    NULL);
+  actor->priv = G_TYPE_INSTANCE_GET_PRIVATE (actor,
+                                             CLUTTER_GST_TYPE_ACTOR,
+                                             ClutterGstActorPrivate);
 }
 
-typedef struct _GetLayerState
-{
-  gboolean has_layer;
-  int first_layer;
-} GetLayerState;
-
-static gboolean
-layer_cb (CoglPipeline *pipeline, int layer, void *user_data)
+static void
+_player_new_frame (ClutterGstPlayer *player,
+                   ClutterGstFrame  *frame,
+                   ClutterGstActor  *self)
 {
-  GetLayerState *state = user_data;
-
-  state->has_layer = TRUE;
-  state->first_layer = layer;
-
-  /* We only care about the first layer. */
-  return FALSE;
-}
+  ClutterGstActorPrivate *priv = self->priv;
 
-static gboolean
-get_first_layer_index (CoglPipeline *pipeline, int *layer_index)
-{
-  GetLayerState state = { FALSE };
-  cogl_pipeline_foreach_layer (pipeline, layer_cb, &state);
-  if (state.has_layer)
-    *layer_index = state.first_layer;
+  if (priv->frame)
+    g_boxed_free (CLUTTER_GST_TYPE_FRAME, priv->frame);
+  priv->frame = g_boxed_copy (CLUTTER_GST_TYPE_FRAME, frame);
 
-  return state.has_layer;
+  clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
 }
 
 /*
@@ -652,238 +239,67 @@ get_first_layer_index (CoglPipeline *pipeline, int *layer_index)
  */
 
 /**
- * clutter_gst_actor_get_cogl_texture:
- * @actor: A #ClutterActor
+ * clutter_gst_actor_get_player:
+ * @self: a #ClutterGstActor
  *
- * Retrieves the handle to the underlying COGL texture used for drawing
- * the actor. No extra reference is taken so if you need to keep the
- * handle then you should call cogl_handle_ref() on it.
+ * Retrieves the #ClutterGstPlayer used by the @self.
  *
- * The texture handle returned is the first layer of the material
- * handle used by the #ClutterActor. If you need to access the other
- * layers you should use clutter_gst_actor_get_cogl_material() instead
- * and use the #CoglMaterial API.
+ * Return value: (transfer none): the #ClutterGstPlayer element used by the actor
  *
- * Return value: (transfer none): a #CoglHandle for the texture. The returned
- *   handle is owned by the #ClutterActor and it should not be unreferenced
+ * Since: 3.0
  */
-CoglHandle
-clutter_gst_actor_get_cogl_texture (ClutterGstActor *actor)
+ClutterGstPlayer *
+clutter_gst_actor_get_player (ClutterGstActor *self)
 {
   ClutterGstActorPrivate *priv;
-  int layer_index;
-
-  g_return_val_if_fail (CLUTTER_GST_IS_ACTOR (actor), NULL);
-
-  priv = actor->priv;
-
-  if (get_first_layer_index (priv->pipeline, &layer_index))
-    return cogl_pipeline_get_layer_texture (priv->pipeline, layer_index);
-
-  return NULL;
-}
-
-/**
- * clutter_gst_actor_set_cogl_texture:
- * @actor: A #ClutterActor
- * @cogl_tex: A CoglHandle for a texture
- *
- * Replaces the underlying COGL texture drawn by this actor with
- * @cogl_tex. A reference to the texture is taken so if the handle is
- * no longer needed it should be deref'd with cogl_handle_unref.
- */
-void
-clutter_gst_actor_set_cogl_texture (ClutterGstActor *actor,
-                                    CoglHandle       cogl_tex)
-{
-  ClutterGstActorPrivate  *priv;
-  gboolean size_changed;
-  guint width, height;
-
-  g_return_if_fail (CLUTTER_GST_IS_ACTOR (actor));
-  g_return_if_fail (cogl_is_texture (cogl_tex));
-
-  /* This function can set the texture without the actor being
-     realized. This is ok because Clutter requires that the GL context
-     always be current so there is no point in waiting to realization
-     to set the texture. */
-
-  priv = actor->priv;
-
-  width = cogl_texture_get_width (cogl_tex);
-  height = cogl_texture_get_height (cogl_tex);
-
-  /* Reference the new texture now in case it is the same one we are
-     already using */
-  cogl_object_ref (cogl_tex);
-
-  /* Remove old texture */
-  texture_free_gl_resources (actor);
-
-  /* Use the new texture */
-  if (priv->pipeline == NULL)
-    priv->pipeline = cogl_pipeline_copy (texture_template_pipeline);
-
-  g_assert (priv->pipeline != NULL);
-  cogl_pipeline_set_layer_texture (priv->pipeline, 0, cogl_tex);
 
-  /* The pipeline now holds a reference to the texture so we can
-     safely release the reference we claimed above */
-  cogl_object_unref (cogl_tex);
+  g_return_val_if_fail (CLUTTER_GST_IS_ACTOR (self), NULL);
 
-  size_changed = (width != (guint) priv->buffer_width || height != (guint) priv->buffer_height);
-  priv->buffer_width = width;
-  priv->buffer_height = height;
+  priv = self->priv;
 
-  if (size_changed)
-    {
-      priv->texture_width = priv->texture_height = 0;
-
-      /* queue a relayout to ask containers/layout manager to ask for
-       * the preferred size again */
-      clutter_actor_queue_relayout (CLUTTER_ACTOR (actor));
-
-      g_signal_emit (actor, actor_signals[SIZE_CHANGE], 0,
-                     priv->buffer_width,
-                     priv->buffer_height);
-    }
-
-  /* If resized actor may need resizing but paint() will do this */
-  clutter_actor_queue_redraw (CLUTTER_ACTOR (actor));
-
-  g_object_notify (G_OBJECT (actor), "texture");
+  return priv->player;
 }
 
 /**
- * clutter_gst_actor_get_cogl_material:
- * @actor: A #ClutterActor
+ * clutter_gst_actor_get_player:
+ * @self: a #ClutterGstActor
  *
- * Returns a handle to the underlying COGL material used for drawing
- * the actor.
+ * Retrieves the #ClutterGstPlayer used by the @self.
  *
- * Return value: (transfer none): a handle for a #CoglMaterial. The
- *   material is owned by the #ClutterActor and it should not be
- *   unreferenced
- */
-CoglHandle
-clutter_gst_actor_get_cogl_material (ClutterGstActor *actor)
-{
-  g_return_val_if_fail (CLUTTER_GST_IS_ACTOR (actor), NULL);
-
-  return actor->priv->pipeline;
-}
-
-/**
- * clutter_gst_actor_set_cogl_material:
- * @actor: A #ClutterActor
- * @cogl_material: A CoglHandle for a material
+ * Return value: (transfer none): the #ClutterGstPlayer element used by the actor
  *
- * Replaces the underlying Cogl material drawn by this actor with
- * @cogl_material. A reference to the material is taken so if the
- * handle is no longer needed it should be deref'd with
- * cogl_handle_unref. Texture data is attached to the material so
- * calling this function also replaces the Cogl
- * texture. #ClutterActor requires that the material have a texture
- * layer so you should set one on the material before calling this
- * function.
+ * Since: 3.0
  */
 void
-clutter_gst_actor_set_cogl_material (ClutterGstActor *actor,
-                                     CoglHandle       cogl_material)
-{
-  CoglPipeline *cogl_pipeline = cogl_material;
-  CoglHandle cogl_texture;
-
-  g_return_if_fail (CLUTTER_GST_IS_ACTOR (actor));
-
-  cogl_object_ref (cogl_pipeline);
-
-  if (actor->priv->pipeline)
-    cogl_object_unref (actor->priv->pipeline);
-
-  actor->priv->pipeline = cogl_pipeline;
-
-  /* XXX: We are re-asserting the first layer of the new pipeline to ensure the
-   * priv state is in sync with the contents of the pipeline. */
-  cogl_texture = clutter_gst_actor_get_cogl_texture (actor);
-  clutter_gst_actor_set_cogl_texture (actor, cogl_texture);
-  /* XXX: If we add support for more pipeline layers, this will need
-   * extending */
-
-  g_object_notify (G_OBJECT (actor), "material");
-}
-
-/**
- * clutter_gst_actor_is_idle:
- * @actor: a #ClutterGstActor
- *
- * Get the idle state of actor.
- *
- * Return value: TRUE if the actor is in idle, FALSE otherwise.
- */
-gboolean
-clutter_gst_actor_is_idle (ClutterGstActor *actor)
+clutter_gst_actor_set_player (ClutterGstActor  *self,
+                              ClutterGstPlayer *player)
 {
-  ClutterGstActorClass *klass;
-
-  g_return_val_if_fail (CLUTTER_GST_IS_ACTOR (actor), TRUE);
-
-  klass = CLUTTER_GST_ACTOR_GET_CLASS (actor);
-
-  return klass->is_idle (actor);
-}
+  ClutterGstActorPrivate *priv;
 
-/**
- * clutter_gst_actor_get_idle_material:
- * @actor: a #ClutterGstActor
- *
- * Retrieves the material used to draw when the actor is idle.
- *
- * Return value: (transfer none): the #CoglHandle of the idle material
- */
-CoglHandle
-clutter_gst_actor_get_idle_material (ClutterGstActor *actor)
-{
-  g_return_val_if_fail (CLUTTER_GST_IS_ACTOR (actor),
-                        COGL_INVALID_HANDLE);
+  g_return_if_fail (CLUTTER_GST_IS_ACTOR (self));
+  g_return_if_fail (CLUTTER_GST_IS_PLAYER (player) || player == NULL);
 
-  return actor->priv->idle_material;
-}
+  priv = self->priv;
 
-/**
- * clutter_gst_actor_set_idle_material:
- * @actor: a #ClutterGstActor
- * @cogl_material: the handle of a Cogl material
- *
- * Sets a material to use to draw when the actor is idle. The
- * #ClutterGstActor holds a reference of the @material.
- *
- * The default idle material will paint the #ClutterGstActor in black.
- * If %COGL_INVALID_HANDLE is given as @cogl_material to this function, this
- * default idle material will be used.
- */
-void
-clutter_gst_actor_set_idle_material (ClutterGstActor *actor,
-                                     CoglHandle       cogl_material)
-{
-  ClutterGstActorPrivate *priv;
+  if (priv->player) {
+    g_boxed_free (CLUTTER_GST_TYPE_FRAME, priv->frame);
+    priv->frame = NULL;
+    g_signal_handlers_disconnect_by_func (priv->player,
+                                          _player_new_frame,
+                                          self);
 
-  g_return_if_fail (CLUTTER_GST_IS_ACTOR (actor));
+    g_clear_object (&priv->player);
+  }
 
-  priv = actor->priv;
-  /* priv->idle_material always has a valid material */
-  cogl_handle_unref (priv->idle_material);
+  if (player != NULL) {
+    priv->player = g_object_ref_sink (player);
+    priv->frame = g_boxed_copy (CLUTTER_GST_TYPE_FRAME,
+                                clutter_gst_player_get_frame (player));
 
-  if (cogl_material != COGL_INVALID_HANDLE)
-    {
-      priv->idle_material = cogl_handle_ref (cogl_material);
-      cogl_material_get_color (cogl_material, &priv->idle_color_unpre);
-      _cogl_color_unpremultiply (&priv->idle_color_unpre);
-    }
-  else
-    {
-      create_black_idle_material (actor);
-    }
+    g_signal_connect (priv->player, "new-frame",
+                      G_CALLBACK (_player_new_frame), self);
+  }
 
-  g_object_notify (G_OBJECT (actor), "idle-material");
+  clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
+  g_object_notify (G_OBJECT (self), "player");
 }
diff --git a/clutter-gst/clutter-gst-actor.h b/clutter-gst/clutter-gst-actor.h
index ab21550..baf4b8b 100644
--- a/clutter-gst/clutter-gst-actor.h
+++ b/clutter-gst/clutter-gst-actor.h
@@ -6,8 +6,10 @@
  * clutter-gst-actor.h - ClutterActor using GStreamer
  *
  * Authored By Andre Moreira Magalhaes <andre magalhaes collabora co uk>
+ *             Lionel Landwerlin <lionel g landwerlin linux intel com>
  *
  * Copyright (C) 2012 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright (C) 2013 Intel Corporation.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -34,33 +36,36 @@
 
 #include <glib-object.h>
 #include <clutter/clutter.h>
-#include <gst/gstelement.h>
 
 #include <clutter-gst/clutter-gst-types.h>
+#include <clutter-gst/clutter-gst-player.h>
 
 G_BEGIN_DECLS
 
 #define CLUTTER_GST_TYPE_ACTOR clutter_gst_actor_get_type()
 
 #define CLUTTER_GST_ACTOR(obj) \
-  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
-  CLUTTER_GST_TYPE_ACTOR, ClutterGstActor))
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj),                                   \
+                               CLUTTER_GST_TYPE_ACTOR,                  \
+                               ClutterGstActor))
 
-#define CLUTTER_GST_ACTOR_CLASS(klass) \
-  (G_TYPE_CHECK_CLASS_CAST ((klass), \
-  CLUTTER_GST_TYPE_ACTOR, ClutterGstActorClass))
+#define CLUTTER_GST_ACTOR_CLASS(klass)                                  \
+  (G_TYPE_CHECK_CLASS_CAST ((klass),                                    \
+                            CLUTTER_GST_TYPE_ACTOR,                     \
+                            ClutterGstActorClass))
 
-#define CLUTTER_GST_IS_ACTOR(obj) \
-  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
-  CLUTTER_GST_TYPE_ACTOR))
+#define CLUTTER_GST_IS_ACTOR(obj)                       \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj),                   \
+                               CLUTTER_GST_TYPE_ACTOR))
 
-#define CLUTTER_GST_IS_ACTOR_CLASS(klass) \
-  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
-  CLUTTER_GST_TYPE_ACTOR))
+#define CLUTTER_GST_IS_ACTOR_CLASS(klass)               \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass),                    \
+                            CLUTTER_GST_TYPE_ACTOR))
 
-#define CLUTTER_GST_ACTOR_GET_CLASS(obj) \
-  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
-  CLUTTER_GST_TYPE_ACTOR, ClutterGstActorClass))
+#define CLUTTER_GST_ACTOR_GET_CLASS(obj)                                \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj),                                    \
+                              CLUTTER_GST_TYPE_ACTOR,                   \
+                              ClutterGstActorClass))
 
 typedef struct _ClutterGstActor        ClutterGstActor;
 typedef struct _ClutterGstActorClass   ClutterGstActorClass;
@@ -90,33 +95,23 @@ struct _ClutterGstActorClass
   ClutterActorClass parent_class;
 
   /*< public >*/
-  void     (* size_change) (ClutterGstActor *actor,
-                            gint             width,
-                            gint             height);
-  gboolean (* is_idle)     (ClutterGstActor *actor);
+  void (* paint_frame) (ClutterGstActor *actor, ClutterGstFrame *frame);
 
   /* 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);
+  void (* _clutter_reserved7) (void);
+  void (* _clutter_reserved8) (void);
 };
 
 GType clutter_gst_actor_get_type (void) G_GNUC_CONST;
 
-CoglHandle     clutter_gst_actor_get_cogl_texture  (ClutterGstActor *actor);
-void           clutter_gst_actor_set_cogl_texture  (ClutterGstActor *actor,
-                                                    CoglHandle       cogl_tex);
-CoglHandle     clutter_gst_actor_get_cogl_material (ClutterGstActor *actor);
-void           clutter_gst_actor_set_cogl_material (ClutterGstActor *actor,
-                                                    CoglHandle       cogl_material);
-
-gboolean       clutter_gst_actor_is_idle           (ClutterGstActor *actor);
-CoglHandle     clutter_gst_actor_get_idle_material (ClutterGstActor *actor);
-void           clutter_gst_actor_set_idle_material (ClutterGstActor *actor,
-                                                    CoglHandle       cogl_material);
+ClutterGstPlayer *clutter_gst_actor_get_player        (ClutterGstActor  *self);
+void              clutter_gst_actor_set_player        (ClutterGstActor  *self,
+                                                       ClutterGstPlayer *player);
 
 G_END_DECLS
 
diff --git a/clutter-gst/clutter-gst-camera-actor.c b/clutter-gst/clutter-gst-camera.c
similarity index 50%
rename from clutter-gst/clutter-gst-camera-actor.c
rename to clutter-gst/clutter-gst-camera.c
index 4d87657..43a95f2 100644
--- a/clutter-gst/clutter-gst-camera-actor.c
+++ b/clutter-gst/clutter-gst-camera.c
@@ -3,8 +3,8 @@
  *
  * GStreamer integration library for Clutter.
  *
- * clutter-gst-camera-actor.c - ClutterActor using GStreamer to display/manipulate a
- *                              camera stream.
+ * clutter-gst-camera.c - a GStreamer pipeline to display/manipulate a
+ *                        camera stream.
  *
  * Authored By Andre Moreira Magalhaes <andre magalhaes collabora co uk>
  *
@@ -27,10 +27,11 @@
  */
 
 /**
- * SECTION:clutter-gst-camera-actor
- * @short_description: Actor for playback of camera streams.
+ * SECTION:clutter-gst-camera
+ * @short_description: A player of camera streams.
  *
- * #ClutterGstCameraActor is a #ClutterActor that plays camera streams.
+ * #ClutterGstCamera implements the #ClutterGstPlayer interface and
+ * plays camera streams.
  */
 
 #ifdef HAVE_CONFIG_H
@@ -47,10 +48,11 @@
 #include <gudev/gudev.h>
 #endif
 
-#include "clutter-gst-camera-actor.h"
+#include "clutter-gst-camera.h"
 #include "clutter-gst-debug.h"
 #include "clutter-gst-enum-types.h"
 #include "clutter-gst-marshal.h"
+#include "clutter-gst-player.h"
 #include "clutter-gst-private.h"
 
 static const gchar *supported_media_types[] = {
@@ -58,7 +60,7 @@ static const gchar *supported_media_types[] = {
   NULL
 };
 
-struct _ClutterGstCameraActorPrivate
+struct _ClutterGstCameraPrivate
 {
   GPtrArray *camera_devices;
   ClutterGstCameraDevice *camera_device;
@@ -90,6 +92,15 @@ enum
 
 enum
 {
+  PROP_0,
+
+  PROP_IDLE,
+  PROP_PLAYING,
+  PROP_AUDIO_VOLUME
+};
+
+enum
+{
   READY_FOR_CAPTURE,
   PHOTO_SAVED,
   PHOTO_TAKEN,
@@ -97,33 +108,154 @@ enum
   LAST_SIGNAL
 };
 
-static int camera_actor_signals[LAST_SIGNAL] = { 0 };
+static int camera_signals[LAST_SIGNAL] = { 0 };
+
+static void player_iface_init (ClutterGstPlayerIface *iface);
 
-G_DEFINE_TYPE (ClutterGstCameraActor,
-               clutter_gst_camera_actor,
-               CLUTTER_GST_TYPE_ACTOR);
+G_DEFINE_TYPE_WITH_CODE (ClutterGstCamera, clutter_gst_camera, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (CLUTTER_GST_TYPE_PLAYER, player_iface_init));
 
 /*
- * ClutterGstActor implementation
+ * ClutterGstPlayer implementation
  */
 
+static GstElement *
+clutter_gst_camera_get_pipeline (ClutterGstPlayer *player)
+{
+  ClutterGstCameraPrivate *priv = CLUTTER_GST_CAMERA (player)->priv;
+
+  return priv->camerabin;
+}
+
 static gboolean
-clutter_gst_camera_actor_is_idle (ClutterGstActor *actor)
+clutter_gst_camera_get_idle (ClutterGstPlayer *player)
 {
-  ClutterGstCameraActorPrivate *priv = CLUTTER_GST_CAMERA_ACTOR (actor)->priv;
+  ClutterGstCameraPrivate *priv = CLUTTER_GST_CAMERA (player)->priv;
 
   return priv->is_idle;
 }
 
+static gdouble
+clutter_gst_camera_get_audio_volume (ClutterGstPlayer *player)
+{
+  return 0;
+}
+
+
+static void
+clutter_gst_camera_set_audio_volume (ClutterGstPlayer *player,
+                                     gdouble           volume)
+{
+}
+
+static gboolean
+clutter_gst_camera_get_playing (ClutterGstPlayer *player)
+{
+  ClutterGstCameraPrivate *priv = CLUTTER_GST_CAMERA (player)->priv;
+  GstState state, pending;
+  gboolean playing;
+
+  if (!priv->camerabin)
+    return FALSE;
+
+  gst_element_get_state (priv->camerabin, &state, &pending, 0);
+
+  if (pending)
+    playing = (pending == GST_STATE_PLAYING);
+  else
+    playing = (state == GST_STATE_PLAYING);
+
+  return playing;
+}
+
+static void
+clutter_gst_camera_set_playing (ClutterGstPlayer *player,
+                                gboolean          playing)
+{
+  ClutterGstCameraPrivate *priv = CLUTTER_GST_CAMERA (player)->priv;
+  GstState target_state;
+
+  if (!priv->camerabin)
+    return;
+
+  target_state = playing ? GST_STATE_PLAYING : GST_STATE_NULL;
+
+  gst_element_set_state (priv->camerabin, target_state);
+}
+
+static void
+player_iface_init (ClutterGstPlayerIface *iface)
+{
+  iface->get_pipeline = clutter_gst_camera_get_pipeline;
+  iface->get_idle = clutter_gst_camera_get_idle;
+
+  iface->get_audio_volume = clutter_gst_camera_get_audio_volume;
+  iface->set_audio_volume = clutter_gst_camera_set_audio_volume;
+
+  iface->get_playing = clutter_gst_camera_get_playing;
+  iface->set_playing = clutter_gst_camera_set_playing;
+}
+
 /*
  * GObject implementation
  */
 
 static void
-clutter_gst_camera_actor_dispose (GObject *object)
+clutter_gst_camera_get_property (GObject    *object,
+                                 guint       property_id,
+                                 GValue     *value,
+                                 GParamSpec *pspec)
+{
+  switch (property_id)
+    {
+    case PROP_IDLE:
+      g_value_set_boolean (value,
+                           clutter_gst_camera_get_idle (CLUTTER_GST_PLAYER (object)));
+      break;
+
+    case PROP_PLAYING:
+      g_value_set_boolean (value,
+                           clutter_gst_camera_get_playing (CLUTTER_GST_PLAYER (object)));
+      break;
+
+    case PROP_AUDIO_VOLUME:
+      g_value_set_double (value,
+                          clutter_gst_camera_get_audio_volume (CLUTTER_GST_PLAYER (object)));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+clutter_gst_camera_set_property (GObject      *object,
+                                 guint         property_id,
+                                 const GValue *value,
+                                 GParamSpec   *pspec)
+{
+  switch (property_id)
+    {
+    case PROP_PLAYING:
+      clutter_gst_camera_set_playing (CLUTTER_GST_PLAYER (object),
+                                      g_value_get_boolean (value));
+      break;
+
+    case PROP_AUDIO_VOLUME:
+      clutter_gst_camera_set_audio_volume (CLUTTER_GST_PLAYER (object),
+                                           g_value_get_double (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+clutter_gst_camera_dispose (GObject *object)
 {
-  ClutterGstCameraActor *camera_actor = CLUTTER_GST_CAMERA_ACTOR (object);
-  ClutterGstCameraActorPrivate *priv = camera_actor->priv;
+  ClutterGstCamera *self = CLUTTER_GST_CAMERA (object);
+  ClutterGstCameraPrivate *priv = self->priv;
 
   g_free (priv->photo_filename);
   priv->photo_filename = NULL;
@@ -147,102 +279,111 @@ clutter_gst_camera_actor_dispose (GObject *object)
       priv->camerabin = NULL;
     }
 
-  G_OBJECT_CLASS (clutter_gst_camera_actor_parent_class)->dispose (object);
+  G_OBJECT_CLASS (clutter_gst_camera_parent_class)->dispose (object);
 }
 
 static void
-clutter_gst_camera_actor_class_init (ClutterGstCameraActorClass *klass)
+clutter_gst_camera_class_init (ClutterGstCameraClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
   ClutterGstActorClass *gst_actor_class = CLUTTER_GST_ACTOR_CLASS (klass);
 
-  g_type_class_add_private (klass, sizeof (ClutterGstCameraActorPrivate));
+  g_type_class_add_private (klass, sizeof (ClutterGstCameraPrivate));
+
+  object_class->get_property = clutter_gst_camera_get_property;
+  object_class->set_property = clutter_gst_camera_set_property;
+  object_class->dispose = clutter_gst_camera_dispose;
 
-  object_class->dispose = clutter_gst_camera_actor_dispose;
+  g_object_class_override_property (object_class,
+                                    PROP_IDLE, "idle");
+  g_object_class_override_property (object_class,
+                                    PROP_PLAYING, "playing");
+  g_object_class_override_property (object_class,
+                                    PROP_AUDIO_VOLUME, "audio-volume");
 
-  gst_actor_class->is_idle = clutter_gst_camera_actor_is_idle;
+  /* Signals */
 
   /**
-   * ClutterGstCameraActor::ready-for-capture:
-   * @camera_actor: the actor which received the signal
-   * @ready: whether the @camera_actor is ready for a new capture
+   * ClutterGstCamera::ready-for-capture:
+   * @self: the actor which received the signal
+   * @ready: whether the @self is ready for a new capture
    *
    * The ::ready-for-capture signal is emitted whenever the value of
-   * clutter_gst_camera_actor_is_ready_for_capture changes.
+   * clutter_gst_camera_is_ready_for_capture changes.
    */
-  camera_actor_signals[READY_FOR_CAPTURE] =
+  camera_signals[READY_FOR_CAPTURE] =
     g_signal_new ("ready-for-capture",
                   G_TYPE_FROM_CLASS (object_class),
                   G_SIGNAL_RUN_LAST,
-                  G_STRUCT_OFFSET (ClutterGstCameraActorClass, ready_for_capture),
+                  G_STRUCT_OFFSET (ClutterGstCameraClass, ready_for_capture),
                   NULL, NULL,
                   g_cclosure_marshal_VOID__BOOLEAN,
                   G_TYPE_NONE, 1,
                   G_TYPE_BOOLEAN);
   /**
-   * ClutterGstCameraActor::photo-saved:
-   * @camera_actor: the actor which received the signal
+   * ClutterGstCamera::photo-saved:
+   * @self: the actor which received the signal
    *
    * The ::photo-saved signal is emitted when a photo was saved to disk.
    */
-  camera_actor_signals[PHOTO_SAVED] =
-      g_signal_new ("photo-saved",
-                    G_TYPE_FROM_CLASS (object_class),
-                    G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-                    G_STRUCT_OFFSET (ClutterGstCameraActorClass, photo_saved),
-                    NULL, NULL,
-                    g_cclosure_marshal_VOID__VOID,
-                    G_TYPE_NONE, 0);
+  camera_signals[PHOTO_SAVED] =
+    g_signal_new ("photo-saved",
+                  G_TYPE_FROM_CLASS (object_class),
+                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                  G_STRUCT_OFFSET (ClutterGstCameraClass, photo_saved),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
   /**
-   * ClutterGstCameraActor::photo-taken:
-   * @camera_actor: the actor which received the signal
+   * ClutterGstCamera::photo-taken:
+   * @self: the actor which received the signal
    * @pixbuf: the photo taken as a #GdkPixbuf
    *
    * The ::photo-taken signal is emitted when a photo was taken.
    */
-  camera_actor_signals[PHOTO_TAKEN] =
-      g_signal_new ("photo-taken",
-                    G_TYPE_FROM_CLASS (object_class),
-                    G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-                    G_STRUCT_OFFSET (ClutterGstCameraActorClass, photo_taken),
-                    NULL, NULL,
-                    g_cclosure_marshal_VOID__OBJECT,
-                    G_TYPE_NONE, 1, GDK_TYPE_PIXBUF);
+  camera_signals[PHOTO_TAKEN] =
+    g_signal_new ("photo-taken",
+                  G_TYPE_FROM_CLASS (object_class),
+                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                  G_STRUCT_OFFSET (ClutterGstCameraClass, photo_taken),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__OBJECT,
+                  G_TYPE_NONE, 1, GDK_TYPE_PIXBUF);
   /**
-   * ClutterGstCameraActor::video-saved:
-   * @camera_actor: the actor which received the signal
+   * ClutterGstCamera::video-saved:
+   * @self: the actor which received the signal
    *
    * The ::video-saved signal is emitted when a video was saved to disk.
    */
-  camera_actor_signals[VIDEO_SAVED] =
-      g_signal_new ("video-saved",
-                    G_TYPE_FROM_CLASS (object_class),
-                    G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-                    G_STRUCT_OFFSET (ClutterGstCameraActorClass, video_saved),
-                    NULL, NULL,
-                    g_cclosure_marshal_VOID__VOID,
-                    G_TYPE_NONE, 0);
+  camera_signals[VIDEO_SAVED] =
+    g_signal_new ("video-saved",
+                  G_TYPE_FROM_CLASS (object_class),
+                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                  G_STRUCT_OFFSET (ClutterGstCameraClass, video_saved),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
 }
 
 static void
 notify_ready_for_capture (GObject               *object,
                           GParamSpec            *pspec,
-                          ClutterGstCameraActor *camera_actor)
+                          ClutterGstCamera *self)
 {
-  ClutterGstCameraActorPrivate *priv = camera_actor->priv;
+  ClutterGstCameraPrivate *priv = self->priv;
   gboolean ready_for_capture;
 
   g_object_get (priv->camera_source, "ready-for-capture",
                 &ready_for_capture, NULL);
-  g_signal_emit (camera_actor, camera_actor_signals[READY_FOR_CAPTURE],
+  g_signal_emit (self, camera_signals[READY_FOR_CAPTURE],
                  0, ready_for_capture);
 }
 
 static void
-parse_photo_data (ClutterGstCameraActor *camera_actor,
-                  GstSample             *sample)
+parse_photo_data (ClutterGstCamera *self,
+                  GstSample        *sample)
 {
-  ClutterGstCameraActorPrivate *priv = camera_actor->priv;
+  ClutterGstCameraPrivate *priv = self->priv;
   GstBuffer *buffer;
   GstCaps *caps;
   const GstStructure *structure;
@@ -270,106 +411,106 @@ parse_photo_data (ClutterGstCameraActor *camera_actor,
                                      data ? (GdkPixbufDestroyNotify) g_free : NULL, NULL);
 
   g_object_set (G_OBJECT (priv->camerabin), "post-previews", FALSE, NULL);
-  g_signal_emit (camera_actor, camera_actor_signals[PHOTO_TAKEN], 0, pixbuf);
+  g_signal_emit (self, camera_signals[PHOTO_TAKEN], 0, pixbuf);
   g_object_unref (pixbuf);
 }
 
 static void
-bus_message_cb (GstBus                *bus,
-                GstMessage            *message,
-                ClutterGstCameraActor *camera_actor)
+bus_message_cb (GstBus           *bus,
+                GstMessage       *message,
+                ClutterGstCamera *self)
 {
-  ClutterGstCameraActorPrivate *priv = camera_actor->priv;
+  ClutterGstCameraPrivate *priv = self->priv;
 
   switch (GST_MESSAGE_TYPE (message))
     {
-      case GST_MESSAGE_ERROR:
-        {
-          GError *err = NULL;
-          gchar *debug = NULL;
-
-          gst_message_parse_error (message, &err, &debug);
-          if (err && err->message)
-            g_warning ("%s", err->message);
-          else
-            g_warning ("Unparsable GST_MESSAGE_ERROR message.");
-
-          if (err)
-            g_error_free (err);
-          g_free (debug);
-
-          priv->is_idle = TRUE;
-          g_object_notify (G_OBJECT (camera_actor), "idle");
-          break;
-        }
-
-      case GST_MESSAGE_STATE_CHANGED:
-        {
-          if (strcmp (GST_MESSAGE_SRC_NAME (message), "camerabin") == 0)
-            {
-              GstState new;
-
-              gst_message_parse_state_changed (message, NULL, &new, NULL);
-              if (new == GST_STATE_PLAYING)
-                priv->is_idle = FALSE;
-              else
-                priv->is_idle = TRUE;
-              g_object_notify (G_OBJECT (camera_actor), "idle");
-            }
-          break;
-        }
-
-      case GST_MESSAGE_ELEMENT:
-        {
-          const GstStructure *structure;
-          const GValue *image;
-
-          if (strcmp (GST_MESSAGE_SRC_NAME (message), "camera_source") == 0)
-            {
-              structure = gst_message_get_structure (message);
-              if (strcmp (gst_structure_get_name (structure), "preview-image") == 0)
-                {
-                  if (gst_structure_has_field_typed (structure, "sample", GST_TYPE_SAMPLE))
-                    {
-                      image = gst_structure_get_value (structure, "sample");
-                      if (image)
-                        {
-                          GstSample *sample;
-
-                          sample = gst_value_get_sample (image);
-                          parse_photo_data (camera_actor, sample);
-                        }
-                      else
-                        g_warning ("Could not get buffer from bus message");
-                   }
-                }
-            }
-          else if (strcmp (GST_MESSAGE_SRC_NAME (message), "camerabin") == 0)
-            {
-              structure = gst_message_get_structure (message);
-              if (strcmp (gst_structure_get_name (structure), "image-done") == 0)
-                {
-                  const gchar *filename = gst_structure_get_string (structure, "filename");
-                  if (priv->photo_filename != NULL && filename != NULL &&
-                      (strcmp (priv->photo_filename, filename) == 0))
-                    g_signal_emit (camera_actor, camera_actor_signals[PHOTO_SAVED], 0);
-                }
-              else if (strcmp (gst_structure_get_name (structure), "video-done") == 0)
-                {
-                  g_signal_emit (camera_actor, camera_actor_signals[VIDEO_SAVED], 0);
-                  priv->is_recording = FALSE;
-                }
-            }
-          break;
-        }
+    case GST_MESSAGE_ERROR:
+      {
+        GError *err = NULL;
+        gchar *debug = NULL;
+
+        gst_message_parse_error (message, &err, &debug);
+        if (err && err->message)
+          g_warning ("%s", err->message);
+        else
+          g_warning ("Unparsable GST_MESSAGE_ERROR message.");
+
+        if (err)
+          g_error_free (err);
+        g_free (debug);
+
+        priv->is_idle = TRUE;
+        g_object_notify (G_OBJECT (self), "idle");
+        break;
+      }
+
+    case GST_MESSAGE_STATE_CHANGED:
+      {
+        if (strcmp (GST_MESSAGE_SRC_NAME (message), "camerabin") == 0)
+          {
+            GstState new;
+
+            gst_message_parse_state_changed (message, NULL, &new, NULL);
+            if (new == GST_STATE_PLAYING)
+              priv->is_idle = FALSE;
+            else
+              priv->is_idle = TRUE;
+            g_object_notify (G_OBJECT (self), "idle");
+          }
+        break;
+      }
+
+    case GST_MESSAGE_ELEMENT:
+      {
+        const GstStructure *structure;
+        const GValue *image;
+
+        if (strcmp (GST_MESSAGE_SRC_NAME (message), "camera_source") == 0)
+          {
+            structure = gst_message_get_structure (message);
+            if (strcmp (gst_structure_get_name (structure), "preview-image") == 0)
+              {
+                if (gst_structure_has_field_typed (structure, "sample", GST_TYPE_SAMPLE))
+                  {
+                    image = gst_structure_get_value (structure, "sample");
+                    if (image)
+                      {
+                        GstSample *sample;
+
+                        sample = gst_value_get_sample (image);
+                        parse_photo_data (self, sample);
+                      }
+                    else
+                      g_warning ("Could not get buffer from bus message");
+                  }
+              }
+          }
+        else if (strcmp (GST_MESSAGE_SRC_NAME (message), "camerabin") == 0)
+          {
+            structure = gst_message_get_structure (message);
+            if (strcmp (gst_structure_get_name (structure), "image-done") == 0)
+              {
+                const gchar *filename = gst_structure_get_string (structure, "filename");
+                if (priv->photo_filename != NULL && filename != NULL &&
+                    (strcmp (priv->photo_filename, filename) == 0))
+                  g_signal_emit (self, camera_signals[PHOTO_SAVED], 0);
+              }
+            else if (strcmp (gst_structure_get_name (structure), "video-done") == 0)
+              {
+                g_signal_emit (self, camera_signals[VIDEO_SAVED], 0);
+                priv->is_recording = FALSE;
+              }
+          }
+        break;
+      }
 
     default:
-     break;
-  }
+      break;
+    }
 }
 
 static void
-set_video_profile (ClutterGstCameraActor *camera_actor)
+set_video_profile (ClutterGstCamera *self)
 {
   GstEncodingContainerProfile *prof;
   GstEncodingAudioProfile *audio_prof;
@@ -378,8 +519,8 @@ set_video_profile (ClutterGstCameraActor *camera_actor)
 
   caps = gst_caps_from_string ("application/ogg");
   prof = gst_encoding_container_profile_new ("Ogg audio/video",
-     "Standard Ogg/Theora/Vorbis",
-     caps, NULL);
+                                             "Standard Ogg/Theora/Vorbis",
+                                             caps, NULL);
   gst_caps_unref (caps);
 
   caps = gst_caps_from_string ("video/x-theora");
@@ -392,16 +533,16 @@ set_video_profile (ClutterGstCameraActor *camera_actor)
   gst_encoding_container_profile_add_profile (prof, (GstEncodingProfile*) audio_prof);
   gst_caps_unref (caps);
 
-  clutter_gst_camera_actor_set_video_profile (camera_actor,
-                                              (GstEncodingProfile *) prof);
+  clutter_gst_camera_set_video_profile (self,
+                                        (GstEncodingProfile *) prof);
 
   gst_encoding_profile_unref (prof);
 }
 
 static GstElement *
-setup_video_filter_bin (ClutterGstCameraActor *camera_actor)
+setup_video_filter_bin (ClutterGstCamera *self)
 {
-  ClutterGstCameraActorPrivate *priv = camera_actor->priv;
+  ClutterGstCameraPrivate *priv = self->priv;
   GstElement *bin;
   GstPad *pad;
 
@@ -438,7 +579,7 @@ setup_video_filter_bin (ClutterGstCameraActor *camera_actor)
   gst_object_unref (pad);
   return bin;
 
-error:
+ error:
   if (priv->identity)
     gst_object_unref (priv->identity);
   if (priv->valve)
@@ -453,14 +594,14 @@ error:
     gst_object_unref (priv->post_colorspace);
   return NULL;
 
-error_not_linked:
+ error_not_linked:
   gst_object_unref (bin);
   return NULL;
 }
 
 static GstCaps *
-create_caps_for_formats (gint          width,
-                         gint          height)
+create_caps_for_formats (gint width,
+                         gint height)
 {
   GstCaps *ret = NULL;
   guint length;
@@ -487,9 +628,9 @@ static void
 device_capture_resolution_changed (ClutterGstCameraDevice *camera_device,
                                    gint                    width,
                                    gint                    height,
-                                   ClutterGstCameraActor  *camera_actor)
+                                   ClutterGstCamera       *self)
 {
-  ClutterGstCameraActorPrivate *priv = camera_actor->priv;
+  ClutterGstCameraPrivate *priv = self->priv;
   GstCaps *caps;
 
   if (priv->camera_device != camera_device)
@@ -503,45 +644,45 @@ device_capture_resolution_changed (ClutterGstCameraDevice *camera_device,
 }
 
 static void
-set_device_resolutions (ClutterGstCameraActor  *camera_actor,
-                        ClutterGstCameraDevice *camera_device)
+set_device_resolutions (ClutterGstCamera       *self,
+                        ClutterGstCameraDevice *device)
 
 {
   gint width;
   gint height;
 
-  clutter_gst_camera_device_get_capture_resolution (camera_device, &width, &height);
-  device_capture_resolution_changed (camera_device, width, height, camera_actor);
+  clutter_gst_camera_device_get_capture_resolution (device, &width, &height);
+  device_capture_resolution_changed (device, width, height, self);
 }
 
 static void
-add_device (ClutterGstCameraActor *camera_actor,
-            GstElementFactory     *element_factory,
-            const gchar           *device_node,
-            const gchar           *device_name)
+add_device (ClutterGstCamera  *self,
+            GstElementFactory *element_factory,
+            const gchar       *device_node,
+            const gchar       *device_name)
 {
-  ClutterGstCameraActorPrivate *priv = camera_actor->priv;
-  ClutterGstCameraDevice *camera_device;
+  ClutterGstCameraPrivate *priv = self->priv;
+  ClutterGstCameraDevice *device;
 
   if (!priv->camera_devices)
     priv->camera_devices =
-        g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
-
-  camera_device = g_object_new (CLUTTER_GST_TYPE_CAMERA_DEVICE,
-                                "element-factory", element_factory,
-                                "node", device_node,
-                                "name", device_name,
-                                NULL);
-  g_signal_connect (camera_device, "capture-resolution-changed",
+      g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
+
+  device = g_object_new (CLUTTER_GST_TYPE_CAMERA_DEVICE,
+                         "element-factory", element_factory,
+                         "node", device_node,
+                         "name", device_name,
+                         NULL);
+  g_signal_connect (device, "capture-resolution-changed",
                     G_CALLBACK (device_capture_resolution_changed),
-                    camera_actor);
-  g_ptr_array_add (priv->camera_devices, camera_device);
+                    self);
+  g_ptr_array_add (priv->camera_devices, device);
 }
 
 static gboolean
-probe_camera_devices (ClutterGstCameraActor *camera_actor)
+probe_camera_devices (ClutterGstCamera *self)
 {
-  ClutterGstCameraActorPrivate *priv = camera_actor->priv;
+  ClutterGstCameraPrivate *priv = self->priv;
   GstElement *videosrc;
   GstElementFactory *element_factory;
   GParamSpec *pspec;
@@ -562,7 +703,7 @@ probe_camera_devices (ClutterGstCameraActor *camera_actor)
     }
 
   pspec = g_object_class_find_property (
-    G_OBJECT_GET_CLASS (G_OBJECT (videosrc)), "device");
+                                        G_OBJECT_GET_CLASS (G_OBJECT (videosrc)), "device");
   if (!G_IS_PARAM_SPEC_STRING (pspec))
     {
       g_warning ("Unable to get available camera devices, "
@@ -592,7 +733,7 @@ probe_camera_devices (ClutterGstCameraActor *camera_actor)
           device_node = (gchar *) g_udev_device_get_device_file (udevice);
           device_name = (gchar *) g_udev_device_get_property (udevice, "ID_V4L_PRODUCT");
 
-          add_device (camera_actor, element_factory, device_node, device_name);
+          add_device (self, element_factory, device_node, device_name);
         }
 
       g_object_unref (udevice);
@@ -604,21 +745,21 @@ probe_camera_devices (ClutterGstCameraActor *camera_actor)
    * device as only known device */
   g_object_get (videosrc, "device", &device_node, NULL);
   g_object_get (videosrc, "device-name", &device_name, NULL);
-  add_device (camera_actor, element_factory, device_node, device_name);
+  add_device (self, element_factory, device_node, device_name);
 
   g_free (device_node);
   g_free (device_name);
 #endif
 
-out:
+ out:
   gst_object_unref (videosrc);
   return (priv->camera_devices != NULL);
 }
 
 static gboolean
-setup_camera_source (ClutterGstCameraActor *camera_actor)
+setup_camera_source (ClutterGstCamera *self)
 {
-  ClutterGstCameraActorPrivate *priv = camera_actor->priv;
+  ClutterGstCameraPrivate *priv = self->priv;
   GstElement *camera_source;
   GstElement *old_camera_source = NULL;
 
@@ -637,7 +778,7 @@ setup_camera_source (ClutterGstCameraActor *camera_actor)
 
   g_signal_connect (camera_source, "notify::ready-for-capture",
                     G_CALLBACK (notify_ready_for_capture),
-                    camera_actor);
+                    self);
 
   if (priv->video_filter_bin)
     {
@@ -650,12 +791,12 @@ setup_camera_source (ClutterGstCameraActor *camera_actor)
 }
 
 static gboolean
-setup_pipeline (ClutterGstCameraActor *camera_actor)
+setup_pipeline (ClutterGstCamera *self)
 {
-  ClutterGstCameraActorPrivate *priv = camera_actor->priv;
+  ClutterGstCameraPrivate *priv = self->priv;
   GstElement *camera_sink;
 
-  if (!probe_camera_devices (camera_actor))
+  if (!probe_camera_devices (self))
     {
       g_critical ("Unable to find any suitable capture device");
       return FALSE;
@@ -668,11 +809,11 @@ setup_pipeline (ClutterGstCameraActor *camera_actor)
       return FALSE;
     }
 
-  priv->video_filter_bin = setup_video_filter_bin (camera_actor);
+  priv->video_filter_bin = setup_video_filter_bin (self);
   if (!priv->video_filter_bin)
     g_warning ("Unable to setup video filter, some features will be disabled");
 
-  if (G_UNLIKELY (!setup_camera_source (camera_actor)))
+  if (G_UNLIKELY (!setup_camera_source (self)))
     {
       g_critical ("Unable to create camera source element");
       gst_object_unref (priv->camerabin);
@@ -680,8 +821,8 @@ setup_pipeline (ClutterGstCameraActor *camera_actor)
       return FALSE;
     }
 
-  if (!clutter_gst_camera_actor_set_camera_device (camera_actor,
-           g_ptr_array_index (priv->camera_devices, 0)))
+  if (!clutter_gst_camera_set_camera_device (self,
+                                             g_ptr_array_index (priv->camera_devices, 0)))
     {
       g_critical ("Unable to select capture device");
       gst_object_unref (priv->camerabin);
@@ -689,36 +830,33 @@ setup_pipeline (ClutterGstCameraActor *camera_actor)
       return FALSE;
     }
 
-  camera_sink = gst_element_factory_make ("cluttersink", NULL);
-  g_object_set (camera_sink,
-                "actor", CLUTTER_GST_ACTOR (camera_actor),
-                NULL);
+  camera_sink = gst_element_factory_make ("coglsink", NULL);
   g_object_set (priv->camerabin,
                 "viewfinder-sink", camera_sink,
                 NULL);
 
-  set_video_profile (camera_actor);
+  set_video_profile (self);
 
   priv->bus = gst_element_get_bus (priv->camerabin);
   gst_bus_add_signal_watch (priv->bus);
 
   g_signal_connect (G_OBJECT (priv->bus), "message",
-                    G_CALLBACK (bus_message_cb), camera_actor);
+                    G_CALLBACK (bus_message_cb), self);
 
   return TRUE;
 }
 
 static void
-clutter_gst_camera_actor_init (ClutterGstCameraActor *camera_actor)
+clutter_gst_camera_init (ClutterGstCamera *self)
 {
-  ClutterGstCameraActorPrivate *priv;
+  ClutterGstCameraPrivate *priv;
 
-  camera_actor->priv = priv =
-    G_TYPE_INSTANCE_GET_PRIVATE (camera_actor,
-                                 CLUTTER_GST_TYPE_CAMERA_ACTOR,
-                                 ClutterGstCameraActorPrivate);
+  self->priv = priv =
+    G_TYPE_INSTANCE_GET_PRIVATE (self,
+                                 CLUTTER_GST_TYPE_CAMERA,
+                                 ClutterGstCameraPrivate);
 
-  if (!setup_pipeline (camera_actor))
+  if (!setup_pipeline (self))
     {
       g_warning ("Failed to initiate suitable elements for pipeline.");
       return;
@@ -732,7 +870,7 @@ clutter_gst_camera_actor_init (ClutterGstCameraActor *camera_actor)
  */
 
 /**
- * clutter_gst_camera_actor_new:
+ * clutter_gst_camera_new:
  *
  * Create a camera actor.
  *
@@ -743,50 +881,50 @@ clutter_gst_camera_actor_init (ClutterGstCameraActor *camera_actor)
  *
  * Return value: the newly created camera actor
  */
-ClutterActor*
-clutter_gst_camera_actor_new (void)
+ClutterGstCamera *
+clutter_gst_camera_new (void)
 {
-  return g_object_new (CLUTTER_GST_TYPE_CAMERA_ACTOR,
+  return g_object_new (CLUTTER_GST_TYPE_CAMERA,
                        NULL);
 }
 
-/**
- * clutter_gst_camera_actor_get_pipeline:
- * @camera_actor: a #ClutterGstCameraActor
- *
- * Retrieve the #GstPipeline used by the @camera_actor, for direct use with
- * GStreamer API.
- *
- * Return value: (transfer none): the pipeline element used by the camera actor
- */
-GstElement *
-clutter_gst_camera_actor_get_pipeline (ClutterGstCameraActor *camera_actor)
-{
-  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), NULL);
-
-  return camera_actor->priv->camerabin;
-}
-
-/**
- * clutter_gst_camera_actor_get_camerabin:
- * @camera_actor: a #ClutterGstCameraActor
- *
- * Retrieve the camerabin element used by the @camera_actor, for direct use with
- * GStreamer API.
- *
- * Return value: (transfer none): the pipeline element used by the camera actor
- */
-GstElement *
-clutter_gst_camera_actor_get_camerabin (ClutterGstCameraActor *camera_actor)
-{
-  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), NULL);
-
-  return camera_actor->priv->camerabin;
-}
+/* /\** */
+/*  * clutter_gst_camera_get_pipeline: */
+/*  * @self: a #ClutterGstCamera */
+/*  * */
+/*  * Retrieve the #GstPipeline used by the @self, for direct use with */
+/*  * GStreamer API. */
+/*  * */
+/*  * Return value: (transfer none): the pipeline element used by the camera actor */
+/*  *\/ */
+/* GstElement * */
+/* clutter_gst_camera_get_pipeline (ClutterGstCamera *self) */
+/* { */
+/*   g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), NULL); */
+
+/*   return self->priv->camerabin; */
+/* } */
+
+/* /\** */
+/*  * clutter_gst_camera_get_camerabin: */
+/*  * @self: a #ClutterGstCamera */
+/*  * */
+/*  * Retrieve the camerabin element used by the @self, for direct use with */
+/*  * GStreamer API. */
+/*  * */
+/*  * Return value: (transfer none): the pipeline element used by the camera actor */
+/*  *\/ */
+/* GstElement * */
+/* clutter_gst_camera_get_camerabin (ClutterGstCamera *self) */
+/* { */
+/*   g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), NULL); */
+
+/*   return self->priv->camerabin; */
+/* } */
 
 /**
- * clutter_gst_camera_actor_get_camera_devices:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_get_camera_devices:
+ * @self: a #ClutterGstCamera
  *
  * Retrieve an array of supported camera devices.
  *
@@ -794,66 +932,66 @@ clutter_gst_camera_actor_get_camerabin (ClutterGstCameraActor *camera_actor)
  *                                the supported camera devices
  */
 const GPtrArray *
-clutter_gst_camera_actor_get_camera_devices (ClutterGstCameraActor *camera_actor)
+clutter_gst_camera_get_camera_devices (ClutterGstCamera *self)
 {
-  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), NULL);
+  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), NULL);
 
-  return camera_actor->priv->camera_devices;
+  return self->priv->camera_devices;
 }
 
 /**
- * clutter_gst_camera_actor_get_camera_device:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_get_camera_device:
+ * @self: a #ClutterGstCamera
  *
  * Retrieve the current selected camera device.
  *
  * Return value: (transfer none): The currently selected camera device
  */
 ClutterGstCameraDevice *
-clutter_gst_camera_actor_get_camera_device (ClutterGstCameraActor *camera_actor)
+clutter_gst_camera_get_camera_device (ClutterGstCamera *self)
 {
-  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), NULL);
+  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), NULL);
 
-  return camera_actor->priv->camera_device;
+  return self->priv->camera_device;
 }
 
 /**
- * clutter_gst_camera_actor_set_camera_device:
- * @camera_actor: a #ClutterGstCameraActor
- * @camera_device: a #ClutterGstCameraDevice
+ * clutter_gst_camera_set_camera_device:
+ * @self: a #ClutterGstCamera
+ * @device: a #ClutterGstCameraDevice
  *
  * Set the new active camera device.
  *
  * Return value: %TRUE on success, %FALSE otherwise
  */
 gboolean
-clutter_gst_camera_actor_set_camera_device (ClutterGstCameraActor  *camera_actor,
-                                            ClutterGstCameraDevice *camera_device)
+clutter_gst_camera_set_camera_device (ClutterGstCamera       *self,
+                                      ClutterGstCameraDevice *device)
 {
-  ClutterGstCameraActorPrivate *priv;
+  ClutterGstCameraPrivate *priv;
   GstElementFactory *element_factory;
   GstElement *src;
   gchar *node;
   gboolean was_playing = FALSE;
 
-  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
-  g_return_val_if_fail (camera_device != NULL, FALSE);
+  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
+  g_return_val_if_fail (device != NULL, FALSE);
 
-  priv = camera_actor->priv;
+  priv = self->priv;
 
   if (!priv->camerabin)
     return FALSE;
 
   if (priv->is_recording)
-    clutter_gst_camera_actor_stop_video_recording (camera_actor);
+    clutter_gst_camera_stop_video_recording (self);
 
-  if (clutter_gst_camera_actor_is_playing (camera_actor))
+  if (clutter_gst_camera_is_playing (self))
     {
       gst_element_set_state (priv->camerabin, GST_STATE_NULL);
       was_playing = TRUE;
     }
 
-  g_object_get (camera_device,
+  g_object_get (device,
                 "element-factory", &element_factory,
                 "node", &node,
                 NULL);
@@ -875,13 +1013,13 @@ clutter_gst_camera_actor_set_camera_device (ClutterGstCameraActor  *camera_actor
 
   gst_object_unref (element_factory);
 
-  priv->camera_device = camera_device;
+  priv->camera_device = device;
 
   g_object_set (G_OBJECT (src), "device", node, NULL);
   g_free (node);
   g_object_set (G_OBJECT (priv->camera_source), "video-source", src, NULL);
 
-  set_device_resolutions (camera_actor, camera_device);
+  set_device_resolutions (self, device);
 
   if (was_playing)
     gst_element_set_state (priv->camerabin, GST_STATE_PLAYING);
@@ -890,24 +1028,24 @@ clutter_gst_camera_actor_set_camera_device (ClutterGstCameraActor  *camera_actor
 }
 
 /**
- * clutter_gst_camera_actor_supports_gamma_correction:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_supports_gamma_correction:
+ * @self: a #ClutterGstCamera
  *
- * Check whether the @camera_actor supports gamma correction.
+ * Check whether the @self supports gamma correction.
  *
- * Return value: %TRUE if @camera_actor supports gamma correction, %FALSE otherwise
+ * Return value: %TRUE if @self supports gamma correction, %FALSE otherwise
  */
 gboolean
-clutter_gst_camera_actor_supports_gamma_correction (ClutterGstCameraActor *camera_actor)
+clutter_gst_camera_supports_gamma_correction (ClutterGstCamera *self)
 {
-  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
 
-  return (camera_actor->priv->gamma != NULL);
+  return (self->priv->gamma != NULL);
 }
 
 /**
- * clutter_gst_camera_actor_get_gamma_range:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_get_gamma_range:
+ * @self: a #ClutterGstCamera
  * @min_value: Pointer to store the minimum gamma value, or %NULL
  * @max_value: Pointer to store the maximum gamma value, or %NULL
  * @default_value: Pointer to store the default gamma value, or %NULL
@@ -915,29 +1053,29 @@ clutter_gst_camera_actor_supports_gamma_correction (ClutterGstCameraActor *camer
  * Retrieve the minimum, maximum and default gamma values.
  *
  * This method will return FALSE if gamma correction is not
- * supported on @camera_actor.
- * See clutter_gst_camera_actor_supports_gamma_correction().
+ * supported on @self.
+ * See clutter_gst_camera_supports_gamma_correction().
  *
  * Return value: %TRUE if successful, %FALSE otherwise
  */
 gboolean
-clutter_gst_camera_actor_get_gamma_range (ClutterGstCameraActor *camera_actor,
-                                          gdouble               *min_value,
-                                          gdouble               *max_value,
-                                          gdouble               *default_value)
+clutter_gst_camera_get_gamma_range (ClutterGstCamera *self,
+                                    gdouble          *min_value,
+                                    gdouble          *max_value,
+                                    gdouble          *default_value)
 {
-  ClutterGstCameraActorPrivate *priv;
+  ClutterGstCameraPrivate *priv;
   GParamSpec *pspec;
 
-  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
 
-  priv = camera_actor->priv;
+  priv = self->priv;
 
   if (!priv->gamma)
     return FALSE;
 
   pspec = g_object_class_find_property (
-    G_OBJECT_GET_CLASS (G_OBJECT (priv->gamma)), "gamma");
+                                        G_OBJECT_GET_CLASS (G_OBJECT (priv->gamma)), "gamma");
   /* shouldn't happen */
   g_return_val_if_fail (G_IS_PARAM_SPEC_DOUBLE (pspec), FALSE);
 
@@ -951,28 +1089,28 @@ clutter_gst_camera_actor_get_gamma_range (ClutterGstCameraActor *camera_actor,
 }
 
 /**
- * clutter_gst_camera_actor_get_gamma:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_get_gamma:
+ * @self: a #ClutterGstCamera
  * @cur_value: Pointer to store the current gamma value
  *
  * Retrieve the current gamma value.
  *
  * This method will return FALSE if gamma correction is not
- * supported on @camera_actor.
- * See clutter_gst_camera_actor_supports_gamma_correction().
+ * supported on @self.
+ * See clutter_gst_camera_supports_gamma_correction().
  *
  * Return value: %TRUE if successful, %FALSE otherwise
  */
 gboolean
-clutter_gst_camera_actor_get_gamma (ClutterGstCameraActor *camera_actor,
-                                    gdouble               *cur_value)
+clutter_gst_camera_get_gamma (ClutterGstCamera *self,
+                              gdouble          *cur_value)
 {
-  ClutterGstCameraActorPrivate *priv;
+  ClutterGstCameraPrivate *priv;
 
-  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
   g_return_val_if_fail (cur_value != NULL, FALSE);
 
-  priv = camera_actor->priv;
+  priv = self->priv;
 
   if (!priv->gamma)
     return FALSE;
@@ -982,29 +1120,29 @@ clutter_gst_camera_actor_get_gamma (ClutterGstCameraActor *camera_actor,
 }
 
 /**
- * clutter_gst_camera_actor_set_gamma:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_set_gamma:
+ * @self: a #ClutterGstCamera
  * @value: The value to set
  *
  * Set the gamma value.
  * Allowed values can be retrieved with
- * clutter_gst_camera_actor_get_gamma_range().
+ * clutter_gst_camera_get_gamma_range().
  *
  * This method will return FALSE if gamma correction is not
- * supported on @camera_actor.
- * See clutter_gst_camera_actor_supports_gamma_correction().
+ * supported on @self.
+ * See clutter_gst_camera_supports_gamma_correction().
  *
  * Return value: %TRUE if successful, %FALSE otherwise
  */
 gboolean
-clutter_gst_camera_actor_set_gamma (ClutterGstCameraActor *camera_actor,
-                                    gdouble                value)
+clutter_gst_camera_set_gamma (ClutterGstCamera *self,
+                              gdouble           value)
 {
-  ClutterGstCameraActorPrivate *priv;
+  ClutterGstCameraPrivate *priv;
 
-  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
 
-  priv = camera_actor->priv;
+  priv = self->priv;
 
   if (!priv->gamma)
     return FALSE;
@@ -1014,24 +1152,24 @@ clutter_gst_camera_actor_set_gamma (ClutterGstCameraActor *camera_actor,
 }
 
 /**
- * clutter_gst_camera_actor_supports_color_balance:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_supports_color_balance:
+ * @self: a #ClutterGstCamera
  *
- * Check whether the @camera_actor supports color balance.
+ * Check whether the @self supports color balance.
  *
- * Return value: %TRUE if @camera_actor supports color balance, %FALSE otherwise
+ * Return value: %TRUE if @self supports color balance, %FALSE otherwise
  */
 gboolean
-clutter_gst_camera_actor_supports_color_balance (ClutterGstCameraActor *camera_actor)
+clutter_gst_camera_supports_color_balance (ClutterGstCamera *self)
 {
-  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
 
-  return (camera_actor->priv->color_balance != NULL);
+  return (self->priv->color_balance != NULL);
 }
 
 /**
- * clutter_gst_camera_actor_get_color_balance_property_range:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_get_color_balance_property_range:
+ * @self: a #ClutterGstCamera
  * @property: Property name
  * @min_value: Pointer to store the minimum value of @property, or %NULL
  * @max_value: Pointer to store the maximum value of @property, or %NULL
@@ -1040,30 +1178,30 @@ clutter_gst_camera_actor_supports_color_balance (ClutterGstCameraActor *camera_a
  * Retrieve the minimum, maximum and default values for the color balance property @property,
  *
  * This method will return FALSE if @property does not exist or color balance is not
- * supported on @camera_actor.
- * See clutter_gst_camera_actor_supports_color_balance().
+ * supported on @self.
+ * See clutter_gst_camera_supports_color_balance().
  *
  * Return value: %TRUE if successful, %FALSE otherwise
  */
 gboolean
-clutter_gst_camera_actor_get_color_balance_property_range (ClutterGstCameraActor *camera_actor,
-                                                           const gchar           *property,
-                                                           gdouble               *min_value,
-                                                           gdouble               *max_value,
-                                                           gdouble               *default_value)
+clutter_gst_camera_get_color_balance_property_range (ClutterGstCamera *self,
+                                                     const gchar      *property,
+                                                     gdouble          *min_value,
+                                                     gdouble          *max_value,
+                                                     gdouble          *default_value)
 {
-  ClutterGstCameraActorPrivate *priv;
+  ClutterGstCameraPrivate *priv;
   GParamSpec *pspec;
 
-  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
 
-  priv = camera_actor->priv;
+  priv = self->priv;
 
   if (!priv->color_balance)
     return FALSE;
 
   pspec = g_object_class_find_property (
-    G_OBJECT_GET_CLASS (G_OBJECT (priv->color_balance)), property);
+                                        G_OBJECT_GET_CLASS (G_OBJECT (priv->color_balance)), property);
   g_return_val_if_fail (G_IS_PARAM_SPEC_DOUBLE (pspec), FALSE);
 
   if (min_value)
@@ -1076,37 +1214,37 @@ clutter_gst_camera_actor_get_color_balance_property_range (ClutterGstCameraActor
 }
 
 /**
- * clutter_gst_camera_actor_get_color_balance_property:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_get_color_balance_property:
+ * @self: a #ClutterGstCamera
  * @property: Property name
  * @cur_value: Pointer to store the current value of @property
  *
  * Retrieve the current value for the color balance property @property,
  *
  * This method will return FALSE if @property does not exist or color balance is not
- * supported on @camera_actor.
- * See clutter_gst_camera_actor_supports_color_balance().
+ * supported on @self.
+ * See clutter_gst_camera_supports_color_balance().
  *
  * Return value: %TRUE if successful, %FALSE otherwise
  */
 gboolean
-clutter_gst_camera_actor_get_color_balance_property (ClutterGstCameraActor *camera_actor,
-                                                     const gchar           *property,
-                                                     gdouble               *cur_value)
+clutter_gst_camera_get_color_balance_property (ClutterGstCamera *self,
+                                               const gchar      *property,
+                                               gdouble          *cur_value)
 {
-  ClutterGstCameraActorPrivate *priv;
+  ClutterGstCameraPrivate *priv;
   GParamSpec *pspec;
 
-  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
   g_return_val_if_fail (cur_value != NULL, FALSE);
 
-  priv = camera_actor->priv;
+  priv = self->priv;
 
   if (!priv->color_balance)
     return FALSE;
 
   pspec = g_object_class_find_property (
-    G_OBJECT_GET_CLASS (G_OBJECT (priv->color_balance)), property);
+                                        G_OBJECT_GET_CLASS (G_OBJECT (priv->color_balance)), property);
   g_return_val_if_fail (G_IS_PARAM_SPEC_DOUBLE (pspec), FALSE);
 
   g_object_get (G_OBJECT (priv->color_balance), property, cur_value, NULL);
@@ -1114,38 +1252,38 @@ clutter_gst_camera_actor_get_color_balance_property (ClutterGstCameraActor *came
 }
 
 /**
- * clutter_gst_camera_actor_set_color_balance_property:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_set_color_balance_property:
+ * @self: a #ClutterGstCamera
  * @property: Property name
  * @value: The value to set
  *
  * Set the value for the color balance property @property to @value.
  * Allowed values can be retrieved with
- * clutter_gst_camera_actor_get_color_balance_property_range().
+ * clutter_gst_camera_get_color_balance_property_range().
  *
  * This method will return FALSE if @property does not exist or color balance is not
- * supported on @camera_actor.
- * See clutter_gst_camera_actor_supports_color_balance().
+ * supported on @self.
+ * See clutter_gst_camera_supports_color_balance().
  *
  * Return value: %TRUE if successful, %FALSE otherwise
  */
 gboolean
-clutter_gst_camera_actor_set_color_balance_property (ClutterGstCameraActor *camera_actor,
-                                                     const gchar           *property,
-                                                     gdouble                value)
+clutter_gst_camera_set_color_balance_property (ClutterGstCamera *self,
+                                               const gchar      *property,
+                                               gdouble           value)
 {
-  ClutterGstCameraActorPrivate *priv;
+  ClutterGstCameraPrivate *priv;
   GParamSpec *pspec;
 
-  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
 
-  priv = camera_actor->priv;
+  priv = self->priv;
 
   if (!priv->color_balance)
     return FALSE;
 
   pspec = g_object_class_find_property (
-    G_OBJECT_GET_CLASS (G_OBJECT (priv->color_balance)), property);
+                                        G_OBJECT_GET_CLASS (G_OBJECT (priv->color_balance)), property);
   g_return_val_if_fail (G_IS_PARAM_SPEC_DOUBLE (pspec), FALSE);
 
   g_object_set (G_OBJECT (priv->color_balance), property, value, NULL);
@@ -1153,123 +1291,123 @@ clutter_gst_camera_actor_set_color_balance_property (ClutterGstCameraActor *came
 }
 
 gboolean
-clutter_gst_camera_actor_get_brightness_range (ClutterGstCameraActor *camera_actor,
-                                               gdouble               *min_value,
-                                               gdouble               *max_value,
-                                               gdouble               *default_value)
+clutter_gst_camera_get_brightness_range (ClutterGstCamera *self,
+                                         gdouble          *min_value,
+                                         gdouble          *max_value,
+                                         gdouble          *default_value)
 {
-  return clutter_gst_camera_actor_get_color_balance_property_range (camera_actor,
-             "brightness", min_value, max_value, default_value);
+  return clutter_gst_camera_get_color_balance_property_range (self,
+                                                              "brightness", min_value, max_value, 
default_value);
 }
 
 gboolean
-clutter_gst_camera_actor_get_brightness (ClutterGstCameraActor *camera_actor,
-                                         gdouble               *cur_value)
+clutter_gst_camera_get_brightness (ClutterGstCamera *self,
+                                   gdouble          *cur_value)
 {
-  return clutter_gst_camera_actor_get_color_balance_property (camera_actor,
-             "brightness", cur_value);
+  return clutter_gst_camera_get_color_balance_property (self,
+                                                        "brightness", cur_value);
 }
 
 gboolean
-clutter_gst_camera_actor_set_brightness (ClutterGstCameraActor *camera_actor,
-                                         gdouble                value)
+clutter_gst_camera_set_brightness (ClutterGstCamera *self,
+                                   gdouble           value)
 {
-  return clutter_gst_camera_actor_set_color_balance_property (camera_actor,
-             "brightness", value);
+  return clutter_gst_camera_set_color_balance_property (self,
+                                                        "brightness", value);
 }
 
 gboolean
-clutter_gst_camera_actor_get_contrast_range (ClutterGstCameraActor *camera_actor,
-                                             gdouble               *min_value,
-                                             gdouble               *max_value,
-                                             gdouble               *default_value)
+clutter_gst_camera_get_contrast_range (ClutterGstCamera *self,
+                                       gdouble          *min_value,
+                                       gdouble          *max_value,
+                                       gdouble          *default_value)
 {
-  return clutter_gst_camera_actor_get_color_balance_property_range (camera_actor,
-             "contrast", min_value, max_value, default_value);
+  return clutter_gst_camera_get_color_balance_property_range (self,
+                                                              "contrast", min_value, max_value, 
default_value);
 }
 
 gboolean
-clutter_gst_camera_actor_get_contrast (ClutterGstCameraActor *camera_actor,
-                                       gdouble               *cur_value)
+clutter_gst_camera_get_contrast (ClutterGstCamera *self,
+                                 gdouble          *cur_value)
 {
-  return clutter_gst_camera_actor_get_color_balance_property (camera_actor,
-             "contrast", cur_value);
+  return clutter_gst_camera_get_color_balance_property (self,
+                                                        "contrast", cur_value);
 }
 
 gboolean
-clutter_gst_camera_actor_set_contrast (ClutterGstCameraActor *camera_actor,
-                                       gdouble                value)
+clutter_gst_camera_set_contrast (ClutterGstCamera *self,
+                                 gdouble           value)
 {
-  return clutter_gst_camera_actor_set_color_balance_property (camera_actor,
-             "contrast", value);
+  return clutter_gst_camera_set_color_balance_property (self,
+                                                        "contrast", value);
 }
 
 gboolean
-clutter_gst_camera_actor_get_saturation_range (ClutterGstCameraActor *camera_actor,
-                                               gdouble               *min_value,
-                                               gdouble               *max_value,
-                                               gdouble               *default_value)
+clutter_gst_camera_get_saturation_range (ClutterGstCamera *self,
+                                         gdouble          *min_value,
+                                         gdouble          *max_value,
+                                         gdouble          *default_value)
 {
-  return clutter_gst_camera_actor_get_color_balance_property_range (camera_actor,
-             "saturation", min_value, max_value, default_value);
+  return clutter_gst_camera_get_color_balance_property_range (self,
+                                                              "saturation", min_value, max_value, 
default_value);
 }
 
 gboolean
-clutter_gst_camera_actor_get_saturation (ClutterGstCameraActor *camera_actor,
-                                         gdouble               *cur_value)
+clutter_gst_camera_get_saturation (ClutterGstCamera *self,
+                                   gdouble          *cur_value)
 {
-  return clutter_gst_camera_actor_get_color_balance_property (camera_actor,
-             "saturation", cur_value);
+  return clutter_gst_camera_get_color_balance_property (self,
+                                                        "saturation", cur_value);
 }
 
 gboolean
-clutter_gst_camera_actor_set_saturation (ClutterGstCameraActor *camera_actor,
-                                         gdouble                value)
+clutter_gst_camera_set_saturation (ClutterGstCamera *self,
+                                   gdouble           value)
 {
-  return clutter_gst_camera_actor_set_color_balance_property (camera_actor,
-             "saturation", value);
+  return clutter_gst_camera_set_color_balance_property (self,
+                                                        "saturation", value);
 }
 
 gboolean
-clutter_gst_camera_actor_get_hue_range (ClutterGstCameraActor *camera_actor,
-                                        gdouble               *min_value,
-                                        gdouble               *max_value,
-                                        gdouble               *default_value)
+clutter_gst_camera_get_hue_range (ClutterGstCamera *self,
+                                  gdouble          *min_value,
+                                  gdouble          *max_value,
+                                  gdouble          *default_value)
 {
-  return clutter_gst_camera_actor_get_color_balance_property_range (camera_actor,
-             "hue", min_value, max_value, default_value);
+  return clutter_gst_camera_get_color_balance_property_range (self,
+                                                              "hue", min_value, max_value, default_value);
 }
 
 gboolean
-clutter_gst_camera_actor_get_hue (ClutterGstCameraActor *camera_actor,
-                                  gdouble               *cur_value)
+clutter_gst_camera_get_hue (ClutterGstCamera *self,
+                            gdouble          *cur_value)
 {
-  return clutter_gst_camera_actor_get_color_balance_property (camera_actor,
-             "hue", cur_value);
+  return clutter_gst_camera_get_color_balance_property (self,
+                                                        "hue", cur_value);
 }
 
 gboolean
-clutter_gst_camera_actor_set_hue (ClutterGstCameraActor *camera_actor,
-                                  gdouble                value)
+clutter_gst_camera_set_hue (ClutterGstCamera *self,
+                            gdouble           value)
 {
-  return clutter_gst_camera_actor_set_color_balance_property (camera_actor,
-             "hue", value);
+  return clutter_gst_camera_set_color_balance_property (self,
+                                                        "hue", value);
 }
 
 /**
- * clutter_gst_camera_actor_get_filter:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_get_filter:
+ * @self: a #ClutterGstCamera
  *
  * Retrieve the current filter being used.
  *
  * Return value: (transfer none): The current filter or %NULL if none is set
  */
 GstElement *
-clutter_gst_camera_actor_get_filter (ClutterGstCameraActor  *camera_actor)
+clutter_gst_camera_get_filter (ClutterGstCamera  *self)
 {
-  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
 
-  return camera_actor->priv->custom_filter;
+  return self->priv->custom_filter;
 }
 
 static GstElement *
@@ -1300,25 +1438,25 @@ create_filter_bin (GstElement *filter)
   gst_element_add_pad (filter_bin, gst_ghost_pad_new ("src", pad));
   gst_object_unref (GST_OBJECT (pad));
 
-out:
+ out:
   return filter_bin;
 
-err:
+ err:
   if (pre_filter_colorspace)
     gst_object_unref (pre_filter_colorspace);
   if (post_filter_colorspace)
     gst_object_unref (post_filter_colorspace);
   goto out;
 
-err_not_linked:
+ err_not_linked:
   gst_object_unref (filter_bin);
   filter_bin = NULL;
   goto out;
 }
 
 /**
- * clutter_gst_camera_actor_set_filter:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_set_filter:
+ * @self: a #ClutterGstCamera
  * @filter: a #GstElement for the filter
  *
  * Set the filter element to be used.
@@ -1327,15 +1465,15 @@ err_not_linked:
  * Return value: %TRUE on success, %FALSE otherwise
  */
 gboolean
-clutter_gst_camera_actor_set_filter (ClutterGstCameraActor  *camera_actor,
-                                     GstElement             *filter)
+clutter_gst_camera_set_filter (ClutterGstCamera *self,
+                               GstElement       *filter)
 {
-  ClutterGstCameraActorPrivate *priv;
+  ClutterGstCameraPrivate *priv;
   gboolean ret = FALSE;
 
-  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
 
-  priv = camera_actor->priv;
+  priv = self->priv;
 
   if (!priv->custom_filter && !filter)
     {
@@ -1381,7 +1519,7 @@ clutter_gst_camera_actor_set_filter (ClutterGstCameraActor  *camera_actor,
           goto err_restore;
         }
 
-      if (clutter_gst_camera_actor_is_playing (camera_actor))
+      if (clutter_gst_camera_is_playing (self))
         gst_element_set_state (priv->custom_filter, GST_STATE_PLAYING);
     }
   else
@@ -1389,11 +1527,11 @@ clutter_gst_camera_actor_set_filter (ClutterGstCameraActor  *camera_actor,
 
   ret = TRUE;
 
-out:
+ out:
   g_object_set (G_OBJECT (priv->valve), "drop", FALSE, NULL);
   return ret;
 
-err_restore:
+ err_restore:
   ret = FALSE;
   /* restore default pipeline, should always work */
   gst_element_link (priv->valve, priv->gamma);
@@ -1401,37 +1539,37 @@ err_restore:
 }
 
 /**
- * clutter_gst_camera_actor_remove_filter:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_remove_filter:
+ * @self: a #ClutterGstCamera
  *
  * Remove the current filter, if any.
  *
  * Return value: %TRUE on success, %FALSE otherwise
  */
 gboolean
-clutter_gst_camera_actor_remove_filter (ClutterGstCameraActor *camera_actor)
+clutter_gst_camera_remove_filter (ClutterGstCamera *self)
 {
-  return clutter_gst_camera_actor_set_filter (camera_actor, NULL);
+  return clutter_gst_camera_set_filter (self, NULL);
 }
 
 /**
- * clutter_gst_camera_actor_is_playing:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_is_playing:
+ * @self: a #ClutterGstCamera
  *
- * Retrieve whether the @camera_actor is playing.
+ * Retrieve whether the @self is playing.
  *
  * Return value: %TRUE if playing, %FALSE otherwise
  */
 gboolean
-clutter_gst_camera_actor_is_playing (ClutterGstCameraActor *camera_actor)
+clutter_gst_camera_is_playing (ClutterGstCamera *self)
 {
-  ClutterGstCameraActorPrivate *priv;
+  ClutterGstCameraPrivate *priv;
   GstState state, pending;
   gboolean playing;
 
-  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
 
-  priv = camera_actor->priv;
+  priv = self->priv;
   if (!priv->camerabin)
     return FALSE;
 
@@ -1446,48 +1584,22 @@ clutter_gst_camera_actor_is_playing (ClutterGstCameraActor *camera_actor)
 }
 
 /**
- * clutter_gst_camera_actor_set_playing:
- * @camera_actor: a #ClutterGstCameraActor
- * @playing: %TRUE to start playback
- *
- * Starts or stops playback.
- */
-void
-clutter_gst_camera_actor_set_playing (ClutterGstCameraActor *camera_actor,
-                                      gboolean               playing)
-{
-  ClutterGstCameraActorPrivate *priv;
-  GstState target_state;
-
-  g_return_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor));
-
-  priv = camera_actor->priv;
-
-  if (!priv->camerabin)
-    return;
-
-  target_state = playing ? GST_STATE_PLAYING : GST_STATE_NULL;
-
-  gst_element_set_state (priv->camerabin, target_state);
-}
-
-/**
- * clutter_gst_camera_actor_is_ready_for_capture:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_is_ready_for_capture:
+ * @self: a #ClutterGstCamera
  *
- * Check whether the @camera_actor is ready for video/photo capture.
+ * Check whether the @self is ready for video/photo capture.
  *
- * Return value: %TRUE if @camera_actor is ready for capture, %FALSE otherwise
+ * Return value: %TRUE if @self is ready for capture, %FALSE otherwise
  */
 gboolean
-clutter_gst_camera_actor_is_ready_for_capture (ClutterGstCameraActor *camera_actor)
+clutter_gst_camera_is_ready_for_capture (ClutterGstCamera *self)
 {
-  ClutterGstCameraActorPrivate *priv;
+  ClutterGstCameraPrivate *priv;
   gboolean ready_for_capture;
 
-  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
 
-  priv = camera_actor->priv;
+  priv = self->priv;
 
   g_object_get (priv->camera_source, "ready-for-capture", &ready_for_capture, NULL);
 
@@ -1495,42 +1607,42 @@ clutter_gst_camera_actor_is_ready_for_capture (ClutterGstCameraActor *camera_act
 }
 
 /**
- * clutter_gst_camera_actor_is_recording_video:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_is_recording_video:
+ * @self: a #ClutterGstCamera
  *
- * Check whether the @camera_actor is recording video.
+ * Check whether the @self is recording video.
  *
- * Return value: %TRUE if @camera_actor is recording video, %FALSE otherwise
+ * Return value: %TRUE if @self is recording video, %FALSE otherwise
  */
 gboolean
-clutter_gst_camera_actor_is_recording_video (ClutterGstCameraActor *camera_actor)
+clutter_gst_camera_is_recording_video (ClutterGstCamera *self)
 {
-  ClutterGstCameraActorPrivate *priv;
+  ClutterGstCameraPrivate *priv;
 
-  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
 
-  priv = camera_actor->priv;
+  priv = self->priv;
 
   return priv->is_recording;
 }
 
 /**
- * clutter_gst_camera_actor_set_video_profile:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_set_video_profile:
+ * @self: a #ClutterGstCamera
  * @profile: A #GstEncodingProfile to be used for video recording.
  *
  * Set the encoding profile to be used for video recording.
  * The default profile saves videos as Ogg/Theora videos.
  */
 void
-clutter_gst_camera_actor_set_video_profile (ClutterGstCameraActor *camera_actor,
-                                            GstEncodingProfile    *profile)
+clutter_gst_camera_set_video_profile (ClutterGstCamera   *self,
+                                      GstEncodingProfile *profile)
 {
-  ClutterGstCameraActorPrivate *priv;
+  ClutterGstCameraPrivate *priv;
 
-  g_return_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor));
+  g_return_if_fail (CLUTTER_GST_IS_CAMERA (self));
 
-  priv = camera_actor->priv;
+  priv = self->priv;
 
   if (!priv->camerabin)
     return;
@@ -1539,27 +1651,27 @@ clutter_gst_camera_actor_set_video_profile (ClutterGstCameraActor *camera_actor,
 }
 
 /**
- * clutter_gst_camera_actor_start_video_recording:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_start_video_recording:
+ * @self: a #ClutterGstCamera
  * @filename: (type filename): the name of the video file to where the
  * recording will be saved
  *
- * Start a video recording with the @camera_actor and save it to @filename.
- * This method requires that @camera_actor is playing and ready for capture.
+ * Start a video recording with the @self and save it to @filename.
+ * This method requires that @self is playing and ready for capture.
  *
  * The ::video-saved signal will be emitted when the video is saved.
  *
  * Return value: %TRUE if the video recording was successfully started, %FALSE otherwise
  */
 gboolean
-clutter_gst_camera_actor_start_video_recording (ClutterGstCameraActor *camera_actor,
-                                                const gchar           *filename)
+clutter_gst_camera_start_video_recording (ClutterGstCamera *self,
+                                          const gchar           *filename)
 {
-  ClutterGstCameraActorPrivate *priv;
+  ClutterGstCameraPrivate *priv;
 
-  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
 
-  priv = camera_actor->priv;
+  priv = self->priv;
 
   if (!priv->camerabin)
     return FALSE;
@@ -1567,34 +1679,34 @@ clutter_gst_camera_actor_start_video_recording (ClutterGstCameraActor *camera_ac
   if (priv->is_recording)
     return TRUE;
 
-  if (!clutter_gst_camera_actor_is_playing (camera_actor))
+  if (!clutter_gst_camera_is_playing (self))
     return FALSE;
 
-  if (!clutter_gst_camera_actor_is_ready_for_capture (camera_actor))
+  if (!clutter_gst_camera_is_ready_for_capture (self))
     return FALSE;
 
   g_object_set (priv->camerabin, "mode", CAPTURE_MODE_VIDEO, NULL);
   g_object_set (priv->camerabin, "location", filename, NULL);
-  g_signal_emit_by_name (priv->camerabin, "start-capture", 0);
+  g_signal_emit_by_name (priv->camerabin, "start-capture");
   priv->is_recording = TRUE;
   return TRUE;
 }
 
 /**
  * clutter_gst_camera_stop_video_recording:
- * @camera_actor: a #ClutterGstCameraActor
+ * @self: a #ClutterGstCamera
  *
- * Stop recording video on the @camera_actor.
+ * Stop recording video on the @self.
  */
 void
-clutter_gst_camera_actor_stop_video_recording (ClutterGstCameraActor *camera_actor)
+clutter_gst_camera_stop_video_recording (ClutterGstCamera *self)
 {
-  ClutterGstCameraActorPrivate *priv;
+  ClutterGstCameraPrivate *priv;
   GstState state;
 
-  g_return_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor));
+  g_return_if_fail (CLUTTER_GST_IS_CAMERA (self));
 
-  priv = camera_actor->priv;
+  priv = self->priv;
 
   if (!priv->camerabin)
     return;
@@ -1602,13 +1714,13 @@ clutter_gst_camera_actor_stop_video_recording (ClutterGstCameraActor *camera_act
   if (!priv->is_recording)
     return;
 
-  if (!clutter_gst_camera_actor_is_playing (camera_actor))
+  if (!clutter_gst_camera_is_playing (self))
     return;
 
   gst_element_get_state (priv->camerabin, &state, NULL, 0);
 
   if (state == GST_STATE_PLAYING)
-    g_signal_emit_by_name (priv->camerabin, "stop-capture", 0);
+    g_signal_emit_by_name (priv->camerabin, "stop-capture");
   else if (priv->is_recording)
     {
       g_warning ("Cannot cleanly shutdown recording pipeline, forcing");
@@ -1620,22 +1732,22 @@ clutter_gst_camera_actor_stop_video_recording (ClutterGstCameraActor *camera_act
 }
 
 /**
- * clutter_gst_camera_actor_set_photo_profile:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_set_photo_profile:
+ * @self: a #ClutterGstCamera
  * @profile: A #GstEncodingProfile to be used for photo captures.
  *
  * Set the encoding profile to be used for photo captures.
  * The default profile saves photos as JPEG images.
  */
 void
-clutter_gst_camera_actor_set_photo_profile (ClutterGstCameraActor *camera_actor,
-                                            GstEncodingProfile    *profile)
+clutter_gst_camera_set_photo_profile (ClutterGstCamera *self,
+                                      GstEncodingProfile    *profile)
 {
-  ClutterGstCameraActorPrivate *priv;
+  ClutterGstCameraPrivate *priv;
 
-  g_return_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor));
+  g_return_if_fail (CLUTTER_GST_IS_CAMERA (self));
 
-  priv = camera_actor->priv;
+  priv = self->priv;
 
   if (!priv->camerabin)
     return;
@@ -1644,36 +1756,36 @@ clutter_gst_camera_actor_set_photo_profile (ClutterGstCameraActor *camera_actor,
 }
 
 /**
- * clutter_gst_camera_actor_take_photo:
- * @camera_actor: a #ClutterGstCameraActor
+ * clutter_gst_camera_take_photo:
+ * @self: a #ClutterGstCamera
  * @filename: (type filename): the name of the file to where the
  * photo will be saved
  *
- * Take a photo with the @camera_actor and save it to @filename.
- * This method requires that @camera_actor is playing and ready for capture.
+ * Take a photo with the @self and save it to @filename.
+ * This method requires that @self is playing and ready for capture.
  *
  * The ::photo-saved signal will be emitted when the video is saved.
  *
  * Return value: %TRUE if the photo was successfully captured, %FALSE otherwise
  */
 gboolean
-clutter_gst_camera_actor_take_photo (ClutterGstCameraActor *camera_actor,
-                                     const gchar           *filename)
+clutter_gst_camera_take_photo (ClutterGstCamera *self,
+                               const gchar      *filename)
 {
-  ClutterGstCameraActorPrivate *priv;
+  ClutterGstCameraPrivate *priv;
 
-  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
   g_return_val_if_fail (filename != NULL, FALSE);
 
-  priv = camera_actor->priv;
+  priv = self->priv;
 
   if (!priv->camerabin)
     return FALSE;
 
-  if (!clutter_gst_camera_actor_is_playing (camera_actor))
+  if (!clutter_gst_camera_is_playing (self))
     return FALSE;
 
-  if (!clutter_gst_camera_actor_is_ready_for_capture (camera_actor))
+  if (!clutter_gst_camera_is_ready_for_capture (self))
     return FALSE;
 
   g_free (priv->photo_filename);
@@ -1682,37 +1794,37 @@ clutter_gst_camera_actor_take_photo (ClutterGstCameraActor *camera_actor,
   /* Take the photo */
   g_object_set (priv->camerabin, "location", filename, NULL);
   g_object_set (priv->camerabin, "mode", CAPTURE_MODE_IMAGE, NULL);
-  g_signal_emit_by_name (priv->camerabin, "start-capture", 0);
+  g_signal_emit_by_name (priv->camerabin, "start-capture");
   return TRUE;
 }
 
 /**
  * clutter_gst_camera_take_photo_pixbuf:
- * @camera_actor: a #ClutterGstCameraActor
+ * @self: a #ClutterGstCamera
  *
- * Take a photo with the @camera_actor and emit it in the ::photo-taken signal as a
+ * Take a photo with the @self and emit it in the ::photo-taken signal as a
  * #GdkPixbuf.
- * This method requires that @camera_actor is playing and ready for capture.
+ * This method requires that @self is playing and ready for capture.
  *
  * Return value: %TRUE if the photo was successfully captured, %FALSE otherwise
  */
 gboolean
-clutter_gst_camera_actor_take_photo_pixbuf (ClutterGstCameraActor *camera_actor)
+clutter_gst_camera_take_photo_pixbuf (ClutterGstCamera *self)
 {
-  ClutterGstCameraActorPrivate *priv;
+  ClutterGstCameraPrivate *priv;
   GstCaps *caps;
 
-  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA_ACTOR (camera_actor), FALSE);
+  g_return_val_if_fail (CLUTTER_GST_IS_CAMERA (self), FALSE);
 
-  priv = camera_actor->priv;
+  priv = self->priv;
 
   if (!priv->camerabin)
     return FALSE;
 
-  if (!clutter_gst_camera_actor_is_playing (camera_actor))
+  if (!clutter_gst_camera_is_playing (self))
     return FALSE;
 
-  if (!clutter_gst_camera_actor_is_ready_for_capture (camera_actor))
+  if (!clutter_gst_camera_is_ready_for_capture (self))
     return FALSE;
 
   caps = gst_caps_new_simple ("video/x-raw",
@@ -1729,6 +1841,6 @@ clutter_gst_camera_actor_take_photo_pixbuf (ClutterGstCameraActor *camera_actor)
   /* Take the photo */
   g_object_set (priv->camerabin, "location", NULL, NULL);
   g_object_set (priv->camerabin, "mode", CAPTURE_MODE_IMAGE, NULL);
-  g_signal_emit_by_name (priv->camerabin, "start-capture", 0);
+  g_signal_emit_by_name (priv->camerabin, "start-capture");
   return TRUE;
 }
diff --git a/clutter-gst/clutter-gst-camera.h b/clutter-gst/clutter-gst-camera.h
new file mode 100644
index 0000000..f348ab0
--- /dev/null
+++ b/clutter-gst/clutter-gst-camera.h
@@ -0,0 +1,208 @@
+/*
+ * Clutter-GStreamer.
+ *
+ * GStreamer integration library for Clutter.
+ *
+ * clutter-gst-camera-actor.h - ClutterActor using GStreamer to display/manipulate a
+ *                              camera stream.
+ *
+ * Authored By Andre Moreira Magalhaes <andre magalhaes collabora co uk>
+ *
+ * Copyright (C) 2012 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * 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.
+ */
+
+#if !defined(__CLUTTER_GST_H_INSIDE__) && !defined(CLUTTER_GST_COMPILATION)
+#error "Only <clutter-gst/clutter-gst.h> can be included directly."
+#endif
+
+#ifndef __CLUTTER_GST_CAMERA_H__
+#define __CLUTTER_GST_CAMERA_H__
+
+#include <clutter/clutter.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <glib-object.h>
+#include <gst/gstelement.h>
+#include <gst/pbutils/encoding-profile.h>
+
+#include <clutter-gst/clutter-gst-actor.h>
+#include <clutter-gst/clutter-gst-camera-device.h>
+#include <clutter-gst/clutter-gst-types.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_GST_TYPE_CAMERA clutter_gst_camera_get_type()
+
+#define CLUTTER_GST_CAMERA(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  CLUTTER_GST_TYPE_CAMERA, ClutterGstCamera))
+
+#define CLUTTER_GST_CAMERA_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  CLUTTER_GST_TYPE_CAMERA, ClutterGstCameraClass))
+
+#define CLUTTER_GST_IS_CAMERA(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  CLUTTER_GST_TYPE_CAMERA))
+
+#define CLUTTER_GST_IS_CAMERA_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  CLUTTER_GST_TYPE_CAMERA))
+
+#define CLUTTER_GST_CAMERA_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  CLUTTER_GST_TYPE_CAMERA, ClutterGstCameraClass))
+
+typedef struct _ClutterGstCamera        ClutterGstCamera;
+typedef struct _ClutterGstCameraClass   ClutterGstCameraClass;
+typedef struct _ClutterGstCameraPrivate ClutterGstCameraPrivate;
+
+/**
+ * ClutterGstCamera:
+ *
+ * Subclass of #ClutterGstActor that displays camera streams using GStreamer.
+ *
+ * The #ClutterGstCamera structure contains only private data and
+ * should not be accessed directly.
+ */
+struct _ClutterGstCamera
+{
+  /*< private >*/
+  ClutterGstActor parent;
+  ClutterGstCameraPrivate *priv;
+};
+
+/**
+ * ClutterGstCameraClass:
+ *
+ * Base class for #ClutterGstCamera.
+ */
+struct _ClutterGstCameraClass
+{
+  /*< private >*/
+  ClutterGstActorClass parent_class;
+
+  void (* ready_for_capture) (ClutterGstCamera *self,
+                              gboolean               ready);
+  void (* photo_saved)       (ClutterGstCamera *self);
+  void (* photo_taken)       (ClutterGstCamera *self,
+                              GdkPixbuf             *pixbuf);
+  void (* video_saved)       (ClutterGstCamera *self);
+
+  /* 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_gst_camera_get_type (void) G_GNUC_CONST;
+
+ClutterGstCamera * clutter_gst_camera_new                   (void);
+
+const GPtrArray *
+               clutter_gst_camera_get_camera_devices    (ClutterGstCamera   *self);
+ClutterGstCameraDevice *
+               clutter_gst_camera_get_camera_device     (ClutterGstCamera   *self);
+gboolean       clutter_gst_camera_set_camera_device     (ClutterGstCamera       *self,
+                                                         ClutterGstCameraDevice *device);
+
+gboolean       clutter_gst_camera_supports_gamma_correction
+                                                        (ClutterGstCamera   *self);
+gboolean       clutter_gst_camera_get_gamma_range       (ClutterGstCamera   *self,
+                                                         gdouble            *min_value,
+                                                         gdouble            *max_value,
+                                                         gdouble            *default_value);
+gboolean       clutter_gst_camera_get_gamma             (ClutterGstCamera   *self,
+                                                         gdouble            *cur_value);
+gboolean       clutter_gst_camera_set_gamma             (ClutterGstCamera   *self,
+                                                         gdouble             value);
+
+gboolean       clutter_gst_camera_supports_color_balance
+                                                        (ClutterGstCamera   *self);
+gboolean       clutter_gst_camera_get_color_balance_property_range
+                                                        (ClutterGstCamera   *self,
+                                                         const gchar        *property,
+                                                         gdouble            *min_value,
+                                                         gdouble            *max_value,
+                                                         gdouble            *default_value);
+gboolean       clutter_gst_camera_get_color_balance_property
+                                                        (ClutterGstCamera   *self,
+                                                         const gchar        *property,
+                                                         gdouble            *cur_value);
+gboolean       clutter_gst_camera_set_color_balance_property
+                                                        (ClutterGstCamera   *self,
+                                                         const gchar        *property,
+                                                         gdouble             value);
+gboolean       clutter_gst_camera_get_brightness_range  (ClutterGstCamera   *self,
+                                                         gdouble            *min_value,
+                                                         gdouble            *max_value,
+                                                         gdouble            *default_value);
+gboolean       clutter_gst_camera_get_brightness        (ClutterGstCamera   *self,
+                                                         gdouble            *cur_value);
+gboolean       clutter_gst_camera_set_brightness        (ClutterGstCamera   *self,
+                                                         gdouble             value);
+gboolean       clutter_gst_camera_get_contrast_range    (ClutterGstCamera   *self,
+                                                         gdouble            *min_value,
+                                                         gdouble            *max_value,
+                                                         gdouble            *default_value);
+gboolean       clutter_gst_camera_get_contrast          (ClutterGstCamera   *self,
+                                                         gdouble            *cur_value);
+gboolean       clutter_gst_camera_set_contrast          (ClutterGstCamera   *self,
+                                                         gdouble             value);
+gboolean       clutter_gst_camera_get_saturation_range  (ClutterGstCamera   *self,
+                                                         gdouble            *min_value,
+                                                         gdouble            *max_value,
+                                                         gdouble            *default_value);
+gboolean       clutter_gst_camera_get_saturation        (ClutterGstCamera   *self,
+                                                         gdouble            *cur_value);
+gboolean       clutter_gst_camera_set_saturation        (ClutterGstCamera   *self,
+                                                         gdouble             value);
+gboolean       clutter_gst_camera_get_hue_range         (ClutterGstCamera   *self,
+                                                         gdouble            *min_value,
+                                                         gdouble            *max_value,
+                                                         gdouble            *default_value);
+gboolean       clutter_gst_camera_get_hue               (ClutterGstCamera   *self,
+                                                         gdouble            *cur_value);
+gboolean       clutter_gst_camera_set_hue               (ClutterGstCamera   *self,
+                                                         gdouble             value);
+
+GstElement *   clutter_gst_camera_get_filter            (ClutterGstCamera   *self);
+gboolean       clutter_gst_camera_set_filter            (ClutterGstCamera   *self,
+                                                         GstElement         *filter);
+gboolean       clutter_gst_camera_remove_filter         (ClutterGstCamera   *self);
+
+gboolean       clutter_gst_camera_is_ready_for_capture  (ClutterGstCamera   *self);
+
+void           clutter_gst_camera_set_video_profile     (ClutterGstCamera   *self,
+                                                         GstEncodingProfile *profile);
+gboolean       clutter_gst_camera_is_recording_video    (ClutterGstCamera   *self);
+gboolean       clutter_gst_camera_start_video_recording (ClutterGstCamera   *self,
+                                                               const gchar  *filename);
+void           clutter_gst_camera_stop_video_recording  (ClutterGstCamera   *self);
+
+void           clutter_gst_camera_set_photo_profile     (ClutterGstCamera   *self,
+                                                         GstEncodingProfile *profile);
+gboolean       clutter_gst_camera_take_photo            (ClutterGstCamera   *self,
+                                                         const gchar        *filename);
+gboolean       clutter_gst_camera_take_photo_pixbuf     (ClutterGstCamera   *self);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_GST_CAMERA_H__ */
diff --git a/clutter-gst/clutter-gst-playback.c b/clutter-gst/clutter-gst-playback.c
new file mode 100644
index 0000000..2152547
--- /dev/null
+++ b/clutter-gst/clutter-gst-playback.c
@@ -0,0 +1,2799 @@
+/*
+ * Clutter-GStreamer.
+ *
+ * GStreamer integration library for Clutter.
+ *
+ * clutter-gst-player.c - Wrap some convenience functions around playbin
+ *
+ * Authored By Damien Lespiau    <damien lespiau intel com>
+ *             Lionel Landwerlin <lionel g landwerlin linux intel com>
+ *             Matthew Allum     <mallum openedhand com>
+ *             Emmanuele Bassi   <ebassi linux intel com>
+ *             Andre Moreira Magalhaes <andre magalhaes collabora co uk>
+ *
+ * Copyright (C) 2006 OpenedHand
+ * Copyright (C) 2009-2013 Intel Corporation
+ * Copyright (C) 2012 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "clutter-gst-debug.h"
+#include "clutter-gst-enum-types.h"
+#include "clutter-gst-marshal.h"
+#include "clutter-gst-playback.h"
+#include "clutter-gst-player.h"
+#include "clutter-gst-private.h"
+
+#include <string.h>
+
+#include <gio/gio.h>
+#include <cogl-gst/cogl-gst.h>
+#include <gst/video/video.h>
+#include <gst/tag/tag.h>
+#include <gst/audio/streamvolume.h>
+
+#if defined (CLUTTER_WINDOWING_X11) && defined (HAVE_HW_DECODER_SUPPORT)
+#define GST_USE_UNSTABLE_API 1
+#include <gst/video/videocontext.h>
+#include <clutter/x11/clutter-x11.h>
+#endif
+
+static void player_iface_init (ClutterGstPlayerIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (ClutterGstPlayback, clutter_gst_playback, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (CLUTTER_GST_TYPE_PLAYER, player_iface_init))
+
+#define GST_PLAYBACK_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), CLUTTER_GST_TYPE_PLAYBACK, ClutterGstPlaybackPrivate))
+
+/* idle timeouts (in ms) */
+#define TICK_TIMEOUT        500
+#define BUFFERING_TIMEOUT   250
+
+enum
+{
+  PROP_0,
+
+  PROP_URI,
+  PROP_PLAYING,
+  PROP_PROGRESS,
+  PROP_SUBTITLE_URI,
+  PROP_SUBTITLE_FONT_NAME,
+  PROP_AUDIO_VOLUME,
+  PROP_CAN_SEEK,
+  PROP_BUFFER_FILL,
+  PROP_DURATION,
+  PROP_IDLE,
+  PROP_USER_AGENT,
+  PROP_SEEK_FLAGS,
+  PROP_AUDIO_STREAMS,
+  PROP_AUDIO_STREAM,
+  PROP_SUBTITLE_TRACKS,
+  PROP_SUBTITLE_TRACK,
+  PROP_IN_SEEK
+};
+
+enum
+{
+  DOWNLOAD_BUFFERING_SIGNAL,
+
+  LAST_SIGNAL
+};
+
+/* Elements don't expose header files */
+typedef enum {
+  GST_PLAY_FLAG_VIDEO         = (1 << 0),
+  GST_PLAY_FLAG_AUDIO         = (1 << 1),
+  GST_PLAY_FLAG_TEXT          = (1 << 2),
+  GST_PLAY_FLAG_VIS           = (1 << 3),
+  GST_PLAY_FLAG_SOFT_VOLUME   = (1 << 4),
+  GST_PLAY_FLAG_NATIVE_AUDIO  = (1 << 5),
+  GST_PLAY_FLAG_NATIVE_VIDEO  = (1 << 6),
+  GST_PLAY_FLAG_DOWNLOAD      = (1 << 7),
+  GST_PLAY_FLAG_BUFFERING     = (1 << 8),
+  GST_PLAY_FLAG_DEINTERLACE   = (1 << 9)
+} GstPlayFlags;
+
+struct _ClutterGstPlaybackPrivate
+{
+  GstElement *pipeline;
+  GstBus *bus;
+
+  ClutterGstFrame *current_frame;
+
+  gchar *uri;
+
+  guint is_idle : 1;
+  guint is_live : 1;
+  guint can_seek : 1;
+  guint in_seek : 1;
+  guint is_changing_uri : 1;
+  guint in_error : 1;
+  guint in_eos : 1;
+  guint in_download_buffering : 1;
+  /* when in progressive download, we use the buffer-fill property to signal
+   * that we have enough data to play the stream. This flag allows to send
+   * the notify that buffer-fill is 1.0 only once */
+  guint virtual_stream_buffer_signalled : 1;
+
+  gdouble stacked_progress;
+
+  gdouble target_progress;
+  GstState target_state;
+
+  guint tick_timeout_id;
+  guint buffering_timeout_id;
+
+  /* This is a cubic volume, suitable for use in a UI cf. StreamVolume doc */
+  gdouble volume;
+
+  gdouble buffer_fill;
+  gdouble duration;
+  gchar *font_name;
+  gchar *user_agent;
+
+  GstSeekFlags seek_flags;    /* flags for the seek in set_progress(); */
+
+  GstElement *download_buffering_element;
+
+  GList *audio_streams;
+  GList *subtitle_tracks;
+};
+
+
+static guint signals[LAST_SIGNAL] = { 0, };
+
+static gboolean player_buffering_timeout (gpointer data);
+
+/* Logic */
+
+#ifdef CLUTTER_GST_ENABLE_DEBUG
+static gchar *
+get_stream_description (GstTagList *tags,
+                        gint        track_num)
+{
+  gchar *description = NULL;
+
+  if (tags)
+    {
+
+      gst_tag_list_get_string (tags, GST_TAG_LANGUAGE_CODE, &description);
+
+      if (description)
+        {
+          const gchar *language = gst_tag_get_language_name (description);
+
+          if (language)
+            {
+              g_free (description);
+              description = g_strdup (language);
+            }
+        }
+
+      if (!description)
+        gst_tag_list_get_string (tags, GST_TAG_CODEC, &description);
+    }
+
+  if (!description)
+    description = g_strdup_printf ("Track %d", track_num);
+
+  return description;
+}
+
+gchar *
+list_to_string (GList *list)
+{
+  GstTagList *tags;
+  gchar *description;
+  GString *string;
+  GList *l;
+  gint n, i;
+
+  if (!list)
+    return g_strdup ("<empty list>");
+
+  string = g_string_new (NULL);
+  n = g_list_length (list);
+  for (i = 0, l = list; i < n - 1; i++, l = g_list_next (l))
+    {
+      tags = l->data;
+      description = get_stream_description (tags, i);
+      g_string_append_printf (string, "%s, ", description);
+      g_free (description);
+    }
+
+  tags = l->data;
+  description = get_stream_description (tags, i);
+  g_string_append_printf (string, "%s", (gchar *) description);
+  g_free (description);
+
+  return g_string_free (string, FALSE);
+}
+#endif
+
+static const gchar *
+gst_state_to_string (GstState state)
+{
+  switch (state)
+    {
+    case GST_STATE_VOID_PENDING:
+      return "pending";
+    case GST_STATE_NULL:
+      return "null";
+    case GST_STATE_READY:
+      return "ready";
+    case GST_STATE_PAUSED:
+      return "paused";
+    case GST_STATE_PLAYING:
+      return "playing";
+    }
+
+  return "Unknown state";
+}
+
+static void
+free_tags_list (GList **listp)
+{
+  GList *l;
+
+  l = *listp;
+  while (l)
+    {
+      if (l->data)
+        gst_tag_list_unref (l->data);
+      l = g_list_delete_link (l, l);
+    }
+
+  *listp = NULL;
+}
+
+static gboolean
+tick_timeout (gpointer data)
+{
+  GObject *player = data;
+
+  g_object_notify (player, "progress");
+
+  return TRUE;
+}
+
+static void
+player_set_user_agent (ClutterGstPlayback *self,
+                       const gchar        *user_agent)
+{
+  ClutterGstPlaybackPrivate *priv = self->priv;
+  GstElement *source;
+  GParamSpec *pspec;
+
+  if (user_agent == NULL)
+    return;
+
+  g_object_get (priv->pipeline, "source", &source, NULL);
+  if (source == NULL)
+    return;
+
+  pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (source),
+                                        "user-agent");
+  if (pspec == NULL)
+    return;
+
+  CLUTTER_GST_NOTE (MEDIA, "setting user agent: %s", user_agent);
+
+  g_object_set (source, "user-agent", user_agent, NULL);
+}
+
+static void
+autoload_subtitle (ClutterGstPlayback *self,
+                   const gchar        *uri)
+{
+  ClutterGstPlaybackPrivate *priv = self->priv;
+  gchar *path, *dot, *subtitle_path;
+  GFile *video;
+  guint i;
+
+  static const char subtitles_extensions[][4] =
+    {
+      "sub", "SUB",
+      "srt", "SRT",
+      "smi", "SMI",
+      "ssa", "SSA",
+      "ass", "ASS",
+      "asc", "ASC"
+    };
+
+  /* do not try to look for subtitle files if the video file is not mounted
+   * locally */
+  if (!g_str_has_prefix (uri, "file://"))
+    return;
+
+  /* Retrieve the absolute path of the video file */
+  video = g_file_new_for_uri (uri);
+  path = g_file_get_path (video);
+  g_object_unref (video);
+  if (path == NULL)
+    return;
+
+  /* Put a '\0' after the dot of the extension */
+  dot = strrchr (path, '.');
+  if (dot == NULL) {
+    g_free (path);
+    return;
+  }
+  *++dot = '\0';
+
+  /* we can't use path as the temporary buffer for the paths of the potential
+   * subtitle files as we may not have enough room there */
+  subtitle_path = g_malloc (strlen (path) + 1 + 4);
+  strcpy (subtitle_path, path);
+
+  /* reuse dot to point to the first byte of the extension of subtitle_path */
+  dot = subtitle_path + (dot - path);
+
+  for (i = 0; i < G_N_ELEMENTS (subtitles_extensions); i++)
+    {
+      GFile *candidate;
+
+      memcpy (dot, subtitles_extensions[i], 4);
+      candidate = g_file_new_for_path (subtitle_path);
+      if (g_file_query_exists (candidate, NULL))
+        {
+          gchar *suburi;
+
+          suburi = g_file_get_uri (candidate);
+
+          CLUTTER_GST_NOTE (MEDIA, "found subtitle: %s", suburi);
+
+          g_object_set (priv->pipeline, "suburi", suburi, NULL);
+          g_free (suburi);
+
+          g_object_unref (candidate);
+          break;
+        }
+
+      g_object_unref (candidate);
+    }
+
+  g_free (path);
+  g_free (subtitle_path);
+}
+
+static void
+set_subtitle_uri (ClutterGstPlayback *self,
+                  const gchar        *uri)
+{
+  ClutterGstPlaybackPrivate *priv = self->priv;
+  GstPlayFlags flags;
+
+  if (!priv->pipeline)
+    return;
+
+  CLUTTER_GST_NOTE (MEDIA, "setting subtitle URI: %s", uri);
+
+  g_object_get (priv->pipeline, "flags", &flags, NULL);
+
+  g_object_set (priv->pipeline, "suburi", uri, NULL);
+
+  g_object_set (priv->pipeline, "flags", flags, NULL);
+}
+
+static void
+player_configure_buffering_timeout (ClutterGstPlayback *self,
+                                    guint               ms)
+{
+  ClutterGstPlaybackPrivate *priv = self->priv;
+
+  if (priv->buffering_timeout_id)
+    {
+      g_source_remove (priv->buffering_timeout_id);
+      priv->buffering_timeout_id = 0;
+    }
+
+  if (ms)
+    {
+      priv->buffering_timeout_id =
+        g_timeout_add (ms, player_buffering_timeout, self);
+    }
+}
+
+static void
+player_clear_download_buffering (ClutterGstPlayback *self)
+{
+  ClutterGstPlaybackPrivate *priv = self->priv;
+
+  if (priv->download_buffering_element)
+    {
+      g_object_unref (priv->download_buffering_element);
+      priv->download_buffering_element = NULL;
+    }
+  player_configure_buffering_timeout (self, 0);
+  priv->in_download_buffering = FALSE;
+  priv->virtual_stream_buffer_signalled = 0;
+}
+
+static gboolean
+is_live_pipeline (GstElement *pipeline)
+{
+  GstState state, pending;
+  GstStateChangeReturn state_change_res;
+  gboolean is_live = FALSE;
+
+  /* get pipeline current state, we need to change the pipeline state to PAUSED to
+   * see if we are dealing with a live source and we want to restore the pipeline
+   * state afterwards */
+  gst_element_get_state (pipeline, &state, &pending, 0);
+
+  /* a pipeline with live source should return NO_PREROLL in PAUSE */
+  state_change_res = gst_element_set_state (pipeline, GST_STATE_PAUSED);
+  is_live = (state_change_res == GST_STATE_CHANGE_NO_PREROLL);
+
+  /* restore pipeline previous state */
+  if (pending == GST_STATE_VOID_PENDING)
+    gst_element_set_state (pipeline, state);
+  else
+    gst_element_set_state (pipeline, pending);
+
+  return is_live;
+}
+
+static void
+set_uri (ClutterGstPlayback *self,
+         const gchar        *uri)
+{
+  ClutterGstPlaybackPrivate *priv = self->priv;
+  GstState state, pending;
+
+  CLUTTER_GST_NOTE (MEDIA, "setting uri %s", uri);
+
+  if (!priv->pipeline)
+    return;
+
+  g_free (priv->uri);
+
+  priv->in_eos = FALSE;
+  priv->in_error = FALSE;
+
+  if (uri)
+    {
+      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, tick_timeout, self);
+        }
+
+      /* try to load subtitles based on the uri of the file */
+      set_subtitle_uri (self, NULL);
+
+      /* reset the states of download buffering */
+      player_clear_download_buffering (self);
+    }
+  else
+    {
+      priv->uri = NULL;
+
+      if (priv->tick_timeout_id)
+       {
+         g_source_remove (priv->tick_timeout_id);
+         priv->tick_timeout_id = 0;
+       }
+
+      if (priv->buffering_timeout_id)
+        {
+          g_source_remove (priv->buffering_timeout_id);
+          priv->buffering_timeout_id = 0;
+        }
+
+      if (priv->download_buffering_element)
+        {
+          g_object_unref (priv->download_buffering_element);
+          priv->download_buffering_element = NULL;
+        }
+
+    }
+
+  priv->can_seek = FALSE;
+  priv->duration = 0.0;
+  priv->stacked_progress = 0.0;
+  priv->target_progress = 0.0;
+
+  CLUTTER_GST_NOTE (MEDIA, "setting URI: %s", uri);
+
+  if (uri)
+    {
+      gst_element_get_state (priv->pipeline, &state, &pending, 0);
+      if (pending)
+        state = pending;
+
+      gst_element_set_state (priv->pipeline, GST_STATE_NULL);
+
+      g_object_set (priv->pipeline, "uri", uri, NULL);
+
+      priv->is_live = is_live_pipeline (priv->pipeline);
+
+      set_subtitle_uri (self, NULL);
+      autoload_subtitle (self, uri);
+
+      gst_element_set_state (priv->pipeline, state);
+
+      priv->is_changing_uri = TRUE;
+    }
+  else
+    {
+      priv->is_idle = TRUE;
+      priv->is_live = FALSE;
+      set_subtitle_uri (self, NULL);
+      gst_element_set_state (priv->pipeline, GST_STATE_NULL);
+      g_object_notify (G_OBJECT (self), "idle");
+    }
+
+  /*
+   * Emit notifications for all these to make sure UI is not showing
+   * any properties of the old URI.
+   */
+  g_object_notify (G_OBJECT (self), "uri");
+  g_object_notify (G_OBJECT (self), "can-seek");
+  g_object_notify (G_OBJECT (self), "duration");
+  g_object_notify (G_OBJECT (self), "progress");
+
+  free_tags_list (&priv->audio_streams);
+  CLUTTER_GST_NOTE (AUDIO_STREAM, "audio-streams changed");
+  g_object_notify (G_OBJECT (self), "audio-streams");
+
+  free_tags_list (&priv->subtitle_tracks);
+  CLUTTER_GST_NOTE (SUBTITLES, "subtitle-tracks changed");
+  g_object_notify (G_OBJECT (self), "subtitle-tracks");
+}
+
+static gdouble
+get_audio_volume (ClutterGstPlayback *self)
+{
+  ClutterGstPlaybackPrivate *priv = self->priv;
+
+  if (!priv->pipeline)
+    return 0.0;
+
+  CLUTTER_GST_NOTE (MEDIA, "get volume: %.02f", priv->volume);
+
+  return priv->volume;
+}
+
+static void
+set_audio_volume (ClutterGstPlayback *self,
+                  gdouble             volume)
+{
+  ClutterGstPlaybackPrivate *priv = self->priv;
+
+    if (!priv->pipeline)
+      return;
+
+  CLUTTER_GST_NOTE (MEDIA, "set volume: %.02f", volume);
+
+  volume = CLAMP (volume, 0.0, 1.0);
+  gst_stream_volume_set_volume (GST_STREAM_VOLUME (priv->pipeline),
+                               GST_STREAM_VOLUME_FORMAT_CUBIC,
+                               volume);
+  g_object_notify (G_OBJECT (self), "audio-volume");
+}
+
+static void
+set_in_seek (ClutterGstPlayback *self,
+             gboolean            seeking)
+{
+  ClutterGstPlaybackPrivate *priv = self->priv;
+
+  priv->in_seek = seeking;
+  g_object_notify (G_OBJECT (self), "in-seek");
+}
+
+
+static void
+set_playing (ClutterGstPlayback *self,
+             gboolean            playing)
+{
+  ClutterGstPlaybackPrivate *priv = self->priv;
+
+  if (!priv->pipeline)
+    return;
+
+  CLUTTER_GST_NOTE (MEDIA, "set playing: %d", playing);
+
+  priv->in_error = FALSE;
+  priv->in_eos = FALSE;
+
+  priv->target_state = playing ? GST_STATE_PLAYING : GST_STATE_PAUSED;
+
+  if (priv->uri)
+    {
+      set_in_seek (self, FALSE);
+
+      gst_element_set_state (priv->pipeline, priv->target_state);
+    }
+  else
+    {
+      if (playing)
+       g_warning ("Unable to start playing: no URI is set");
+    }
+
+  g_object_notify (G_OBJECT (self), "playing");
+  g_object_notify (G_OBJECT (self), "progress");
+}
+
+static gboolean
+get_playing (ClutterGstPlayback *player)
+{
+  ClutterGstPlaybackPrivate *priv = player->priv;
+  GstState state, pending;
+  gboolean playing;
+
+  if (!priv->pipeline)
+    return FALSE;
+
+  gst_element_get_state (priv->pipeline, &state, &pending, 0);
+
+  if (pending)
+    playing = (pending == GST_STATE_PLAYING);
+  else
+    playing = (state == GST_STATE_PLAYING);
+
+  CLUTTER_GST_NOTE (MEDIA, "get playing: %d", playing);
+
+  return playing;
+}
+
+static void
+set_progress (ClutterGstPlayback *self,
+              gdouble             progress)
+{
+  ClutterGstPlaybackPrivate *priv = self->priv;
+  GstQuery *duration_q;
+  gint64 position;
+
+  if (!priv->pipeline)
+    return;
+
+  CLUTTER_GST_NOTE (MEDIA, "set progress: %.02f", progress);
+
+  priv->in_eos = FALSE;
+  priv->target_progress = progress;
+
+  if (priv->in_download_buffering)
+    {
+      /* we clear the virtual_stream_buffer_signalled flag as it's likely we
+       * need to buffer again */
+      priv->virtual_stream_buffer_signalled = 0;
+    }
+
+  if (priv->in_seek || priv->is_idle || priv->is_changing_uri)
+    {
+      /* We can't seek right now, let's save the position where we
+         want to seek and do that later. */
+      CLUTTER_GST_NOTE (MEDIA,
+                        "already seeking/idleing. stacking progress point.");
+      priv->stacked_progress = progress;
+      return;
+    }
+
+  duration_q = gst_query_new_duration (GST_FORMAT_TIME);
+
+  if (gst_element_query (priv->pipeline, duration_q))
+    {
+      gint64 duration = 0;
+
+      gst_query_parse_duration (duration_q, NULL, &duration);
+
+      position = progress * duration;
+    }
+  else
+    position = 0;
+
+  gst_query_unref (duration_q);
+
+  gst_element_seek (priv->pipeline,
+                   1.0,
+                   GST_FORMAT_TIME,
+                   GST_SEEK_FLAG_FLUSH | priv->seek_flags,
+                   GST_SEEK_TYPE_SET,
+                   position,
+                   GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
+
+  set_in_seek (self, TRUE);
+
+  priv->stacked_progress = 0.0;
+
+  CLUTTER_GST_NOTE (MEDIA, "set progress (seeked): %.02f", progress);
+}
+
+static gdouble
+get_progress (ClutterGstPlayback *self)
+{
+  ClutterGstPlaybackPrivate *priv = self->priv;
+  GstQuery *position_q, *duration_q;
+  gdouble progress;
+
+  if (!priv->pipeline)
+    return 0.0;
+
+  /* when hitting an error or after an EOS, playbin has some weird values when
+   * querying the duration and progress. We default to 0.0 on error and 1.0 on
+   * EOS */
+  if (priv->in_error)
+    {
+      CLUTTER_GST_NOTE (MEDIA, "get progress (error): 0.0");
+      return 0.0;
+    }
+
+  if (priv->in_eos)
+    {
+      CLUTTER_GST_NOTE (MEDIA, "get progress (eos): 1.0");
+      return 1.0;
+    }
+
+  /* When seeking, the progress returned by playbin is 0.0. We want that to be
+   * the last known position instead as returning 0.0 will have some ugly
+   * effects, say on a progress bar getting updated from the progress tick. */
+  if (priv->in_seek || priv->is_changing_uri)
+    {
+      CLUTTER_GST_NOTE (MEDIA, "get progress (target): %.02f",
+                        priv->target_progress);
+      return priv->target_progress;
+    }
+
+  position_q = gst_query_new_position (GST_FORMAT_TIME);
+  duration_q = gst_query_new_duration (GST_FORMAT_TIME);
+
+  if (gst_element_query (priv->pipeline, position_q) &&
+      gst_element_query (priv->pipeline, duration_q))
+    {
+      gint64 position, duration;
+
+      position = duration = 0;
+
+      gst_query_parse_position (position_q, NULL, &position);
+      gst_query_parse_duration (duration_q, NULL, &duration);
+
+      progress = CLAMP ((gdouble) position / (gdouble) duration, 0.0, 1.0);
+    }
+  else
+    progress = 0.0;
+
+  gst_query_unref (position_q);
+  gst_query_unref (duration_q);
+
+  CLUTTER_GST_NOTE (MEDIA, "get progress (pipeline): %.02f", progress);
+
+  return progress;
+}
+
+static void
+set_subtitle_font_name (ClutterGstPlayback *self,
+                        const gchar        *font_name)
+{
+  ClutterGstPlaybackPrivate *priv = self->priv;
+
+  if (!priv->pipeline)
+    return;
+
+  CLUTTER_GST_NOTE (MEDIA, "setting subtitle font to %s", font_name);
+
+  g_free (priv->font_name);
+  priv->font_name = g_strdup (font_name);
+  g_object_set (priv->pipeline, "subtitle-font-desc", font_name, NULL);
+}
+
+static gboolean
+player_buffering_timeout (gpointer data)
+{
+  ClutterGstPlayback *self = (ClutterGstPlayback *) data;
+  ClutterGstPlaybackPrivate *priv = self->priv;
+  gdouble start_d, stop_d, seconds_buffered;
+  gint64 start, stop, left;
+  gint buffer_percent;
+  GstState current_state;
+  GstElement *element;
+  GstQuery *query;
+  gboolean res;
+
+  element = priv->download_buffering_element;
+  if (element == NULL)
+    element = priv->pipeline;
+
+  /* queue2 only knows about _PERCENT and _BYTES */
+  query = gst_query_new_buffering (GST_FORMAT_PERCENT);
+  res = gst_element_query (element, query);
+
+  if (res == FALSE)
+    {
+      priv->buffering_timeout_id = 0;
+      player_clear_download_buffering (self);
+      return FALSE;
+    }
+
+  /* signal the current range */
+
+  gst_query_parse_buffering_stats (query, NULL, NULL, NULL, &left);
+  gst_query_parse_buffering_range (query, NULL, &start, &stop, NULL);
+
+  CLUTTER_GST_NOTE (BUFFERING,
+                    "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT
+                    ", buffering left %" G_GINT64_FORMAT, start, stop, left);
+
+  start_d = (gdouble) start / GST_FORMAT_PERCENT_MAX;
+  stop_d = (gdouble) stop / GST_FORMAT_PERCENT_MAX;
+
+  g_signal_emit (self, signals[DOWNLOAD_BUFFERING_SIGNAL], 0, start_d, stop_d);
+
+  /* handle the "virtual stream buffer" and the associated pipeline state.
+   * We pause the pipeline until the content is buffered.
+   */
+  seconds_buffered = priv->duration * (stop_d - start_d);
+  gst_query_parse_buffering_percent (query, NULL, &buffer_percent);
+  priv->buffer_fill = CLAMP ((gdouble) buffer_percent / 100.0, 0.0, 1.0);
+
+  if (priv->buffer_fill != 1.0 || !priv->virtual_stream_buffer_signalled)
+    {
+      CLUTTER_GST_NOTE (BUFFERING, "buffer holds %0.2fs of data, buffer-fill "
+                        "is %.02f", seconds_buffered, priv->buffer_fill);
+
+      g_object_notify (G_OBJECT (self), "buffer-fill");
+
+      if (priv->buffer_fill == 1.0)
+        priv->virtual_stream_buffer_signalled = 1;
+    }
+
+  gst_element_get_state (priv->pipeline, &current_state, NULL, 0);
+  if (priv->buffer_fill < 1.0)
+    {
+      if (current_state != GST_STATE_PAUSED)
+        {
+          CLUTTER_GST_NOTE (BUFFERING, "pausing the pipeline");
+          gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
+        }
+    }
+  else
+    {
+      if (current_state != priv->target_state)
+        {
+          CLUTTER_GST_NOTE (BUFFERING, "restoring the pipeline");
+          gst_element_set_state (priv->pipeline, priv->target_state);
+        }
+    }
+
+  /* the file has finished downloading */
+  if (left == G_GINT64_CONSTANT (0))
+    {
+      priv->buffering_timeout_id = 0;
+
+      player_clear_download_buffering (self);
+      gst_query_unref (query);
+      return FALSE;
+    }
+
+  gst_query_unref (query);
+  return TRUE;
+}
+
+static void
+bus_message_error_cb (GstBus             *bus,
+                      GstMessage         *message,
+                      ClutterGstPlayback *self)
+{
+  ClutterGstPlaybackPrivate *priv = self->priv;
+  GError *error = NULL;
+
+  gst_element_set_state (priv->pipeline, GST_STATE_NULL);
+
+  gst_message_parse_error (message, &error, NULL);
+  g_signal_emit_by_name (self, "error", error);
+  g_error_free (error);
+
+  priv->is_idle = TRUE;
+  g_object_notify (G_OBJECT (self), "idle");
+}
+
+/*
+ * This is what's intented in the EOS callback:
+ *   - receive EOS from playbin
+ *   - fire the EOS signal, the user can install a signal handler to loop the
+ *     video for instance.
+ *   - after having emitted the signal, check the state of the pipeline
+ *   - if the pipeline has been set back to playing or pause, don't touch the
+ *     idle state. This will avoid drawing a frame (or more) with the idle
+ *     material when looping
+ */
+static void
+bus_message_eos_cb (GstBus             *bus,
+                    GstMessage         *message,
+                    ClutterGstPlayback *self)
+{
+  ClutterGstPlaybackPrivate *priv = self->priv;
+  GstState state, pending;
+
+  priv->in_eos = TRUE;
+
+  gst_element_set_state (priv->pipeline, GST_STATE_READY);
+
+  g_signal_emit_by_name (self, "eos");
+  g_object_notify (G_OBJECT (self), "progress");
+
+  gst_element_get_state (priv->pipeline, &state, &pending, 0);
+  if (pending)
+    state = pending;
+
+  if (!(state == GST_STATE_PLAYING || state == GST_STATE_PAUSED))
+    {
+      priv->is_idle = TRUE;
+      g_object_notify (G_OBJECT (self), "idle");
+    }
+}
+
+static void
+bus_message_buffering_cb (GstBus             *bus,
+                          GstMessage         *message,
+                          ClutterGstPlayback *self)
+{
+  ClutterGstPlaybackPrivate *priv = self->priv;
+  GstBufferingMode mode;
+  GstState current_state;
+  gint buffer_percent;
+
+  gst_message_parse_buffering_stats (message, &mode, NULL, NULL, NULL);
+
+  if (mode != GST_BUFFERING_DOWNLOAD)
+    priv->in_download_buffering = FALSE;
+
+  switch (mode)
+    {
+    case GST_BUFFERING_LIVE:
+    case GST_BUFFERING_STREAM:
+      gst_message_parse_buffering (message, &buffer_percent);
+      priv->buffer_fill = CLAMP ((gdouble) buffer_percent / 100.0, 0.0, 1.0);
+
+      CLUTTER_GST_NOTE (BUFFERING, "buffer-fill: %.02f", priv->buffer_fill);
+
+      /* no state management needed for live pipelines */
+      if (!priv->is_live)
+        {
+          /* The playbin documentation says that we need to pause the pipeline
+           * when there's not enough data yet. We try to limit the calls to
+           * gst_element_set_state() */
+          gst_element_get_state (priv->pipeline, &current_state, NULL, 0);
+
+          if (priv->buffer_fill < 1.0)
+            {
+              if (current_state != GST_STATE_PAUSED)
+                {
+                  CLUTTER_GST_NOTE (BUFFERING, "pausing the pipeline");
+                  gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
+                }
+            }
+          else
+            {
+              if (current_state != priv->target_state)
+                {
+                  CLUTTER_GST_NOTE (BUFFERING, "restoring the pipeline");
+                  gst_element_set_state (priv->pipeline, priv->target_state);
+                }
+            }
+        }
+
+      g_object_notify (G_OBJECT (self), "buffer-fill");
+      break;
+
+    case GST_BUFFERING_DOWNLOAD:
+      /* we rate limit the messages from GStreamer for a usage in a UI (we
+       * don't want *that* many updates). This is done by installing an idle
+       * handler querying the buffer range and sending a signal from there */
+
+      if (priv->in_download_buffering)
+        break;
+
+      /* install the querying idle handler the first time we receive a download
+       * buffering message */
+      player_configure_buffering_timeout (self, BUFFERING_TIMEOUT);
+
+      /* pause the stream. the idle timeout will set the target state when
+       * having received enough data. We'll use buffer_fill as a "virtual
+       * stream buffer" to signal the application we're buffering until we
+       * can play back from the downloaded stream. */
+      gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
+      priv->buffer_fill = 0.0;
+      g_object_notify (G_OBJECT (self), "buffer-fill");
+
+      priv->download_buffering_element = g_object_ref (message->src);
+      priv->in_download_buffering = TRUE;
+      priv->virtual_stream_buffer_signalled = 0;
+      break;
+
+    case GST_BUFFERING_TIMESHIFT:
+    default:
+      g_warning ("Buffering mode %d not handled", mode);
+      break;
+    }
+}
+
+static void
+on_source_changed (GstElement         *pipeline,
+                   GParamSpec         *pspec,
+                   ClutterGstPlayback *self)
+{
+  ClutterGstPlaybackPrivate *priv = self->priv;
+
+  player_set_user_agent (self, priv->user_agent);
+}
+
+static void
+query_duration (ClutterGstPlayback *self)
+{
+  ClutterGstPlaybackPrivate *priv = self->priv;
+  gboolean success;
+  gint64 duration;
+  gdouble new_duration, difference;
+
+  success = gst_element_query_duration (priv->pipeline,
+                                        GST_FORMAT_TIME,
+                                        &duration);
+  if (G_UNLIKELY (success != TRUE))
+    return;
+
+  new_duration = (gdouble) duration / GST_SECOND;
+
+  /* while we store the new duration if it sligthly changes, the duration
+   * signal is sent only if the new duration is at least one second different
+   * from the old one (as the duration signal is mainly used to update the
+   * time displayed in a UI */
+  difference = ABS (priv->duration - new_duration);
+  if (difference > 1e-3)
+    {
+      CLUTTER_GST_NOTE (MEDIA, "duration: %.02f", new_duration);
+      priv->duration = new_duration;
+
+      if (difference > 1.0)
+        g_object_notify (G_OBJECT (self), "duration");
+    }
+}
+
+static void
+bus_message_duration_changed_cb (GstBus             *bus,
+                                 GstMessage         *message,
+                                 ClutterGstPlayback *self)
+{
+  /* GstElements send a duration-changed message on the bus to signal
+   * that the duration has changed and should be re-queried */
+  query_duration (self);
+}
+
+static void
+bus_message_state_change_cb (GstBus             *bus,
+                             GstMessage         *message,
+                             ClutterGstPlayback *self)
+{
+  ClutterGstPlaybackPrivate *priv = self->priv;
+  GstState old_state, new_state;
+  gpointer src;
+
+  src = GST_MESSAGE_SRC (message);
+  if (src != priv->pipeline)
+    return;
+
+  gst_message_parse_state_changed (message, &old_state, &new_state, NULL);
+
+  CLUTTER_GST_NOTE (MEDIA, "state change:  %s -> %s",
+                    gst_state_to_string (old_state),
+                    gst_state_to_string (new_state));
+
+  if (old_state == new_state)
+    return;
+
+  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 (priv->pipeline, query))
+        {
+          gboolean can_seek = FALSE;
+
+          gst_query_parse_seeking (query, NULL, &can_seek,
+                                   NULL,
+                                   NULL);
+
+          priv->can_seek = (can_seek == TRUE) ? TRUE : FALSE;
+        }
+      else
+        {
+         /* could not query for ability to seek by querying the
+           * pipeline; let's crudely try by using the URI
+          */
+         if (priv->uri && g_str_has_prefix (priv->uri, "http://";))
+            priv->can_seek = FALSE;
+          else
+            priv->can_seek = TRUE;
+       }
+
+      gst_query_unref (query);
+
+      CLUTTER_GST_NOTE (MEDIA, "can-seek: %d", priv->can_seek);
+
+      g_object_notify (G_OBJECT (self), "can-seek");
+
+      query_duration (self);
+    }
+
+  /* is_idle controls the drawing with the idle material */
+  if (new_state == GST_STATE_NULL)
+    {
+      priv->is_idle = TRUE;
+      g_object_notify (G_OBJECT (self), "idle");
+    }
+  else if (new_state == GST_STATE_PLAYING)
+    {
+      priv->is_idle = FALSE;
+      priv->is_changing_uri = FALSE;
+      g_object_notify (G_OBJECT (self), "idle");
+    }
+
+  if (!priv->is_idle)
+    {
+      if (priv->stacked_progress)
+        {
+          set_progress (self, priv->stacked_progress);
+        }
+    }
+}
+
+static void
+bus_message_async_done_cb (GstBus             *bus,
+                           GstMessage         *message,
+                           ClutterGstPlayback *self)
+{
+  ClutterGstPlaybackPrivate *priv = self->priv;
+
+  if (priv->in_seek)
+    {
+      g_object_notify (G_OBJECT (self), "progress");
+
+      set_in_seek (self, FALSE);
+
+      if (priv->stacked_progress)
+        {
+          set_progress (self, priv->stacked_progress);
+        }
+    }
+}
+
+static gboolean
+on_volume_changed_main_context (gpointer data)
+{
+  ClutterGstPlayback *self = CLUTTER_GST_PLAYBACK (data);
+  ClutterGstPlaybackPrivate *priv = self->priv;
+  gdouble volume;
+
+  volume =
+    gst_stream_volume_get_volume (GST_STREAM_VOLUME (priv->pipeline),
+                                  GST_STREAM_VOLUME_FORMAT_CUBIC);
+  priv->volume = volume;
+
+  g_object_notify (G_OBJECT (self), "audio-volume");
+
+  g_object_unref (self);
+
+  return FALSE;
+}
+
+/* playbin proxies the volume property change notification directly from
+ * the element having the "volume" property. This means this callback is
+ * called from the thread that runs the element, potentially different from
+ * the main thread */
+static void
+on_volume_changed (GstElement         *pipeline,
+                  GParamSpec         *pspec,
+                  ClutterGstPlayback *self)
+{
+  g_idle_add (on_volume_changed_main_context, g_object_ref (self));
+}
+
+static GList *
+get_tags (GstElement  *pipeline,
+          const gchar *property_name,
+          const gchar *action_signal)
+{
+  GList *ret = NULL;
+  gint i, n;
+
+  g_object_get (G_OBJECT (pipeline), property_name, &n, NULL);
+  if (n == 0)
+    return NULL;
+
+  for (i = 0; i < n; i++)
+    {
+      GstTagList *tags = NULL;
+
+      g_signal_emit_by_name (G_OBJECT (pipeline), action_signal, i, &tags);
+
+      ret = g_list_prepend (ret, tags);
+    }
+
+  return g_list_reverse (ret);
+}
+
+static gboolean
+on_audio_changed_main_context (gpointer data)
+{
+  ClutterGstPlayback *self = CLUTTER_GST_PLAYBACK (data);
+  ClutterGstPlaybackPrivate *priv = self->priv;
+
+  free_tags_list (&priv->audio_streams);
+  priv->audio_streams = get_tags (priv->pipeline, "n-audio", "get-audio-tags");
+
+  CLUTTER_GST_NOTE (AUDIO_STREAM, "audio-streams changed");
+
+  g_object_notify (G_OBJECT (self), "audio-streams");
+
+  g_object_unref (self);
+
+  return FALSE;
+}
+
+/* same explanation as for notify::volume's usage of g_idle_add() */
+static void
+on_audio_changed (GstElement         *pipeline,
+                  ClutterGstPlayback *self)
+{
+  g_idle_add (on_audio_changed_main_context, g_object_ref (self));
+}
+
+static void
+on_audio_tags_changed (GstElement         *pipeline,
+                       gint                stream,
+                       ClutterGstPlayback *self)
+{
+  gint current_stream;
+
+  g_object_get (G_OBJECT (pipeline), "current-audio", &current_stream, NULL);
+
+  if (current_stream != stream)
+    return;
+
+  g_idle_add (on_audio_changed_main_context, g_object_ref (self));
+}
+
+static gboolean
+on_current_audio_changed_main_context (gpointer data)
+{
+  ClutterGstPlayback *self = CLUTTER_GST_PLAYBACK (data);
+
+  CLUTTER_GST_NOTE (AUDIO_STREAM, "audio stream changed");
+  g_object_notify (G_OBJECT (self), "audio-stream");
+
+  g_object_unref (self);
+
+  return FALSE;
+}
+
+static void
+on_current_audio_changed (GstElement         *pipeline,
+                          GParamSpec         *pspec,
+                          ClutterGstPlayback *self)
+{
+  g_idle_add (on_current_audio_changed_main_context, g_object_ref (self));
+}
+
+static gboolean
+on_text_changed_main_context (gpointer data)
+{
+  ClutterGstPlayback *self = CLUTTER_GST_PLAYBACK (data);
+  ClutterGstPlaybackPrivate *priv = self->priv;
+
+  free_tags_list (&priv->subtitle_tracks);
+  priv->subtitle_tracks = get_tags (priv->pipeline, "n-text", "get-text-tags");
+
+  CLUTTER_GST_NOTE (AUDIO_STREAM, "subtitle-tracks changed");
+
+  g_object_notify (G_OBJECT (self), "subtitle-tracks");
+
+  g_object_unref (self);
+
+  return FALSE;
+}
+
+/* same explanation as for notify::volume's usage of g_idle_add() */
+static void
+on_text_changed (GstElement         *pipeline,
+                 ClutterGstPlayback *self)
+{
+  g_idle_add (on_text_changed_main_context, g_object_ref (self));
+}
+
+static void
+on_text_tags_changed (GstElement         *pipeline,
+                      gint                stream,
+                      ClutterGstPlayback *self)
+{
+  g_idle_add (on_text_changed_main_context, g_object_ref (self));
+}
+
+static gboolean
+on_current_text_changed_main_context (gpointer data)
+{
+  ClutterGstPlayback *self = CLUTTER_GST_PLAYBACK (data);
+
+  CLUTTER_GST_NOTE (AUDIO_STREAM, "text stream changed");
+  g_object_notify (G_OBJECT (self), "subtitle-track");
+
+  g_object_unref (self);
+
+  return FALSE;
+}
+
+static void
+on_current_text_changed (GstElement         *pipeline,
+                         GParamSpec         *pspec,
+                         ClutterGstPlayback *self)
+{
+  g_idle_add (on_current_text_changed_main_context, g_object_ref (self));
+}
+
+/**/
+
+static ClutterGstFrame *
+clutter_gst_playback_get_frame (ClutterGstPlayer *self)
+{
+  ClutterGstPlaybackPrivate *priv = CLUTTER_GST_PLAYBACK (self)->priv;
+
+  return priv->current_frame;
+}
+
+static GstElement *
+clutter_gst_playback_get_pipeline (ClutterGstPlayer *self)
+{
+  ClutterGstPlaybackPrivate *priv = CLUTTER_GST_PLAYBACK (self)->priv;
+
+  return priv->pipeline;
+}
+
+static gboolean
+clutter_gst_playback_get_idle (ClutterGstPlayer *self)
+{
+  ClutterGstPlaybackPrivate *priv = CLUTTER_GST_PLAYBACK (self)->priv;
+
+  return priv->is_idle;
+}
+
+static gdouble
+clutter_gst_playback_get_audio_volume (ClutterGstPlayer *self)
+{
+  return get_audio_volume (CLUTTER_GST_PLAYBACK (self));
+}
+
+static void
+clutter_gst_playback_set_audio_volume (ClutterGstPlayer *self,
+                                       gdouble           volume)
+{
+  set_audio_volume (CLUTTER_GST_PLAYBACK (self), volume);
+}
+
+static gboolean
+clutter_gst_playback_get_playing (ClutterGstPlayer *self)
+{
+  return get_playing (CLUTTER_GST_PLAYBACK (self));
+}
+
+static void
+clutter_gst_playback_set_playing (ClutterGstPlayer *self,
+                                  gboolean          playing)
+{
+  set_playing (CLUTTER_GST_PLAYBACK (self), playing);
+}
+
+static void
+player_iface_init (ClutterGstPlayerIface *iface)
+{
+  iface->get_frame = clutter_gst_playback_get_frame;
+  iface->get_pipeline = clutter_gst_playback_get_pipeline;
+  iface->get_idle = clutter_gst_playback_get_idle;
+
+  iface->get_audio_volume = clutter_gst_playback_get_audio_volume;
+  iface->set_audio_volume = clutter_gst_playback_set_audio_volume;
+
+  iface->get_playing = clutter_gst_playback_get_playing;
+  iface->set_playing = clutter_gst_playback_set_playing;
+}
+
+/**/
+
+static void
+clutter_gst_playback_get_property (GObject    *object,
+                                   guint       property_id,
+                                   GValue     *value,
+                                   GParamSpec *pspec)
+{
+  ClutterGstPlayback *self;
+  ClutterGstPlaybackPrivate *priv = self->priv;
+  gchar *str;
+
+  switch (property_id)
+    {
+    case PROP_URI:
+      g_value_set_string (value, priv->uri);
+      break;
+
+    case PROP_PLAYING:
+      g_value_set_boolean (value, get_playing (self));
+      break;
+
+    case PROP_PROGRESS:
+      g_value_set_double (value, get_progress (self));
+      break;
+
+    case PROP_SUBTITLE_URI:
+      g_object_get (priv->pipeline, "suburi", &str, NULL);
+      g_value_take_string (value, str);
+      break;
+
+    case PROP_SUBTITLE_FONT_NAME:
+      g_value_set_string (value, priv->font_name);
+      break;
+
+    case PROP_AUDIO_VOLUME:
+      g_value_set_double (value, get_audio_volume (self));
+      break;
+
+    case PROP_CAN_SEEK:
+      g_value_set_boolean (value, priv->can_seek);
+      break;
+
+    case PROP_BUFFER_FILL:
+      g_value_set_double (value, priv->buffer_fill);
+      break;
+
+    case PROP_DURATION:
+      g_value_set_double (value, priv->duration);
+      break;
+
+    case PROP_IDLE:
+      g_value_set_boolean (value, priv->is_idle);
+      break;
+
+    case PROP_USER_AGENT:
+      {
+        gchar *user_agent;
+
+        user_agent = clutter_gst_playback_get_user_agent (self);
+        g_value_take_string (value, user_agent);
+      }
+      break;
+
+    case PROP_SEEK_FLAGS:
+      {
+        ClutterGstSeekFlags seek_flags;
+
+        seek_flags = clutter_gst_playback_get_seek_flags (self);
+        g_value_set_flags (value, seek_flags);
+      }
+      break;
+
+    case PROP_AUDIO_STREAMS:
+      g_value_set_pointer (value, priv->audio_streams);
+      break;
+
+    case PROP_AUDIO_STREAM:
+      {
+        gint index_;
+
+        index_ = clutter_gst_playback_get_audio_stream (self);
+        g_value_set_int (value, index_);
+      }
+      break;
+
+    case PROP_SUBTITLE_TRACKS:
+      g_value_set_pointer (value, priv->subtitle_tracks);
+      break;
+
+    case PROP_SUBTITLE_TRACK:
+      {
+        gint index_;
+
+        index_ = clutter_gst_playback_get_subtitle_track (self);
+        g_value_set_int (value, index_);
+      }
+      break;
+
+    case PROP_IN_SEEK:
+      g_value_set_boolean (value, priv->in_seek);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+clutter_gst_playback_set_property (GObject      *object,
+                                   guint         property_id,
+                                   const GValue *value,
+                                   GParamSpec   *pspec)
+{
+  ClutterGstPlayback *self = CLUTTER_GST_PLAYBACK (object);
+
+  switch (property_id)
+    {
+    case PROP_URI:
+      set_uri (self, g_value_get_string (value));
+      break;
+
+    case PROP_PLAYING:
+      set_playing (self, g_value_get_boolean (value));
+      break;
+
+    case PROP_PROGRESS:
+      set_progress (self, g_value_get_double (value));
+      break;
+
+    case PROP_SUBTITLE_URI:
+      set_subtitle_uri (self, g_value_get_string (value));
+      break;
+
+    case PROP_SUBTITLE_FONT_NAME:
+      set_subtitle_font_name (self, g_value_get_string (value));
+      break;
+
+    case PROP_AUDIO_VOLUME:
+      set_audio_volume (self, g_value_get_double (value));
+      break;
+
+    case PROP_USER_AGENT:
+      clutter_gst_playback_set_user_agent (self,
+                                           g_value_get_string (value));
+      break;
+
+    case PROP_SEEK_FLAGS:
+      clutter_gst_playback_set_seek_flags (self,
+                                           g_value_get_flags (value));
+      break;
+
+    case PROP_AUDIO_STREAM:
+      clutter_gst_playback_set_audio_stream (self,
+                                             g_value_get_int (value));
+      break;
+
+    case PROP_SUBTITLE_TRACK:
+      clutter_gst_playback_set_subtitle_track (self,
+                                               g_value_get_int (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+clutter_gst_playback_dispose (GObject *object)
+{
+  ClutterGstPlaybackPrivate *priv = CLUTTER_GST_PLAYBACK (object)->priv;
+
+  if (priv->tick_timeout_id)
+    {
+      g_source_remove (priv->tick_timeout_id);
+      priv->tick_timeout_id = 0;
+    }
+
+  if (priv->buffering_timeout_id)
+    {
+      g_source_remove (priv->buffering_timeout_id);
+      priv->buffering_timeout_id = 0;
+    }
+
+  if (priv->download_buffering_element)
+    g_clear_object (&priv->download_buffering_element);
+
+  if (priv->bus)
+    {
+      gst_bus_remove_signal_watch (priv->bus);
+      priv->bus = NULL;
+    }
+
+  if (priv->pipeline)
+    {
+      gst_element_set_state (priv->pipeline, GST_STATE_NULL);
+      g_clear_object (&priv->pipeline);
+    }
+
+  if (priv->current_frame)
+    {
+      g_boxed_free (CLUTTER_GST_TYPE_FRAME, priv->current_frame);
+      priv->current_frame = NULL;
+    }
+
+  g_free (priv->uri);
+  g_free (priv->font_name);
+  g_free (priv->user_agent);
+  priv->uri = priv->font_name = priv->user_agent = NULL;
+  free_tags_list (&priv->audio_streams);
+  free_tags_list (&priv->subtitle_tracks);
+
+  G_OBJECT_CLASS (clutter_gst_playback_parent_class)->dispose (object);
+}
+
+static void
+clutter_gst_playback_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (clutter_gst_playback_parent_class)->finalize (object);
+}
+
+static void
+clutter_gst_playback_class_init (ClutterGstPlaybackClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GParamSpec *pspec;
+
+  g_type_class_add_private (klass, sizeof (ClutterGstPlaybackPrivate));
+
+  object_class->get_property = clutter_gst_playback_get_property;
+  object_class->set_property = clutter_gst_playback_set_property;
+  object_class->dispose = clutter_gst_playback_dispose;
+  object_class->finalize = clutter_gst_playback_finalize;
+
+  /**
+   * ClutterGstPlayback:uri:
+   *
+   * The location of a media file, expressed as a valid URI.
+   */
+  pspec = g_param_spec_string ("uri",
+                               "URI",
+                               "URI of a media file",
+                               NULL,
+                               CLUTTER_GST_PARAM_READWRITE |
+                               G_PARAM_DEPRECATED);
+  g_object_class_install_property (object_class, PROP_URI, pspec);
+
+  /**
+   * ClutterGstPlayback:progress:
+   *
+   * The current progress of the playback, as a normalized
+   * value between 0.0 and 1.0.
+   */
+  pspec = g_param_spec_double ("progress",
+                               "Progress",
+                               "Current progress of the playback",
+                               0.0, 1.0, 0.0,
+                               CLUTTER_GST_PARAM_READWRITE |
+                               G_PARAM_DEPRECATED);
+  g_object_class_install_property (object_class, PROP_PROGRESS, pspec);
+
+  /**
+   * ClutterGstPlayback:subtitle-uri:
+   *
+   * The location of a subtitle file, expressed as a valid URI.
+   */
+  pspec = g_param_spec_string ("subtitle-uri",
+                               "Subtitle URI",
+                               "URI of a subtitle file",
+                               NULL,
+                               CLUTTER_GST_PARAM_READWRITE |
+                               G_PARAM_DEPRECATED);
+  g_object_class_install_property (object_class, PROP_SUBTITLE_URI, pspec);
+
+  /**
+   * ClutterGstPlayback:subtitle-font-name:
+   *
+   * The font used to display subtitles. The font description has to
+   * follow the same grammar as the one recognized by
+   * pango_font_description_from_string().
+   */
+  pspec = g_param_spec_string ("subtitle-font-name",
+                               "Subtitle Font Name",
+                               "The font used to display subtitles",
+                               NULL,
+                               CLUTTER_GST_PARAM_READWRITE |
+                               G_PARAM_DEPRECATED);
+  g_object_class_install_property (object_class, PROP_SUBTITLE_FONT_NAME, pspec);
+
+  /**
+   * ClutterGstPlayback:can-seek:
+   *
+   * Whether the current stream is seekable.
+   */
+  pspec = g_param_spec_boolean ("can-seek",
+                                "Can Seek",
+                                "Whether the current stream is seekable",
+                                FALSE,
+                                CLUTTER_GST_PARAM_READABLE |
+                                G_PARAM_DEPRECATED);
+  g_object_class_install_property (object_class, PROP_CAN_SEEK, pspec);
+
+  /**
+   * ClutterGstPlayback:buffer-fill:
+   *
+   * The fill level of the buffer for the current stream,
+   * as a value between 0.0 and 1.0.
+   */
+  pspec = g_param_spec_double ("buffer-fill",
+                               "Buffer Fill",
+                               "The fill level of the buffer",
+                               0.0, 1.0, 0.0,
+                               CLUTTER_GST_PARAM_READABLE |
+                               G_PARAM_DEPRECATED);
+  g_object_class_install_property (object_class, PROP_BUFFER_FILL, pspec);
+
+  /**
+   * ClutterGstPlayback:duration:
+   *
+   * The duration of the current stream, in seconds
+   */
+  pspec = g_param_spec_double ("duration",
+                               "Duration",
+                               "The duration of the stream, in seconds",
+                               0, G_MAXDOUBLE, 0,
+                               CLUTTER_GST_PARAM_READABLE);
+  g_object_class_install_property (object_class, PROP_DURATION, pspec);
+
+  /**
+   * ClutterGstPlayback:user-agent:
+   *
+   * The User Agent used by #ClutterGstPlayback with network protocols.
+   *
+   * Since: 1.4
+   */
+  pspec = g_param_spec_string ("user-agent",
+                               "User Agent",
+                               "User Agent used with network protocols",
+                               NULL,
+                               CLUTTER_GST_PARAM_READWRITE);
+  g_object_class_install_property (object_class, PROP_USER_AGENT, pspec);
+
+  /**
+   * ClutterGstPlayback:seek-flags:
+   *
+   * Flags to use when seeking.
+   *
+   * Since: 1.4
+   */
+  pspec = g_param_spec_flags ("seek-flags",
+                              "Seek Flags",
+                              "Flags to use when seeking",
+                              CLUTTER_GST_TYPE_SEEK_FLAGS,
+                              CLUTTER_GST_SEEK_FLAG_NONE,
+                              CLUTTER_GST_PARAM_READWRITE);
+  g_object_class_install_property (object_class, PROP_SEEK_FLAGS, pspec);
+
+  /**
+   * ClutterGstPlayback:audio-streams:
+   *
+   * List of audio streams available on the current media.
+   *
+   * Since: 1.4
+   */
+  pspec = g_param_spec_pointer ("audio-streams",
+                                "Audio Streams",
+                                "List of the audio streams of the media",
+                                CLUTTER_GST_PARAM_READABLE);
+  g_object_class_install_property (object_class, PROP_AUDIO_STREAMS, pspec);
+
+  /**
+   * ClutterGstPlayback:audio-stream:
+   *
+   * Index of the current audio stream.
+   *
+   * Since: 1.4
+   */
+  pspec = g_param_spec_int ("audio-stream",
+                            "Audio Stream",
+                            "Index of the current audio stream",
+                            -1, G_MAXINT, -1,
+                            CLUTTER_GST_PARAM_READWRITE);
+  g_object_class_install_property (object_class, PROP_AUDIO_STREAM, pspec);
+
+  /**
+   * ClutterGstPlayback:subtitle-tracks:
+   *
+   * List of subtitle tracks available.
+   *
+   * Since: 1.4
+   */
+  pspec = g_param_spec_pointer ("subtitle-tracks",
+                                "Subtitles Tracks",
+                                "List of the subtitles tracks of the media",
+                                CLUTTER_GST_PARAM_READABLE);
+  g_object_class_install_property (object_class, PROP_SUBTITLE_TRACKS, pspec);
+
+  /**
+   * ClutterGstPlayback:subtitle-track:
+   *
+   * Current subtitle track being displayed.
+   *
+   * Since: 1.4
+   */
+  pspec = g_param_spec_int ("subtitle-track",
+                            "Subtitle Track",
+                            "Index of the current subtitles track",
+                            -1, G_MAXINT, -1,
+                            CLUTTER_GST_PARAM_READWRITE);
+  g_object_class_install_property (object_class, PROP_SUBTITLE_TRACK, pspec);
+
+  /**
+   * ClutterGstPlayback:in-seek:
+   *
+   * Whether or not the stream is being seeked.
+   *
+   * Since: 1.6
+   */
+  pspec = g_param_spec_boolean ("in-seek",
+                                "In seek mode",
+                                "If currently seeking",
+                                FALSE,
+                                CLUTTER_GST_PARAM_READABLE);
+  g_object_class_install_property (object_class, PROP_IN_SEEK, pspec);
+
+
+  g_object_class_override_property (object_class,
+                                    PROP_IDLE, "idle");
+  g_object_class_override_property (object_class,
+                                    PROP_PLAYING, "playing");
+  g_object_class_override_property (object_class,
+                                    PROP_AUDIO_VOLUME, "audio-volume");
+
+
+  /* Signals */
+
+  /**
+   * ClutterGstPlayback::download-buffering:
+   * @player: the #ClutterGstPlayback instance that received the signal
+   * @start: start position of the buffering
+   * @stop: start position of the buffering
+   *
+   * The ::download-buffering signal is emitted each time their an
+   * update about the buffering of the current media.
+   *
+   * Since: 1.4
+   */
+  signals[DOWNLOAD_BUFFERING_SIGNAL] =
+    g_signal_new ("download-buffering",
+                  CLUTTER_GST_TYPE_PLAYBACK,
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (ClutterGstPlaybackClass,
+                                   download_buffering),
+                  NULL, NULL,
+                  _clutter_gst_marshal_VOID__DOUBLE_DOUBLE,
+                  G_TYPE_NONE, 2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
+}
+
+static void
+_new_frame_from_pipeline (CoglGstVideoSink *sink, ClutterGstPlayback *self)
+{
+  ClutterGstPlaybackPrivate *priv = self->priv;
+
+  clutter_gst_util_update_frame (CLUTTER_GST_PLAYER (self),
+                                 &priv->current_frame,
+                                 cogl_gst_video_sink_get_pipeline (sink));
+}
+
+static void
+_ready_from_pipeline (CoglGstVideoSink *sink, ClutterGstPlayback *self)
+{
+
+  ClutterGstPlaybackPrivate *priv = self->priv;
+
+  g_signal_emit_by_name (self, "ready");
+
+  /* clutter_gst_util_update_frame (CLUTTER_GST_PLAYER (self), */
+  /*                                &priv->current_frame, */
+  /*                                cogl_gst_video_sink_get_pipeline (sink)); */
+}
+
+static GstElement *
+get_pipeline (ClutterGstPlayback *self)
+{
+  ClutterGstPlaybackPrivate *priv = self->priv;
+  GstElement *pipeline, *audio_sink;
+  CoglGstVideoSink *video_sink;
+
+  pipeline = gst_element_factory_make ("playbin", "pipeline");
+  if (!pipeline)
+    {
+      g_critical ("Unable to create playbin element");
+      return NULL;
+    }
+
+  audio_sink = gst_element_factory_make ("gconfaudiosink", "audio-sink");
+  if (!audio_sink)
+    {
+      audio_sink = gst_element_factory_make ("autoaudiosink", "audio-sink");
+      if (!audio_sink)
+       {
+         audio_sink = gst_element_factory_make ("alsasink", "audio-sink");
+         g_warning ("Could not create a GST audio_sink. "
+                    "Audio unavailable.");
+
+          /* do we even need to bother? */
+         if (!audio_sink)
+           audio_sink = gst_element_factory_make ("fakesink", "audio-sink");
+       }
+    }
+
+  video_sink = cogl_gst_video_sink_new (clutter_backend_get_cogl_context (clutter_get_default_backend ()));
+  /* gst_element_factory_make ("coglsink", "video-sink"); */
+
+  g_signal_connect (video_sink, "new-frame",
+                    G_CALLBACK (_new_frame_from_pipeline), self);
+  g_signal_connect (video_sink, "pipeline-ready",
+                    G_CALLBACK (_ready_from_pipeline), self);
+
+  g_object_set (G_OBJECT (pipeline),
+                "audio-sink", audio_sink,
+                "video-sink", video_sink,
+                "subtitle-font-desc", "Sans 16",
+                NULL);
+
+  return pipeline;
+}
+
+static void
+clutter_gst_playback_init (ClutterGstPlayback *self)
+{
+  ClutterGstPlaybackPrivate *priv;
+
+  self->priv = priv = GST_PLAYBACK_PRIVATE (self);
+
+  priv->is_idle = TRUE;
+  priv->in_seek = FALSE;
+  priv->is_changing_uri = FALSE;
+  priv->in_download_buffering = FALSE;
+
+  priv->pipeline = get_pipeline (self);
+  g_assert (priv->pipeline != NULL);
+
+  g_signal_connect (priv->pipeline, "notify::source",
+                    G_CALLBACK (on_source_changed), self);
+
+  /* We default to not playing until someone calls set_playing(TRUE) */
+  priv->target_state = GST_STATE_PAUSED;
+
+  /* Default to a fast seek, ie. same effect than set_seek_flags (NONE); */
+  priv->seek_flags = GST_SEEK_FLAG_KEY_UNIT;
+
+  priv->bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline));
+
+  gst_bus_add_signal_watch (priv->bus);
+
+  g_signal_connect_object (priv->bus, "message::error",
+                          G_CALLBACK (bus_message_error_cb),
+                          self, 0);
+  g_signal_connect_object (priv->bus, "message::eos",
+                          G_CALLBACK (bus_message_eos_cb),
+                          self, 0);
+  g_signal_connect_object (priv->bus, "message::buffering",
+                          G_CALLBACK (bus_message_buffering_cb),
+                          self, 0);
+  g_signal_connect_object (priv->bus, "message::duration-changed",
+                          G_CALLBACK (bus_message_duration_changed_cb),
+                          self, 0);
+  g_signal_connect_object (priv->bus, "message::state-changed",
+                          G_CALLBACK (bus_message_state_change_cb),
+                          self, 0);
+  g_signal_connect_object (priv->bus, "message::async-done",
+                           G_CALLBACK (bus_message_async_done_cb),
+                           self, 0);
+
+  g_signal_connect (priv->pipeline, "notify::volume",
+                   G_CALLBACK (on_volume_changed),
+                    self);
+
+  g_signal_connect (priv->pipeline, "audio-changed",
+                    G_CALLBACK (on_audio_changed),
+                    self);
+  g_signal_connect (priv->pipeline, "audio-tags-changed",
+                    G_CALLBACK (on_audio_tags_changed),
+                    self);
+  g_signal_connect (priv->pipeline, "notify::current-audio",
+                    G_CALLBACK (on_current_audio_changed),
+                    self);
+
+  g_signal_connect (priv->pipeline, "text-changed",
+                    G_CALLBACK (on_text_changed),
+                    self);
+  g_signal_connect (priv->pipeline, "text-tags-changed",
+                    G_CALLBACK (on_text_tags_changed),
+                    self);
+  g_signal_connect (priv->pipeline, "notify::current-text",
+                    G_CALLBACK (on_current_text_changed),
+                    self);
+
+#if defined(CLUTTER_WINDOWING_X11) && defined (HAVE_HW_DECODER_SUPPORT)
+  gst_bus_set_sync_handler (priv->bus, on_sync_message,
+      clutter_x11_get_default_display (), NULL);
+#endif
+
+  gst_object_unref (GST_OBJECT (priv->bus));
+}
+
+ClutterGstPlayback *
+clutter_gst_playback_new (void)
+{
+  return g_object_new (CLUTTER_GST_TYPE_PLAYBACK, NULL);
+}
+
+/**
+ * clutter_gst_playback_set_uri:
+ * @self: a #ClutterGstPlayback
+ * @uri: the URI of the media stream
+ *
+ * Sets the URI of @self to @uri.
+ */
+void
+clutter_gst_playback_set_uri (ClutterGstPlayback *self,
+                              const gchar        *uri)
+{
+  g_return_if_fail (CLUTTER_GST_IS_PLAYBACK (self));
+
+  g_object_set (G_OBJECT (self), "uri", uri, NULL);
+}
+
+/**
+ * clutter_gst_playback_get_uri:
+ * @self: a #ClutterGstPlayback
+ *
+ * Retrieves the URI from @self.
+ *
+ * Return value: the URI of the media stream. Use g_free()
+ *   to free the returned string
+ */
+gchar *
+clutter_gst_playback_get_uri (ClutterGstPlayback *self)
+{
+  gchar *retval = NULL;
+
+  g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self), NULL);
+
+  g_object_get (G_OBJECT (self), "uri", &retval, NULL);
+
+  return retval;
+}
+
+/**
+ * clutter_gst_playback_set_filename:
+ * @self: a #ClutterGstPlayback
+ * @filename: A filename
+ *
+ * Sets the source of @self using a file path.
+ */
+void
+clutter_gst_playback_set_filename (ClutterGstPlayback *self,
+                                 const gchar      *filename)
+{
+  gchar *uri;
+  GError *uri_error = NULL;
+
+  if (!g_path_is_absolute (filename))
+    {
+      gchar *abs_path;
+
+      abs_path = g_build_filename (g_get_current_dir (), filename, NULL);
+      uri = g_filename_to_uri (abs_path, NULL, &uri_error);
+      g_free (abs_path);
+    }
+  else
+    uri = g_filename_to_uri (filename, NULL, &uri_error);
+
+  if (uri_error)
+    {
+      g_signal_emit_by_name (self, "error", uri_error);
+      g_error_free (uri_error);
+      return;
+    }
+
+  clutter_gst_playback_set_uri (self, uri);
+
+  g_free (uri);
+}
+
+/**
+ * clutter_gst_playback_get_user_agent:
+ * @self: a #ClutterGstPlayback
+ *
+ * Retrieves the user agent used when streaming.
+ *
+ * Return value: the user agent used. The returned string has to be freed with
+ * g_free()
+ *
+ * Since: 1.4
+ */
+gchar *
+clutter_gst_playback_get_user_agent (ClutterGstPlayback *self)
+{
+  ClutterGstPlaybackPrivate *priv;
+  GstElement *source;
+  GParamSpec *pspec;
+  gchar *user_agent;
+
+  g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self), NULL);
+
+  priv = self->priv;
+
+  /* If the user has set a custom user agent, we just return it even if it is
+   * not used by the current source element of the pipeline */
+  if (priv->user_agent)
+    return g_strdup (priv->user_agent);
+
+  /* If not, we try to retrieve the user agent used by the current source */
+  g_object_get (priv->pipeline, "source", &source, NULL);
+  if (source == NULL)
+    return NULL;
+
+  pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (source),
+                                        "user-agent");
+  if (pspec == NULL)
+    return NULL;
+
+  g_object_get (source, "user-agent", &user_agent, NULL);
+
+  return user_agent;
+}
+
+/**
+ * clutter_gst_playback_set_user_agent:
+ * @self: a #ClutterGstPlayback
+ * @user_agent: the user agent
+ *
+ * Sets the user agent to use when streaming.
+ *
+ * When streaming content, you might want to set a custom user agent, eg. to
+ * promote your software, make it appear in statistics or because the server
+ * requires a special user agent you want to impersonate.
+ *
+ * Since: 1.4
+ */
+void
+clutter_gst_playback_set_user_agent (ClutterGstPlayback *self,
+                                     const gchar        *user_agent)
+{
+  ClutterGstPlaybackPrivate *priv;
+
+  g_return_if_fail (CLUTTER_GST_IS_PLAYBACK (self));
+
+  priv = self->priv;
+
+  g_free (priv->user_agent);
+  if (user_agent)
+    priv->user_agent = g_strdup (user_agent);
+  else
+    priv->user_agent = NULL;
+
+  player_set_user_agent (self, user_agent);
+}
+
+/**
+ * clutter_gst_playback_get_seek_flags:
+ * @self: a #ClutterGstPlayback
+ *
+ * Get the current value of the seek-flags property.
+ *
+ * Return value: a combination of #ClutterGstSeekFlags
+ *
+ * Since: 1.4
+ */
+ClutterGstSeekFlags
+clutter_gst_playback_get_seek_flags (ClutterGstPlayback *self)
+{
+  ClutterGstPlaybackPrivate *priv;
+
+  g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self),
+                        CLUTTER_GST_SEEK_FLAG_NONE);
+
+  priv = self->priv;
+
+  if (priv->seek_flags == GST_SEEK_FLAG_ACCURATE)
+    return CLUTTER_GST_SEEK_FLAG_ACCURATE;
+  else
+    return CLUTTER_GST_SEEK_FLAG_NONE;
+}
+
+/**
+ * clutter_gst_playback_set_seek_flags:
+ * @self: a #ClutterGstPlayback
+ * @flags: a combination of #ClutterGstSeekFlags
+ *
+ * Seeking can be done with several trade-offs. Clutter-gst defaults
+ * to %CLUTTER_GST_SEEK_FLAG_NONE.
+ *
+ * Since: 1.4
+ */
+void
+clutter_gst_playback_set_seek_flags (ClutterGstPlayback  *self,
+                                     ClutterGstSeekFlags  flags)
+{
+  ClutterGstPlaybackPrivate *priv;
+
+  g_return_if_fail (CLUTTER_GST_IS_PLAYBACK (self));
+
+  priv = self->priv;
+
+  if (flags == CLUTTER_GST_SEEK_FLAG_NONE)
+    priv->seek_flags = GST_SEEK_FLAG_KEY_UNIT;
+  else if (flags & CLUTTER_GST_SEEK_FLAG_ACCURATE)
+    priv->seek_flags = GST_SEEK_FLAG_ACCURATE;
+}
+
+/**
+ * clutter_gst_playback_get_buffering_mode:
+ * @self: a #ClutterGstPlayback
+ *
+ * Return value: a #ClutterGstBufferingMode
+ *
+ * Since: 1.4
+ */
+ClutterGstBufferingMode
+clutter_gst_playback_get_buffering_mode (ClutterGstPlayback *self)
+{
+  ClutterGstPlaybackPrivate *priv;
+  GstPlayFlags flags;
+
+  g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self),
+                        CLUTTER_GST_BUFFERING_MODE_STREAM);
+
+  priv = self->priv;
+
+  g_object_get (G_OBJECT (priv->pipeline), "flags", &flags, NULL);
+
+  if (flags & GST_PLAY_FLAG_DOWNLOAD)
+    return CLUTTER_GST_BUFFERING_MODE_DOWNLOAD;
+
+  return CLUTTER_GST_BUFFERING_MODE_STREAM;
+}
+
+/**
+ * clutter_gst_playback_set_buffering_mode:
+ * @self: a #ClutterGstPlayback
+ * @mode: a #ClutterGstBufferingMode
+ *
+ * Since: 1.4
+ */
+void
+clutter_gst_playback_set_buffering_mode (ClutterGstPlayback      *self,
+                                         ClutterGstBufferingMode  mode)
+{
+  ClutterGstPlaybackPrivate *priv;
+  GstPlayFlags flags;
+
+  g_return_if_fail (CLUTTER_GST_IS_PLAYBACK (self));
+
+  priv = self->priv;
+
+  g_object_get (G_OBJECT (priv->pipeline), "flags", &flags, NULL);
+
+  switch (mode)
+    {
+    case CLUTTER_GST_BUFFERING_MODE_STREAM:
+      flags &= ~GST_PLAY_FLAG_DOWNLOAD;
+      break;
+
+    case CLUTTER_GST_BUFFERING_MODE_DOWNLOAD:
+      flags |= GST_PLAY_FLAG_DOWNLOAD;
+      break;
+
+    default:
+      g_warning ("Unexpected buffering mode %d", mode);
+      break;
+    }
+
+  g_object_set (G_OBJECT (priv->pipeline), "flags", flags, NULL);
+}
+
+/**
+ * clutter_gst_playback_get_buffer_fill:
+ * @self: a #ClutterGstPlayback
+ *
+ * Retrieves the amount of the stream that is buffered.
+ *
+ * Return value: the fill level, between 0.0 and 1.0
+ */
+gdouble
+clutter_gst_playback_get_buffer_fill (ClutterGstPlayback *self)
+{
+  gdouble retval = 0.0;
+
+  g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self), 0);
+
+  g_object_get (G_OBJECT (self), "buffer-fill", &retval, NULL);
+
+  return retval;
+}
+
+/**
+ * clutter_gst_playback_get_buffer_size:
+ * @self: a #ClutterGstPlayback
+ *
+ * Retrieves the buffer size when buffering network streams.
+ *
+ * Return value: The buffer size
+ */
+gint
+clutter_gst_playback_get_buffer_size (ClutterGstPlayback *self)
+{
+  ClutterGstPlaybackPrivate *priv;
+  gint size;
+
+  g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self), 0);
+
+  priv = self->priv;
+
+  g_object_get (G_OBJECT (priv->pipeline), "buffer-size", &size, NULL);
+
+  return size;
+}
+
+/**
+ * clutter_gst_playback_set_buffer_size:
+ * @self: a #ClutterGstPlayback
+ * @size: The new size
+ *
+ * Sets the buffer size to be used when buffering network streams.
+ */
+void
+clutter_gst_playback_set_buffer_size (ClutterGstPlayback *self,
+                                      gint                size)
+{
+  ClutterGstPlaybackPrivate *priv;
+
+  g_return_if_fail (CLUTTER_GST_IS_PLAYBACK (self));
+
+  priv = self->priv;
+
+  g_object_set (G_OBJECT (priv->pipeline), "buffer-size", size, NULL);
+}
+
+/**
+ * clutter_gst_playback_get_buffer_duration:
+ * @self: a #ClutterGstPlayback
+ *
+ * Retrieves the buffer duration when buffering network streams.
+ *
+ * Return value: The buffer duration
+ */
+gint64
+clutter_gst_playback_get_buffer_duration (ClutterGstPlayback *self)
+{
+  ClutterGstPlaybackPrivate *priv;
+  gint64 duration;
+
+  g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self), 0);
+
+  priv = self->priv;
+
+  g_object_get (G_OBJECT (priv->pipeline), "buffer-duration", &duration, NULL);
+
+  return duration;
+}
+
+/**
+ * clutter_gst_playback_set_buffer_duration:
+ * @self: a #ClutterGstPlayback
+ * @duration: The new duration
+ *
+ * Sets the buffer duration to be used when buffering network streams.
+ */
+void
+clutter_gst_playback_set_buffer_duration (ClutterGstPlayback *self,
+                                          gint64              duration)
+{
+  ClutterGstPlaybackPrivate *priv;
+
+  g_return_if_fail (CLUTTER_GST_IS_PLAYBACK (self));
+
+  priv = self->priv;
+
+  g_object_set (G_OBJECT (priv->pipeline), "buffer-duration", duration, NULL);
+}
+
+/**
+ * clutter_gst_playback_get_audio_streams:
+ * @self: a #ClutterGstPlayback
+ *
+ * Get the list of audio streams of the current media.
+ *
+ * Return value: (transfer none) (element-type utf8): a list of
+ * strings describing the available audio streams
+ *
+ * Since: 1.4
+ */
+GList *
+clutter_gst_playback_get_audio_streams (ClutterGstPlayback *self)
+{
+  ClutterGstPlaybackPrivate *priv;
+
+  g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self), NULL);
+
+  priv = self->priv;
+
+  if (CLUTTER_GST_DEBUG_ENABLED (AUDIO_STREAM))
+    {
+      gchar *streams;
+
+      streams = list_to_string (priv->audio_streams);
+      CLUTTER_GST_NOTE (AUDIO_STREAM, "audio streams: %s", streams);
+      g_free (streams);
+    }
+
+  return priv->audio_streams;
+}
+
+/**
+ * clutter_gst_playback_get_audio_stream:
+ * @self: a #ClutterGstPlayback
+ *
+ * Get the current audio stream. The number returned in the index of the
+ * audio stream playing in the list returned by
+ * clutter_gst_playback_get_audio_streams().
+ *
+ * Return value: the index of the current audio stream, -1 if the media has no
+ * audio stream
+ *
+ * Since: 1.4
+ */
+gint
+clutter_gst_playback_get_audio_stream (ClutterGstPlayback *self)
+{
+  ClutterGstPlaybackPrivate *priv;
+  gint index_ = -1;
+
+  g_return_if_fail (CLUTTER_GST_IS_PLAYBACK (self));
+
+  priv = self->priv;
+
+  g_object_get (G_OBJECT (priv->pipeline),
+                "current-audio", &index_,
+                NULL);
+
+  CLUTTER_GST_NOTE (AUDIO_STREAM, "audio stream is #%d", index_);
+
+  return index_;
+}
+
+/**
+ * clutter_gst_playback_set_audio_stream:
+ * @self: a #ClutterGstPlayback
+ * @index_: the index of the audio stream
+ *
+ * Set the audio stream to play. @index_ is the index of the stream
+ * in the list returned by clutter_gst_playback_get_audio_streams().
+ *
+ * Since: 1.4
+ */
+void
+clutter_gst_playback_set_audio_stream (ClutterGstPlayback *self,
+                                       gint                index_)
+{
+  ClutterGstPlaybackPrivate *priv;
+
+  g_return_if_fail (CLUTTER_GST_IS_PLAYBACK (self));
+
+  priv = self->priv;
+
+  g_return_if_fail (index_ >= 0 &&
+                    index_ < (gint) g_list_length (priv->audio_streams));
+
+  CLUTTER_GST_NOTE (AUDIO_STREAM, "set audio audio stream to #%d", index_);
+
+  g_object_set (G_OBJECT (priv->pipeline),
+                "current-audio", index_,
+                NULL);
+}
+
+/**
+ * clutter_gst_playback_set_subtitle_uri:
+ * @self: a #ClutterGstPlayback
+ * @uri: the URI of a subtitle file
+ *
+ * Sets the location of a subtitle file to display while playing @self.
+ */
+void
+clutter_gst_playback_set_subtitle_uri (ClutterGstPlayback *self,
+                                       const char         *uri)
+{
+  g_return_if_fail (CLUTTER_GST_IS_PLAYBACK (self));
+
+  g_object_set (G_OBJECT (self), "subtitle-uri", uri, NULL);
+}
+
+/**
+ * clutter_gst_playback_get_subtitle_uri:
+ * @self: a #ClutterGstPlayback
+ *
+ * Retrieves the URI of the subtitle file in use.
+ *
+ * Return value: the URI of the subtitle file. Use g_free()
+ *   to free the returned string
+ */
+gchar *
+clutter_gst_playback_get_subtitle_uri (ClutterGstPlayback *self)
+{
+  gchar *retval = NULL;
+
+  g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self), NULL);
+
+  g_object_get (G_OBJECT (self), "subtitle-uri", &retval, NULL);
+
+  return retval;
+}
+
+/**
+ * clutter_gst_playback_set_subtitle_font_name:
+ * @self: a #ClutterGstPlayback
+ * @font_name: a font name, or %NULL to set the default font name
+ *
+ * Sets the font used by the subtitle renderer. The @font_name string must be
+ * either %NULL, which means that the default font name of the underlying
+ * implementation will be used; or must follow the grammar recognized by
+ * pango_font_description_from_string() like:
+ *
+ * |[
+ *   clutter_gst_playback_set_subtitle_font_name (player, "Sans 24pt");
+ * ]|
+ */
+void
+clutter_gst_playback_set_subtitle_font_name (ClutterGstPlayback *self,
+                                             const char         *font_name)
+{
+  g_return_if_fail (CLUTTER_GST_IS_PLAYBACK (self));
+
+  g_object_set (G_OBJECT (self), "subtitle-font-name", font_name, NULL);
+}
+
+/**
+ * clutter_gst_playback_get_subtitle_font_name:
+ * @self: a #ClutterGstPlayback
+ *
+ * Retrieves the font name currently used.
+ *
+ * Return value: a string containing the font name. Use g_free()
+ *   to free the returned string
+ */
+gchar *
+clutter_gst_playback_get_subtitle_font_name (ClutterGstPlayback *self)
+{
+  gchar *retval = NULL;
+
+  g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self), NULL);
+
+  g_object_get (G_OBJECT (self), "subtitle-font-name", &retval, NULL);
+
+  return retval;
+}
+
+/**
+ * clutter_gst_playback_get_subtitle_tracks:
+ * @self: a #ClutterGstPlayback
+ *
+ * Get the list of subtitles tracks of the current media.
+ *
+ * Return value: (transfer none) (element-type utf8): a list of
+ * strings describing the available subtitles tracks
+ *
+ * Since: 1.4
+ */
+GList *
+clutter_gst_playback_get_subtitle_tracks (ClutterGstPlayback *self)
+{
+  ClutterGstPlaybackPrivate *priv;
+
+  g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self), NULL);
+
+  priv = self->priv;
+
+  if (CLUTTER_GST_DEBUG_ENABLED (SUBTITLES))
+    {
+      gchar *tracks;
+
+      tracks = list_to_string (priv->subtitle_tracks);
+      CLUTTER_GST_NOTE (SUBTITLES, "subtitle tracks: %s", tracks);
+      g_free (tracks);
+    }
+
+  return priv->subtitle_tracks;
+}
+
+/**
+ * clutter_gst_playback_get_subtitle_track:
+ * @self: a #ClutterGstPlayback
+ *
+ * Get the current subtitles track. The number returned is the index of the
+ * subtiles track in the list returned by
+ * clutter_gst_playback_get_subtitle_tracks().
+ *
+ * Return value: the index of the current subtitlest track, -1 if the media has
+ * no subtitles track or if the subtitles have been turned off
+ *
+ * Since: 1.4
+ */
+gint
+clutter_gst_playback_get_subtitle_track (ClutterGstPlayback *self)
+{
+  ClutterGstPlaybackPrivate *priv;
+  gint index_ = -1;
+
+  g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self), -1);
+
+  priv = self->priv;
+
+  g_object_get (G_OBJECT (priv->pipeline),
+                "current-text", &index_,
+                NULL);
+
+  CLUTTER_GST_NOTE (SUBTITLES, "text track is #%d", index_);
+
+  return index_;
+}
+
+/**
+ * clutter_gst_playback_set_subtitle_track:
+ * @self: a #ClutterGstPlayback
+ * @index_: the index of the subtitles track
+ *
+ * Set the subtitles track to play. @index_ is the index of the stream
+ * in the list returned by clutter_gst_playback_get_subtitle_tracks().
+ *
+ * If @index_ is -1, the subtitles are turned off.
+ *
+ * Since: 1.4
+ */
+void
+clutter_gst_playback_set_subtitle_track (ClutterGstPlayback *self,
+                                         gint                index_)
+{
+  ClutterGstPlaybackPrivate *priv;
+  GstPlayFlags flags;
+
+  g_return_if_fail (CLUTTER_GST_IS_PLAYBACK (self));
+
+  priv = self->priv;
+
+  g_return_if_fail (index_ >= -1 &&
+                    index_ < (gint) g_list_length (priv->subtitle_tracks));
+
+  CLUTTER_GST_NOTE (SUBTITLES, "set subtitle track to #%d", index_);
+
+  g_object_get (priv->pipeline, "flags", &flags, NULL);
+  flags &= ~GST_PLAY_FLAG_TEXT;
+  g_object_set (priv->pipeline, "flags", flags, NULL);
+
+  if (index_ >= 0)
+    {
+      g_object_set (G_OBJECT (priv->pipeline),
+                    "current-text", index_,
+                    NULL);
+
+      flags |= GST_PLAY_FLAG_TEXT;
+      g_object_set (priv->pipeline, "flags", flags, NULL);
+    }
+}
+
+/**
+ * clutter_gst_playback_get_in_seek:
+ * @self: a #ClutterGstPlayback
+ *
+ * Whether the player is seeking.
+ *
+ * Return value: TRUE if the player is seeking, FALSE otherwise.
+ *
+ * Since: 1.6
+ */
+gboolean
+clutter_gst_playback_get_in_seek (ClutterGstPlayback *self)
+{
+  g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self), FALSE);
+
+  return self->priv->in_seek;
+}
+
+/**
+ * clutter_gst_playback_get_can_seek:
+ * @self: a #ClutterGstPlayback
+ *
+ * Retrieves whether @self is seekable or not.
+ *
+ * Return value: %TRUE if @self can seek, %FALSE otherwise.
+ */
+gboolean
+clutter_gst_playback_get_can_seek (ClutterGstPlayback *self)
+{
+  g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self), FALSE);
+
+  return self->priv->can_seek;
+}
+
+/**
+ * clutter_gst_playback_set_progress:
+ * @self: a #ClutterGstPlayback
+ * @progress: the progress of the playback, between 0.0 and 1.0
+ *
+ * Sets the playback progress of @self. The @progress is
+ * a normalized value between 0.0 (begin) and 1.0 (end).
+ */
+void
+clutter_gst_playback_set_progress (ClutterGstPlayback *self,
+                                   gdouble             progress)
+{
+  g_return_if_fail (CLUTTER_GST_IS_PLAYBACK (self));
+
+  set_progress (self, progress);
+}
+
+/**
+ * clutter_gst_playback_get_progress:
+ * @self: a #ClutterGstPlayback
+ *
+ * Retrieves the playback progress of @self.
+ *
+ * Return value: the playback progress, between 0.0 and 1.0
+ */
+gdouble
+clutter_gst_playback_get_progress (ClutterGstPlayback *self)
+{
+  g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self), 0);
+
+  return get_progress (self);
+}
+
+/**
+ * clutter_gst_playback_get_duration:
+ * @self: a #ClutterGstPlayback
+ *
+ * Retrieves the duration of the media stream that @self represents.
+ *
+ * Return value: the duration of the media stream, in seconds
+ */
+gdouble
+clutter_gst_playback_get_duration (ClutterGstPlayback *self)
+{
+  gdouble retval = 0;
+
+  g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self), 0);
+
+  g_object_get (G_OBJECT (self), "duration", &retval, NULL);
+
+  return retval;
+}
+
+/**
+ * clutter_gst_playback_is_live_media:
+ * @self: a #ClutterGstPlayback
+ *
+ * Whether the player is using a live media.
+ *
+ * Return value: TRUE if the player is using a live media, FALSE otherwise.
+ */
+gboolean
+clutter_gst_playback_is_live_media (ClutterGstPlayback *self)
+{
+  ClutterGstPlaybackPrivate *priv;
+
+  g_return_val_if_fail (CLUTTER_GST_IS_PLAYBACK (self), FALSE);
+
+  return self->priv->is_live;
+}
diff --git a/clutter-gst/clutter-gst-playback.h b/clutter-gst/clutter-gst-playback.h
new file mode 100644
index 0000000..1be5084
--- /dev/null
+++ b/clutter-gst/clutter-gst-playback.h
@@ -0,0 +1,116 @@
+/* clutter-gst-playback.h */
+
+#ifndef __CLUTTER_GST_PLAYBACK_H__
+#define __CLUTTER_GST_PLAYBACK_H__
+
+#include <glib-object.h>
+
+#include <clutter-gst/clutter-gst-types.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_GST_TYPE_PLAYBACK clutter_gst_playback_get_type()
+
+#define CLUTTER_GST_PLAYBACK(obj)                               \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj),                           \
+                               CLUTTER_GST_TYPE_PLAYBACK,       \
+                               ClutterGstPlayback))
+
+#define CLUTTER_GST_PLAYBACK_CLASS(klass)                   \
+  (G_TYPE_CHECK_CLASS_CAST ((klass),                        \
+                            CLUTTER_GST_TYPE_PLAYBACK,      \
+                            ClutterGstPlaybackClass))
+
+#define CLUTTER_GST_IS_PLAYBACK(obj)                            \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj),                           \
+                               CLUTTER_GST_TYPE_PLAYBACK))
+
+#define CLUTTER_GST_IS_PLAYBACK_CLASS(klass)            \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass),                    \
+                            CLUTTER_GST_TYPE_PLAYBACK))
+
+#define CLUTTER_GST_PLAYBACK_GET_CLASS(obj)                     \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj),                            \
+                              CLUTTER_GST_TYPE_PLAYBACK,        \
+                              ClutterGstPlaybackClass))
+
+typedef struct _ClutterGstPlayback ClutterGstPlayback;
+typedef struct _ClutterGstPlaybackClass ClutterGstPlaybackClass;
+typedef struct _ClutterGstPlaybackPrivate ClutterGstPlaybackPrivate;
+
+struct _ClutterGstPlayback
+{
+  GObject parent;
+
+  ClutterGstPlaybackPrivate *priv;
+};
+
+struct _ClutterGstPlaybackClass
+{
+  GObjectClass parent_class;
+
+  /* signals */
+  void (* download_buffering)  (ClutterGstPlayback *self,
+                                gdouble             start,
+                                gdouble             stop);
+};
+
+GType clutter_gst_playback_get_type (void) G_GNUC_CONST;
+
+ClutterGstPlayback *      clutter_gst_playback_new (void);
+
+void                      clutter_gst_playback_set_uri             (ClutterGstPlayback        *self,
+                                                                    const gchar               *uri);
+gchar *                   clutter_gst_playback_get_uri             (ClutterGstPlayback        *self);
+void                      clutter_gst_playback_set_filename        (ClutterGstPlayback        *self,
+                                                                    const gchar               *filename);
+
+gchar *                   clutter_gst_playback_get_user_agent      (ClutterGstPlayback        *self);
+void                      clutter_gst_playback_set_user_agent      (ClutterGstPlayback        *self,
+                                                                    const gchar               *user_agent);
+
+ClutterGstSeekFlags       clutter_gst_playback_get_seek_flags      (ClutterGstPlayback        *self);
+void                      clutter_gst_playback_set_seek_flags      (ClutterGstPlayback        *self,
+                                                                    ClutterGstSeekFlags        flags);
+
+ClutterGstBufferingMode   clutter_gst_playback_get_buffering_mode  (ClutterGstPlayback        *self);
+void                      clutter_gst_playback_set_buffering_mode  (ClutterGstPlayback        *self,
+                                                                    ClutterGstBufferingMode    mode);
+gdouble                   clutter_gst_playback_get_buffer_fill     (ClutterGstPlayback        *self);
+gint                      clutter_gst_playback_get_buffer_size     (ClutterGstPlayback        *self);
+void                      clutter_gst_playback_set_buffer_size     (ClutterGstPlayback        *self,
+                                                                    gint                       size);
+gint64                    clutter_gst_playback_get_buffer_duration (ClutterGstPlayback        *self);
+void                      clutter_gst_playback_set_buffer_duration (ClutterGstPlayback        *self,
+                                                                    gint64                     duration);
+
+GList *                   clutter_gst_playback_get_audio_streams   (ClutterGstPlayback        *self);
+gint                      clutter_gst_playback_get_audio_stream    (ClutterGstPlayback        *self);
+void                      clutter_gst_playback_set_audio_stream    (ClutterGstPlayback        *self,
+                                                                    gint                       index_);
+
+void                      clutter_gst_playback_set_subtitle_uri    (ClutterGstPlayback        *self,
+                                                                    const gchar               *uri);
+gchar *                   clutter_gst_playback_get_subtitle_uri    (ClutterGstPlayback        *self);
+void                      clutter_gst_playback_set_subtitle_font_name
+                                                                   (ClutterGstPlayback        *self,
+                                                                    const char                *font_name);
+gchar *                   clutter_gst_playback_get_subtitle_font_name
+                                                                   (ClutterGstPlayback        *self);
+GList *                   clutter_gst_playback_get_subtitle_tracks (ClutterGstPlayback        *self);
+gint                      clutter_gst_playback_get_subtitle_track  (ClutterGstPlayback        *self);
+void                      clutter_gst_playback_set_subtitle_track  (ClutterGstPlayback        *self,
+                                                                    gint                       index_);
+
+gboolean                  clutter_gst_playback_get_in_seek         (ClutterGstPlayback        *self);
+
+void                      clutter_gst_playback_set_progress        (ClutterGstPlayback        *self,
+                                                                    gdouble                    progress);
+gdouble                   clutter_gst_playback_get_progress        (ClutterGstPlayback        *self);
+gdouble                   clutter_gst_playback_get_duration        (ClutterGstPlayback        *self);
+
+gboolean                  clutter_gst_playback_is_live_media       (ClutterGstPlayback        *self);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_GST_PLAYBACK_H__ */
diff --git a/clutter-gst/clutter-gst-player.c b/clutter-gst/clutter-gst-player.c
index 0b5dc81..25f8db5 100644
--- a/clutter-gst/clutter-gst-player.c
+++ b/clutter-gst/clutter-gst-player.c
@@ -12,7 +12,7 @@
  *             Andre Moreira Magalhaes <andre magalhaes collabora co uk>
  *
  * Copyright (C) 2006 OpenedHand
- * Copyright (C) 2009-2011 Intel Corporation
+ * Copyright (C) 2009-2013 Intel Corporation
  * Copyright (C) 2012 Collabora Ltd. <http://www.collabora.co.uk/>
  *
  * This library is free software; you can redistribute it and/or
@@ -45,3258 +45,317 @@
 #include "config.h"
 #endif
 
-#include <string.h>
-
-#include <gst/video/video.h>
-#include <gst/tag/tag.h>
-#include <gst/audio/streamvolume.h>
-
-#include "clutter-gst-debug.h"
 #include "clutter-gst-enum-types.h"
 #include "clutter-gst-marshal.h"
-#include "clutter-gst-player.h"
-#include "clutter-gst-private.h"
-
-#if defined (CLUTTER_WINDOWING_X11) && defined (HAVE_HW_DECODER_SUPPORT)
-#define GST_USE_UNSTABLE_API 1
-#include <gst/video/videocontext.h>
-#include <clutter/x11/clutter-x11.h>
-#endif
-
-
-typedef ClutterGstPlayerIface       ClutterGstPlayerInterface;
-
-G_DEFINE_INTERFACE (ClutterGstPlayer, clutter_gst_player, G_TYPE_OBJECT)
-
-#define PLAYER_GET_PRIVATE(player)                              \
-  (g_object_get_qdata (G_OBJECT (player),                       \
-                       clutter_gst_player_private_quark))
-#define PLAYER_SET_PRIVATE(player,private)                      \
-  (g_object_set_qdata (G_OBJECT (player),                       \
-                       clutter_gst_player_private_quark,        \
-                       private))
-
-#define PLAYER_GET_CLASS_PRIVATE(player)                     \
-  (g_type_get_qdata (G_OBJECT_TYPE (player),                 \
-                     clutter_gst_player_class_quark))
-
-/* idle timeouts (in ms) */
-#define TICK_TIMEOUT        500
-#define BUFFERING_TIMEOUT   250
-
-enum
-{
-  EOS_SIGNAL,
-  ERROR_SIGNAL, /* can't be called 'ERROR' otherwise it clashes with wingdi.h */
-  DOWNLOAD_BUFFERING_SIGNAL,
-
-  LAST_SIGNAL
-};
-
-enum
-{
-  PROP_0,
-
-  /* ClutterGstPlayer properties */
-  PROP_URI,
-  PROP_PLAYING,
-  PROP_PROGRESS,
-  PROP_SUBTITLE_URI,
-  PROP_SUBTITLE_FONT_NAME,
-  PROP_AUDIO_VOLUME,
-  PROP_CAN_SEEK,
-  PROP_BUFFER_FILL,
-  PROP_DURATION,
-  PROP_IDLE,
-  PROP_USER_AGENT,
-  PROP_SEEK_FLAGS,
-  PROP_AUDIO_STREAMS,
-  PROP_AUDIO_STREAM,
-  PROP_SUBTITLE_TRACKS,
-  PROP_SUBTITLE_TRACK,
-  PROP_IN_SEEK
-};
-
-struct _ClutterGstPlayerIfacePrivate
-{
-  void       (*set_property)           (GObject        *object,
-                                         guint           property_id,
-                                         const GValue   *value,
-                                         GParamSpec     *pspec);
-  void       (*get_property)           (GObject        *object,
-                                         guint           property_id,
-                                         GValue         *value,
-                                         GParamSpec     *pspec);
-};
-
-typedef struct _ClutterGstPlayerPrivate ClutterGstPlayerPrivate;
-
-/* Elements don't expose header files */
-typedef enum {
-  GST_PLAY_FLAG_VIDEO         = (1 << 0),
-  GST_PLAY_FLAG_AUDIO         = (1 << 1),
-  GST_PLAY_FLAG_TEXT          = (1 << 2),
-  GST_PLAY_FLAG_VIS           = (1 << 3),
-  GST_PLAY_FLAG_SOFT_VOLUME   = (1 << 4),
-  GST_PLAY_FLAG_NATIVE_AUDIO  = (1 << 5),
-  GST_PLAY_FLAG_NATIVE_VIDEO  = (1 << 6),
-  GST_PLAY_FLAG_DOWNLOAD      = (1 << 7),
-  GST_PLAY_FLAG_BUFFERING     = (1 << 8),
-  GST_PLAY_FLAG_DEINTERLACE   = (1 << 9)
-} GstPlayFlags;
-
-struct _ClutterGstPlayerPrivate
-{
-  GObject parent;
-
-  GstElement *pipeline;
-  GstBus *bus;
-
-  gchar *uri;
-
-  guint is_idle : 1;
-  guint is_live : 1;
-  guint can_seek : 1;
-  guint in_seek : 1;
-  guint is_changing_uri : 1;
-  guint in_error : 1;
-  guint in_eos : 1;
-  guint in_download_buffering : 1;
-  /* when in progressive download, we use the buffer-fill property to signal
-   * that we have enough data to play the stream. This flag allows to send
-   * the notify that buffer-fill is 1.0 only once */
-  guint virtual_stream_buffer_signalled : 1;
-
-  gdouble stacked_progress;
-
-  gdouble target_progress;
-  GstState target_state;
-
-  guint tick_timeout_id;
-  guint buffering_timeout_id;
-
-  /* This is a cubic volume, suitable for use in a UI cf. StreamVolume doc */
-  gdouble volume;
-
-  gdouble buffer_fill;
-  gdouble duration;
-  gchar *font_name;
-  gchar *user_agent;
-
-  GstSeekFlags seek_flags;    /* flags for the seek in set_progress(); */
-
-  GstElement *download_buffering_element;
-
-  GList *audio_streams;
-  GList *subtitle_tracks;
-};
-
-static GQuark clutter_gst_player_private_quark = 0;
-static GQuark clutter_gst_player_class_quark = 0;
-
-static guint signals[LAST_SIGNAL] = { 0, };
-
-static gboolean player_buffering_timeout (gpointer data);
-
-/* Logic */
-
-#ifdef CLUTTER_GST_ENABLE_DEBUG
-static gchar *
-get_stream_description (GstTagList *tags,
-                        gint        track_num)
-{
-  gchar *description = NULL;
-
-  if (tags)
-    {
-
-      gst_tag_list_get_string (tags, GST_TAG_LANGUAGE_CODE, &description);
-
-      if (description)
-        {
-          const gchar *language = gst_tag_get_language_name (description);
-
-          if (language)
-            {
-              g_free (description);
-              description = g_strdup (language);
-            }
-        }
-
-      if (!description)
-        gst_tag_list_get_string (tags, GST_TAG_CODEC, &description);
-    }
-
-  if (!description)
-    description = g_strdup_printf ("Track %d", track_num);
-
-  return description;
-}
-
-gchar *
-list_to_string (GList *list)
-{
-  GstTagList *tags;
-  gchar *description;
-  GString *string;
-  GList *l;
-  gint n, i;
-
-  if (!list)
-    return g_strdup ("<empty list>");
-
-  string = g_string_new (NULL);
-  n = g_list_length (list);
-  for (i = 0, l = list; i < n - 1; i++, l = g_list_next (l))
-    {
-      tags = l->data;
-      description = get_stream_description (tags, i);
-      g_string_append_printf (string, "%s, ", description);
-      g_free (description);
-    }
-
-  tags = l->data;
-  description = get_stream_description (tags, i);
-  g_string_append_printf (string, "%s", (gchar *) description);
-  g_free (description);
-
-  return g_string_free (string, FALSE);
-}
-#endif
-
-static const gchar *
-gst_state_to_string (GstState state)
-{
-  switch (state)
-    {
-    case GST_STATE_VOID_PENDING:
-      return "pending";
-    case GST_STATE_NULL:
-      return "null";
-    case GST_STATE_READY:
-      return "ready";
-    case GST_STATE_PAUSED:
-      return "paused";
-    case GST_STATE_PLAYING:
-      return "playing";
-    }
-
-  return "Unknown state";
-}
-
-static void
-free_tags_list (GList **listp)
-{
-  GList *l;
-
-  l = *listp;
-  while (l)
-    {
-      if (l->data)
-        gst_tag_list_unref (l->data);
-      l = g_list_delete_link (l, l);
-    }
-
-  *listp = NULL;
-}
-
-static gboolean
-tick_timeout (gpointer data)
-{
-  GObject *player = data;
-
-  g_object_notify (player, "progress");
-
-  return TRUE;
-}
-
-static void
-player_set_user_agent (ClutterGstPlayer *player,
-                       const gchar      *user_agent)
-{
-  ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-  GstElement *source;
-  GParamSpec *pspec;
-
-  if (user_agent == NULL)
-    return;
-
-  g_object_get (priv->pipeline, "source", &source, NULL);
-  if (source == NULL)
-    return;
-
-  pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (source),
-                                        "user-agent");
-  if (pspec == NULL)
-    return;
-
-  CLUTTER_GST_NOTE (MEDIA, "setting user agent: %s", user_agent);
-
-  g_object_set (source, "user-agent", user_agent, NULL);
-}
-
-static void
-autoload_subtitle (ClutterGstPlayer *player,
-                   const gchar      *uri)
-{
-  ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-  gchar *path, *dot, *subtitle_path;
-  GFile *video;
-  guint i;
-
-  static const char subtitles_extensions[][4] =
-    {
-      "sub", "SUB",
-      "srt", "SRT",
-      "smi", "SMI",
-      "ssa", "SSA",
-      "ass", "ASS",
-      "asc", "ASC"
-    };
-
-  /* do not try to look for subtitle files if the video file is not mounted
-   * locally */
-  if (!g_str_has_prefix (uri, "file://"))
-    return;
-
-  /* Retrieve the absolute path of the video file */
-  video = g_file_new_for_uri (uri);
-  path = g_file_get_path (video);
-  g_object_unref (video);
-  if (path == NULL)
-    return;
-
-  /* Put a '\0' after the dot of the extension */
-  dot = strrchr (path, '.');
-  if (dot == NULL) {
-    g_free (path);
-    return;
-  }
-  *++dot = '\0';
-
-  /* we can't use path as the temporary buffer for the paths of the potential
-   * subtitle files as we may not have enough room there */
-  subtitle_path = g_malloc (strlen (path) + 1 + 4);
-  strcpy (subtitle_path, path);
-
-  /* reuse dot to point to the first byte of the extension of subtitle_path */
-  dot = subtitle_path + (dot - path);
-
-  for (i = 0; i < G_N_ELEMENTS (subtitles_extensions); i++)
-    {
-      GFile *candidate;
-
-      memcpy (dot, subtitles_extensions[i], 4);
-      candidate = g_file_new_for_path (subtitle_path);
-      if (g_file_query_exists (candidate, NULL))
-        {
-          gchar *suburi;
-
-          suburi = g_file_get_uri (candidate);
-
-          CLUTTER_GST_NOTE (MEDIA, "found subtitle: %s", suburi);
-
-          g_object_set (priv->pipeline, "suburi", suburi, NULL);
-          g_free (suburi);
-
-          g_object_unref (candidate);
-          break;
-        }
-
-      g_object_unref (candidate);
-    }
-
-  g_free (path);
-  g_free (subtitle_path);
-}
-
-static void
-set_subtitle_uri (ClutterGstPlayer *player,
-                  const gchar      *uri)
-{
-  ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-  GstPlayFlags flags;
-
-  if (!priv->pipeline)
-    return;
-
-  CLUTTER_GST_NOTE (MEDIA, "setting subtitle URI: %s", uri);
-
-  g_object_get (priv->pipeline, "flags", &flags, NULL);
-
-  g_object_set (priv->pipeline, "suburi", uri, NULL);
-
-  g_object_set (priv->pipeline, "flags", flags, NULL);
-}
-
-static void
-player_configure_buffering_timeout (ClutterGstPlayer *player,
-                                    guint             ms)
-{
-  ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-
-  if (priv->buffering_timeout_id)
-    {
-      g_source_remove (priv->buffering_timeout_id);
-      priv->buffering_timeout_id = 0;
-    }
-
-  if (ms)
-    {
-      priv->buffering_timeout_id =
-        g_timeout_add (ms, player_buffering_timeout, player);
-    }
-}
-
-static void
-player_clear_download_buffering (ClutterGstPlayer *player)
-{
-  ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-
-  if (priv->download_buffering_element)
-    {
-      g_object_unref (priv->download_buffering_element);
-      priv->download_buffering_element = NULL;
-    }
-  player_configure_buffering_timeout (player, 0);
-  priv->in_download_buffering = FALSE;
-  priv->virtual_stream_buffer_signalled = 0;
-}
-
-static gboolean
-is_live_pipeline (GstElement *pipeline)
-{
-  GstState state, pending;
-  GstStateChangeReturn state_change_res;
-  gboolean is_live = FALSE;
-
-  /* get pipeline current state, we need to change the pipeline state to PAUSED to
-   * see if we are dealing with a live source and we want to restore the pipeline
-   * state afterwards */
-  gst_element_get_state (pipeline, &state, &pending, 0);
-
-  /* a pipeline with live source should return NO_PREROLL in PAUSE */
-  state_change_res = gst_element_set_state (pipeline, GST_STATE_PAUSED);
-  is_live = (state_change_res == GST_STATE_CHANGE_NO_PREROLL);
-
-  /* restore pipeline previous state */
-  if (pending == GST_STATE_VOID_PENDING)
-    gst_element_set_state (pipeline, state);
-  else
-    gst_element_set_state (pipeline, pending);
-
-  return is_live;
-}
-
-static void
-set_uri (ClutterGstPlayer *player,
-         const gchar      *uri)
-{
-  ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-  GObject *self = G_OBJECT (player);
-  GstState state, pending;
-
-  CLUTTER_GST_NOTE (MEDIA, "setting uri %s", uri);
-
-  if (!priv->pipeline)
-    return;
-
-  g_free (priv->uri);
-
-  priv->in_eos = FALSE;
-  priv->in_error = FALSE;
-
-  if (uri)
-    {
-      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, tick_timeout, self);
-        }
-
-      /* try to load subtitles based on the uri of the file */
-      set_subtitle_uri (player, NULL);
-
-      /* reset the states of download buffering */
-      player_clear_download_buffering (player);
-    }
-  else
-    {
-      priv->uri = NULL;
-
-      if (priv->tick_timeout_id)
-       {
-         g_source_remove (priv->tick_timeout_id);
-         priv->tick_timeout_id = 0;
-       }
-
-      if (priv->buffering_timeout_id)
-        {
-          g_source_remove (priv->buffering_timeout_id);
-          priv->buffering_timeout_id = 0;
-        }
-
-      if (priv->download_buffering_element)
-        {
-          g_object_unref (priv->download_buffering_element);
-          priv->download_buffering_element = NULL;
-        }
-
-    }
-
-  priv->can_seek = FALSE;
-  priv->duration = 0.0;
-  priv->stacked_progress = 0.0;
-  priv->target_progress = 0.0;
-
-  CLUTTER_GST_NOTE (MEDIA, "setting URI: %s", uri);
-
-  if (uri)
-    {
-      gst_element_get_state (priv->pipeline, &state, &pending, 0);
-      if (pending)
-        state = pending;
-
-      gst_element_set_state (priv->pipeline, GST_STATE_NULL);
-
-      g_object_set (priv->pipeline, "uri", uri, NULL);
-
-      priv->is_live = is_live_pipeline (priv->pipeline);
-
-      set_subtitle_uri (player, NULL);
-      autoload_subtitle (player, uri);
-
-      gst_element_set_state (priv->pipeline, state);
-
-      priv->is_changing_uri = TRUE;
-    }
-  else
-    {
-      priv->is_idle = TRUE;
-      priv->is_live = FALSE;
-      set_subtitle_uri (player, NULL);
-      gst_element_set_state (priv->pipeline, GST_STATE_NULL);
-      g_object_notify (G_OBJECT (player), "idle");
-    }
-
-  /*
-   * Emit notifications for all these to make sure UI is not showing
-   * any properties of the old URI.
-   */
-  g_object_notify (self, "uri");
-  g_object_notify (self, "can-seek");
-  g_object_notify (self, "duration");
-  g_object_notify (self, "progress");
-
-  free_tags_list (&priv->audio_streams);
-  CLUTTER_GST_NOTE (AUDIO_STREAM, "audio-streams changed");
-  g_object_notify (self, "audio-streams");
-
-  free_tags_list (&priv->subtitle_tracks);
-  CLUTTER_GST_NOTE (SUBTITLES, "subtitle-tracks changed");
-  g_object_notify (self, "subtitle-tracks");
-}
-
-static void
-set_in_seek (ClutterGstPlayer *player,
-             gboolean          seeking)
-{
-  ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-
-  priv->in_seek = seeking;
-  g_object_notify (G_OBJECT (player), "in-seek");
-}
-
-
-static void
-set_playing (ClutterGstPlayer *player,
-             gboolean          playing)
-{
-  ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-
-  if (!priv->pipeline)
-    return;
-
-  CLUTTER_GST_NOTE (MEDIA, "set playing: %d", playing);
-
-  priv->in_error = FALSE;
-  priv->in_eos = FALSE;
-
-  priv->target_state = playing ? GST_STATE_PLAYING : GST_STATE_PAUSED;
-
-  if (priv->uri)
-    {
-      set_in_seek (player, FALSE);
-
-      gst_element_set_state (priv->pipeline, priv->target_state);
-    }
-  else
-    {
-      if (playing)
-       g_warning ("Unable to start playing: no URI is set");
-    }
-
-  g_object_notify (G_OBJECT (player), "playing");
-  g_object_notify (G_OBJECT (player), "progress");
-}
-
-static gboolean
-get_playing (ClutterGstPlayer *player)
-{
-  ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-  GstState state, pending;
-  gboolean playing;
-
-  if (!priv->pipeline)
-    return FALSE;
-
-  gst_element_get_state (priv->pipeline, &state, &pending, 0);
-
-  if (pending)
-    playing = (pending == GST_STATE_PLAYING);
-  else
-    playing = (state == GST_STATE_PLAYING);
-
-  CLUTTER_GST_NOTE (MEDIA, "get playing: %d", playing);
-
-  return playing;
-}
-
-static void
-set_progress (ClutterGstPlayer *player,
-              gdouble           progress)
-{
-  ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-  GstQuery *duration_q;
-  gint64 position;
-
-  if (!priv->pipeline)
-    return;
-
-  CLUTTER_GST_NOTE (MEDIA, "set progress: %.02f", progress);
-
-  priv->in_eos = FALSE;
-  priv->target_progress = progress;
-
-  if (priv->in_download_buffering)
-    {
-      /* we clear the virtual_stream_buffer_signalled flag as it's likely we
-       * need to buffer again */
-      priv->virtual_stream_buffer_signalled = 0;
-    }
-
-  if (priv->in_seek || priv->is_idle || priv->is_changing_uri)
-    {
-      /* We can't seek right now, let's save the position where we
-         want to seek and do that later. */
-      CLUTTER_GST_NOTE (MEDIA,
-                        "already seeking/idleing. stacking progress point.");
-      priv->stacked_progress = progress;
-      return;
-    }
-
-  duration_q = gst_query_new_duration (GST_FORMAT_TIME);
-
-  if (gst_element_query (priv->pipeline, duration_q))
-    {
-      gint64 duration = 0;
-
-      gst_query_parse_duration (duration_q, NULL, &duration);
-
-      position = progress * duration;
-    }
-  else
-    position = 0;
-
-  gst_query_unref (duration_q);
-
-  gst_element_seek (priv->pipeline,
-                   1.0,
-                   GST_FORMAT_TIME,
-                   GST_SEEK_FLAG_FLUSH | priv->seek_flags,
-                   GST_SEEK_TYPE_SET,
-                   position,
-                   GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
-
-  set_in_seek (player, TRUE);
-
-  priv->stacked_progress = 0.0;
-
-  CLUTTER_GST_NOTE (MEDIA, "set progress (seeked): %.02f", progress);
-}
-
-static gdouble
-get_progress (ClutterGstPlayer *player)
-{
-  ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-  GstQuery *position_q, *duration_q;
-  gdouble progress;
-
-  if (!priv->pipeline)
-    return 0.0;
-
-  /* when hitting an error or after an EOS, playbin has some weird values when
-   * querying the duration and progress. We default to 0.0 on error and 1.0 on
-   * EOS */
-  if (priv->in_error)
-    {
-      CLUTTER_GST_NOTE (MEDIA, "get progress (error): 0.0");
-      return 0.0;
-    }
-
-  if (priv->in_eos)
-    {
-      CLUTTER_GST_NOTE (MEDIA, "get progress (eos): 1.0");
-      return 1.0;
-    }
-
-  /* When seeking, the progress returned by playbin is 0.0. We want that to be
-   * the last known position instead as returning 0.0 will have some ugly
-   * effects, say on a progress bar getting updated from the progress tick. */
-  if (priv->in_seek || priv->is_changing_uri)
-    {
-      CLUTTER_GST_NOTE (MEDIA, "get progress (target): %.02f",
-                        priv->target_progress);
-      return priv->target_progress;
-    }
-
-  position_q = gst_query_new_position (GST_FORMAT_TIME);
-  duration_q = gst_query_new_duration (GST_FORMAT_TIME);
-
-  if (gst_element_query (priv->pipeline, position_q) &&
-      gst_element_query (priv->pipeline, duration_q))
-    {
-      gint64 position, duration;
-
-      position = duration = 0;
-
-      gst_query_parse_position (position_q, NULL, &position);
-      gst_query_parse_duration (duration_q, NULL, &duration);
-
-      progress = CLAMP ((gdouble) position / (gdouble) duration, 0.0, 1.0);
-    }
-  else
-    progress = 0.0;
-
-  gst_query_unref (position_q);
-  gst_query_unref (duration_q);
-
-  CLUTTER_GST_NOTE (MEDIA, "get progress (pipeline): %.02f", progress);
-
-  return progress;
-}
-
-static void
-set_subtitle_font_name (ClutterGstPlayer *player,
-                        const gchar      *font_name)
-{
-  ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-
-  if (!priv->pipeline)
-    return;
-
-  CLUTTER_GST_NOTE (MEDIA, "setting subtitle font to %s", font_name);
-
-  g_free (priv->font_name);
-  priv->font_name = g_strdup (font_name);
-  g_object_set (priv->pipeline, "subtitle-font-desc", font_name, NULL);
-}
-
-static void
-set_audio_volume (ClutterGstPlayer *player,
-                  gdouble           volume)
-{
-  ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-
-    if (!priv->pipeline)
-      return;
-
-  CLUTTER_GST_NOTE (MEDIA, "set volume: %.02f", volume);
-
-  volume = CLAMP (volume, 0.0, 1.0);
-  gst_stream_volume_set_volume (GST_STREAM_VOLUME (priv->pipeline),
-                               GST_STREAM_VOLUME_FORMAT_CUBIC,
-                               volume);
-  g_object_notify (G_OBJECT (player), "audio-volume");
-}
-
-static gdouble
-get_audio_volume (ClutterGstPlayer *player)
-{
-  ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-
-  if (!priv->pipeline)
-    return 0.0;
-
-  CLUTTER_GST_NOTE (MEDIA, "get volume: %.02f", priv->volume);
-
-  return priv->volume;
-}
-
-static gboolean
-player_buffering_timeout (gpointer data)
-{
-  ClutterGstPlayer *player = (ClutterGstPlayer *) data;
-  ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-  gdouble start_d, stop_d, seconds_buffered;
-  gint64 start, stop, left;
-  gint buffer_percent;
-  GstState current_state;
-  GstElement *element;
-  GstQuery *query;
-  gboolean res;
-
-  element = priv->download_buffering_element;
-  if (element == NULL)
-    element = priv->pipeline;
-
-  /* queue2 only knows about _PERCENT and _BYTES */
-  query = gst_query_new_buffering (GST_FORMAT_PERCENT);
-  res = gst_element_query (element, query);
-
-  if (res == FALSE)
-    {
-      priv->buffering_timeout_id = 0;
-      player_clear_download_buffering (player);
-      return FALSE;
-    }
-
-  /* signal the current range */
-
-  gst_query_parse_buffering_stats (query, NULL, NULL, NULL, &left);
-  gst_query_parse_buffering_range (query, NULL, &start, &stop, NULL);
-
-  CLUTTER_GST_NOTE (BUFFERING,
-                    "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT
-                    ", buffering left %" G_GINT64_FORMAT, start, stop, left);
-
-  start_d = (gdouble) start / GST_FORMAT_PERCENT_MAX;
-  stop_d = (gdouble) stop / GST_FORMAT_PERCENT_MAX;
-
-  g_signal_emit (player, signals[DOWNLOAD_BUFFERING_SIGNAL], 0, start_d, stop_d);
-
-  /* handle the "virtual stream buffer" and the associated pipeline state.
-   * We pause the pipeline until the content is buffered.
-   */
-  seconds_buffered = priv->duration * (stop_d - start_d);
-  gst_query_parse_buffering_percent (query, NULL, &buffer_percent);
-  priv->buffer_fill = CLAMP ((gdouble) buffer_percent / 100.0, 0.0, 1.0);
-
-  if (priv->buffer_fill != 1.0 || !priv->virtual_stream_buffer_signalled)
-    {
-      CLUTTER_GST_NOTE (BUFFERING, "buffer holds %0.2fs of data, buffer-fill "
-                        "is %.02f", seconds_buffered, priv->buffer_fill);
-
-      g_object_notify (G_OBJECT (player), "buffer-fill");
-
-      if (priv->buffer_fill == 1.0)
-        priv->virtual_stream_buffer_signalled = 1;
-    }
-
-  gst_element_get_state (priv->pipeline, &current_state, NULL, 0);
-  if (priv->buffer_fill < 1.0)
-    {
-      if (current_state != GST_STATE_PAUSED)
-        {
-          CLUTTER_GST_NOTE (BUFFERING, "pausing the pipeline");
-          gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
-        }
-    }
-  else
-    {
-      if (current_state != priv->target_state)
-        {
-          CLUTTER_GST_NOTE (BUFFERING, "restoring the pipeline");
-          gst_element_set_state (priv->pipeline, priv->target_state);
-        }
-    }
-
-  /* the file has finished downloading */
-  if (left == G_GINT64_CONSTANT (0))
-    {
-      priv->buffering_timeout_id = 0;
-
-      player_clear_download_buffering (player);
-      gst_query_unref (query);
-      return FALSE;
-    }
-
-  gst_query_unref (query);
-  return TRUE;
-}
-
-static void
-bus_message_error_cb (GstBus           *bus,
-                      GstMessage       *message,
-                      ClutterGstPlayer *player)
-{
-  ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-  GError *error = NULL;
-
-  gst_element_set_state (priv->pipeline, GST_STATE_NULL);
-
-  gst_message_parse_error (message, &error, NULL);
-  g_signal_emit (player, signals[ERROR_SIGNAL], 0, error);
-  g_error_free (error);
-
-  priv->is_idle = TRUE;
-  g_object_notify (G_OBJECT (player), "idle");
-}
-
-/*
- * This is what's intented in the EOS callback:
- *   - receive EOS from playbin
- *   - fire the EOS signal, the user can install a signal handler to loop the
- *     video for instance.
- *   - after having emitted the signal, check the state of the pipeline
- *   - if the pipeline has been set back to playing or pause, don't touch the
- *     idle state. This will avoid drawing a frame (or more) with the idle
- *     material when looping
- */
-static void
-bus_message_eos_cb (GstBus           *bus,
-                    GstMessage       *message,
-                    ClutterGstPlayer *player)
-{
-  ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-  GstState state, pending;
-
-  priv->in_eos = TRUE;
-
-  gst_element_set_state (priv->pipeline, GST_STATE_READY);
-
-  g_signal_emit (player, signals[EOS_SIGNAL], 0);
-  g_object_notify (G_OBJECT (player), "progress");
-
-  gst_element_get_state (priv->pipeline, &state, &pending, 0);
-  if (pending)
-    state = pending;
-
-  if (!(state == GST_STATE_PLAYING || state == GST_STATE_PAUSED))
-    {
-      priv->is_idle = TRUE;
-      g_object_notify (G_OBJECT (player), "idle");
-    }
-}
-
-static void
-bus_message_buffering_cb (GstBus           *bus,
-                          GstMessage       *message,
-                          ClutterGstPlayer *player)
-{
-  ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-  GstBufferingMode mode;
-  GstState current_state;
-  gint buffer_percent;
-
-  gst_message_parse_buffering_stats (message, &mode, NULL, NULL, NULL);
-
-  if (mode != GST_BUFFERING_DOWNLOAD)
-    priv->in_download_buffering = FALSE;
-
-  switch (mode)
-    {
-    case GST_BUFFERING_LIVE:
-    case GST_BUFFERING_STREAM:
-      gst_message_parse_buffering (message, &buffer_percent);
-      priv->buffer_fill = CLAMP ((gdouble) buffer_percent / 100.0, 0.0, 1.0);
-
-      CLUTTER_GST_NOTE (BUFFERING, "buffer-fill: %.02f", priv->buffer_fill);
-
-      /* no state management needed for live pipelines */
-      if (!priv->is_live)
-        {
-          /* The playbin documentation says that we need to pause the pipeline
-           * when there's not enough data yet. We try to limit the calls to
-           * gst_element_set_state() */
-          gst_element_get_state (priv->pipeline, &current_state, NULL, 0);
-
-          if (priv->buffer_fill < 1.0)
-            {
-              if (current_state != GST_STATE_PAUSED)
-                {
-                  CLUTTER_GST_NOTE (BUFFERING, "pausing the pipeline");
-                  gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
-                }
-            }
-          else
-            {
-              if (current_state != priv->target_state)
-                {
-                  CLUTTER_GST_NOTE (BUFFERING, "restoring the pipeline");
-                  gst_element_set_state (priv->pipeline, priv->target_state);
-                }
-            }
-        }
-
-      g_object_notify (G_OBJECT (player), "buffer-fill");
-      break;
-
-    case GST_BUFFERING_DOWNLOAD:
-      /* we rate limit the messages from GStreamer for a usage in a UI (we
-       * don't want *that* many updates). This is done by installing an idle
-       * handler querying the buffer range and sending a signal from there */
-
-      if (priv->in_download_buffering)
-        break;
-
-      /* install the querying idle handler the first time we receive a download
-       * buffering message */
-      player_configure_buffering_timeout (player, BUFFERING_TIMEOUT);
-
-      /* pause the stream. the idle timeout will set the target state when
-       * having received enough data. We'll use buffer_fill as a "virtual
-       * stream buffer" to signal the application we're buffering until we
-       * can play back from the downloaded stream. */
-      gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
-      priv->buffer_fill = 0.0;
-      g_object_notify (G_OBJECT (player), "buffer-fill");
-
-      priv->download_buffering_element = g_object_ref (message->src);
-      priv->in_download_buffering = TRUE;
-      priv->virtual_stream_buffer_signalled = 0;
-      break;
-
-    case GST_BUFFERING_TIMESHIFT:
-    default:
-      g_warning ("Buffering mode %d not handled", mode);
-      break;
-    }
-}
-
-static void
-on_source_changed (GstElement       *pipeline,
-                   GParamSpec       *pspec,
-                   ClutterGstPlayer *player)
-{
-  ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-
-  player_set_user_agent (player, priv->user_agent);
-}
-
-static void
-query_duration (ClutterGstPlayer *player)
-{
-  ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-  gboolean success;
-  gint64 duration;
-  gdouble new_duration, difference;
-
-  success = gst_element_query_duration (priv->pipeline,
-                                        GST_FORMAT_TIME,
-                                        &duration);
-  if (G_UNLIKELY (success != TRUE))
-    return;
-
-  new_duration = (gdouble) duration / GST_SECOND;
-
-  /* while we store the new duration if it sligthly changes, the duration
-   * signal is sent only if the new duration is at least one second different
-   * from the old one (as the duration signal is mainly used to update the
-   * time displayed in a UI */
-  difference = ABS (priv->duration - new_duration);
-  if (difference > 1e-3)
-    {
-      CLUTTER_GST_NOTE (MEDIA, "duration: %.02f", new_duration);
-      priv->duration = new_duration;
-
-      if (difference > 1.0)
-        g_object_notify (G_OBJECT (player), "duration");
-    }
-}
-
-static void
-bus_message_duration_changed_cb (GstBus           *bus,
-                                 GstMessage       *message,
-                                 ClutterGstPlayer *player)
-{
-  /* GstElements send a duration-changed message on the bus to signal
-   * that the duration has changed and should be re-queried */
-  query_duration (player);
-}
-
-static void
-bus_message_state_change_cb (GstBus           *bus,
-                             GstMessage       *message,
-                             ClutterGstPlayer *player)
-{
-  ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-  GstState old_state, new_state;
-  gpointer src;
-
-  src = GST_MESSAGE_SRC (message);
-  if (src != priv->pipeline)
-    return;
-
-  gst_message_parse_state_changed (message, &old_state, &new_state, NULL);
-
-  CLUTTER_GST_NOTE (MEDIA, "state change:  %s -> %s",
-                    gst_state_to_string (old_state),
-                    gst_state_to_string (new_state));
-
-  if (old_state == new_state)
-    return;
-
-  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 (priv->pipeline, query))
-        {
-          gboolean can_seek = FALSE;
-
-          gst_query_parse_seeking (query, NULL, &can_seek,
-                                   NULL,
-                                   NULL);
-
-          priv->can_seek = (can_seek == TRUE) ? TRUE : FALSE;
-        }
-      else
-        {
-         /* could not query for ability to seek by querying the
-           * pipeline; let's crudely try by using the URI
-          */
-         if (priv->uri && g_str_has_prefix (priv->uri, "http://";))
-            priv->can_seek = FALSE;
-          else
-            priv->can_seek = TRUE;
-       }
-
-      gst_query_unref (query);
-
-      CLUTTER_GST_NOTE (MEDIA, "can-seek: %d", priv->can_seek);
-
-      g_object_notify (G_OBJECT (player), "can-seek");
-
-      query_duration (player);
-    }
-
-  /* is_idle controls the drawing with the idle material */
-  if (new_state == GST_STATE_NULL)
-    {
-      priv->is_idle = TRUE;
-      g_object_notify (G_OBJECT (player), "idle");
-    }
-  else if (new_state == GST_STATE_PLAYING)
-    {
-      priv->is_idle = FALSE;
-      priv->is_changing_uri = FALSE;
-      g_object_notify (G_OBJECT (player), "idle");
-    }
-
-  if (!priv->is_idle)
-    {
-      if (priv->stacked_progress)
-        {
-          set_progress (player, priv->stacked_progress);
-        }
-    }
-}
-
-static void
-bus_message_async_done_cb (GstBus           *bus,
-                           GstMessage       *message,
-                           ClutterGstPlayer *player)
-{
-  ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-
-  if (priv->in_seek)
-    {
-      g_object_notify (G_OBJECT (player), "progress");
-
-      set_in_seek (player, FALSE);
-
-      if (priv->stacked_progress)
-        {
-          set_progress (player, priv->stacked_progress);
-        }
-    }
-}
-
-static gboolean
-on_volume_changed_main_context (gpointer data)
-{
-  ClutterGstPlayer *player = CLUTTER_GST_PLAYER (data);
-  ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-  gdouble volume;
-
-  volume =
-    gst_stream_volume_get_volume (GST_STREAM_VOLUME (priv->pipeline),
-                                  GST_STREAM_VOLUME_FORMAT_CUBIC);
-  priv->volume = volume;
-
-  g_object_notify (G_OBJECT (player), "audio-volume");
-
-  g_object_unref (player);
-
-  return FALSE;
-}
-
-/* playbin proxies the volume property change notification directly from
- * the element having the "volume" property. This means this callback is
- * called from the thread that runs the element, potentially different from
- * the main thread */
-static void
-on_volume_changed (GstElement       *pipeline,
-                  GParamSpec       *pspec,
-                  ClutterGstPlayer *player)
-{
-  g_idle_add (on_volume_changed_main_context, g_object_ref (player));
-}
-
-static GList *
-get_tags (GstElement  *pipeline,
-          const gchar *property_name,
-          const gchar *action_signal)
-{
-  GList *ret = NULL;
-  gint i, n;
-
-  g_object_get (G_OBJECT (pipeline), property_name, &n, NULL);
-  if (n == 0)
-    return NULL;
-
-  for (i = 0; i < n; i++)
-    {
-      GstTagList *tags = NULL;
-
-      g_signal_emit_by_name (G_OBJECT (pipeline), action_signal, i, &tags);
-
-      ret = g_list_prepend (ret, tags);
-    }
-
-  return g_list_reverse (ret);
-}
-
-static gboolean
-on_audio_changed_main_context (gpointer data)
-{
-  ClutterGstPlayer *player = CLUTTER_GST_PLAYER (data);
-  ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-
-  free_tags_list (&priv->audio_streams);
-  priv->audio_streams = get_tags (priv->pipeline, "n-audio", "get-audio-tags");
-
-  CLUTTER_GST_NOTE (AUDIO_STREAM, "audio-streams changed");
-
-  g_object_notify (G_OBJECT (player), "audio-streams");
-
-  g_object_unref (player);
-
-  return FALSE;
-}
-
-/* same explanation as for notify::volume's usage of g_idle_add() */
-static void
-on_audio_changed (GstElement       *pipeline,
-                  ClutterGstPlayer *player)
-{
-  g_idle_add (on_audio_changed_main_context, g_object_ref (player));
-}
-
-static void
-on_audio_tags_changed (GstElement       *pipeline,
-                       gint              stream,
-                       ClutterGstPlayer *player)
-{
-  gint current_stream;
-
-  g_object_get (G_OBJECT (pipeline), "current-audio", &current_stream, NULL);
-
-  if (current_stream != stream)
-    return;
-
-  g_idle_add (on_audio_changed_main_context, g_object_ref (player));
-}
-
-static gboolean
-on_current_audio_changed_main_context (gpointer data)
-{
-  ClutterGstPlayer *player = CLUTTER_GST_PLAYER (data);
-
-  CLUTTER_GST_NOTE (AUDIO_STREAM, "audio stream changed");
-  g_object_notify (G_OBJECT (player), "audio-stream");
-
-  g_object_unref (player);
-
-  return FALSE;
-}
-
-static void
-on_current_audio_changed (GstElement       *pipeline,
-                          GParamSpec       *pspec,
-                          ClutterGstPlayer *player)
-{
-  g_idle_add (on_current_audio_changed_main_context, g_object_ref (player));
-}
-
-static gboolean
-on_text_changed_main_context (gpointer data)
-{
-  ClutterGstPlayer *player = CLUTTER_GST_PLAYER (data);
-  ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-
-  free_tags_list (&priv->subtitle_tracks);
-  priv->subtitle_tracks = get_tags (priv->pipeline, "n-text", "get-text-tags");
-
-  CLUTTER_GST_NOTE (AUDIO_STREAM, "subtitle-tracks changed");
-
-  g_object_notify (G_OBJECT (player), "subtitle-tracks");
-
-  g_object_unref (player);
-
-  return FALSE;
-}
-
-/* same explanation as for notify::volume's usage of g_idle_add() */
-static void
-on_text_changed (GstElement       *pipeline,
-                  ClutterGstPlayer *player)
-{
-  g_idle_add (on_text_changed_main_context, g_object_ref (player));
-}
-
-static void
-on_text_tags_changed (GstElement       *pipeline,
-                       gint              stream,
-                       ClutterGstPlayer *player)
-{
-  g_idle_add (on_text_changed_main_context, g_object_ref (player));
-}
-
-static gboolean
-on_current_text_changed_main_context (gpointer data)
-{
-  ClutterGstPlayer *player = CLUTTER_GST_PLAYER (data);
-
-  CLUTTER_GST_NOTE (AUDIO_STREAM, "text stream changed");
-  g_object_notify (G_OBJECT (player), "subtitle-track");
-
-  g_object_unref (player);
-
-  return FALSE;
-}
-
-static void
-on_current_text_changed (GstElement       *pipeline,
-                          GParamSpec       *pspec,
-                          ClutterGstPlayer *player)
-{
-  g_idle_add (on_current_text_changed_main_context, g_object_ref (player));
-}
-
-/* GObject's magic/madness */
-
-static void
-clutter_gst_player_set_property (GObject      *object,
-                                 guint         property_id,
-                                 const GValue *value,
-                                 GParamSpec   *pspec)
-{
-  ClutterGstPlayer *player = CLUTTER_GST_PLAYER (object);
-  ClutterGstPlayerIfacePrivate *iface_priv;
-
-  switch (property_id)
-    {
-    case PROP_URI:
-      set_uri (player, g_value_get_string (value));
-      break;
-
-    case PROP_PLAYING:
-      set_playing (player, g_value_get_boolean (value));
-      break;
-
-    case PROP_PROGRESS:
-      set_progress (player, g_value_get_double (value));
-      break;
-
-    case PROP_SUBTITLE_URI:
-      set_subtitle_uri (player, g_value_get_string (value));
-      break;
-
-    case PROP_SUBTITLE_FONT_NAME:
-      set_subtitle_font_name (player, g_value_get_string (value));
-      break;
-
-    case PROP_AUDIO_VOLUME:
-      set_audio_volume (player, g_value_get_double (value));
-      break;
-
-    case PROP_USER_AGENT:
-      clutter_gst_player_set_user_agent (player,
-                                         g_value_get_string (value));
-      break;
-
-    case PROP_SEEK_FLAGS:
-      clutter_gst_player_set_seek_flags (player,
-                                         g_value_get_flags (value));
-      break;
-
-    case PROP_AUDIO_STREAM:
-      clutter_gst_player_set_audio_stream (player,
-                                           g_value_get_int (value));
-      break;
-
-    case PROP_SUBTITLE_TRACK:
-      clutter_gst_player_set_subtitle_track (player,
-                                             g_value_get_int (value));
-      break;
-
-    default:
-      iface_priv = PLAYER_GET_CLASS_PRIVATE (object);
-      iface_priv->set_property (object, property_id, value, pspec);
-    }
-}
-
-
-static void
-clutter_gst_player_get_property (GObject    *object,
-                                 guint       property_id,
-                                 GValue     *value,
-                                 GParamSpec *pspec)
-{
-  ClutterGstPlayer *player = CLUTTER_GST_PLAYER (object);
-  ClutterGstPlayerPrivate *priv = PLAYER_GET_PRIVATE (player);
-  ClutterGstPlayerIfacePrivate *iface_priv;
-  gchar *str;
-
-  switch (property_id)
-    {
-    case PROP_URI:
-      g_value_set_string (value, priv->uri);
-      break;
-
-    case PROP_PLAYING:
-      g_value_set_boolean (value, get_playing (player));
-      break;
-
-    case PROP_PROGRESS:
-      g_value_set_double (value, get_progress (player));
-      break;
-
-    case PROP_SUBTITLE_URI:
-      g_object_get (priv->pipeline, "suburi", &str, NULL);
-      g_value_take_string (value, str);
-      break;
-
-    case PROP_SUBTITLE_FONT_NAME:
-      g_value_set_string (value, priv->font_name);
-      break;
-
-    case PROP_AUDIO_VOLUME:
-      g_value_set_double (value, get_audio_volume (player));
-      break;
-
-    case PROP_CAN_SEEK:
-      g_value_set_boolean (value, priv->can_seek);
-      break;
-
-    case PROP_BUFFER_FILL:
-      g_value_set_double (value, priv->buffer_fill);
-      break;
-
-    case PROP_DURATION:
-      g_value_set_double (value, priv->duration);
-      break;
-
-    case PROP_IDLE:
-      g_value_set_boolean (value, priv->is_idle);
-      break;
-
-    case PROP_USER_AGENT:
-      {
-        gchar *user_agent;
-
-        user_agent = clutter_gst_player_get_user_agent (player);
-        g_value_take_string (value, user_agent);
-      }
-      break;
-
-    case PROP_SEEK_FLAGS:
-      {
-        ClutterGstSeekFlags seek_flags;
-
-        seek_flags = clutter_gst_player_get_seek_flags (player);
-        g_value_set_flags (value, seek_flags);
-      }
-      break;
-
-    case PROP_AUDIO_STREAMS:
-      g_value_set_pointer (value, priv->audio_streams);
-      break;
-
-    case PROP_AUDIO_STREAM:
-      {
-        gint index_;
-
-        index_ = clutter_gst_player_get_audio_stream (player);
-        g_value_set_int (value, index_);
-      }
-      break;
-
-    case PROP_SUBTITLE_TRACKS:
-      g_value_set_pointer (value, priv->subtitle_tracks);
-      break;
-
-    case PROP_SUBTITLE_TRACK:
-      {
-        gint index_;
-
-        index_ = clutter_gst_player_get_subtitle_track (player);
-        g_value_set_int (value, index_);
-      }
-      break;
-
-    case PROP_IN_SEEK:
-      g_value_set_boolean (value, priv->in_seek);
-      break;
-
-    default:
-      iface_priv = PLAYER_GET_CLASS_PRIVATE (object);
-      iface_priv->get_property (object, property_id, value, pspec);
-    }
-}
-
-/**
- * clutter_gst_player_class_init:
- * @object_class: a #GObjectClass
- *
- * Adds the #ClutterGstPlayer properties to a class and surchages the
- * set/get_property of #GObjectClass. You should call this
- * function at the end of the class_init method of the class
- * implementing #ClutterGstPlayer.
- *
- * Since: 1.4
- */
-void
-clutter_gst_player_class_init (GObjectClass *object_class)
-{
-  ClutterGstPlayerIfacePrivate *priv;
-
-  priv = g_new0 (ClutterGstPlayerIfacePrivate, 1);
-  g_type_set_qdata (G_OBJECT_CLASS_TYPE (object_class),
-                    clutter_gst_player_class_quark,
-                    priv);
-
-  /* Save object's methods we want to override */
-  priv->set_property = object_class->set_property;
-  priv->get_property = object_class->get_property;
-
-  /* Replace by our methods */
-  object_class->set_property = clutter_gst_player_set_property;
-  object_class->get_property = clutter_gst_player_get_property;
-
-  /* Override ClutterGstPlayer's properties */
-  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_PROGRESS, "progress");
-  g_object_class_override_property (object_class,
-                                    PROP_SUBTITLE_URI, "subtitle-uri");
-  g_object_class_override_property (object_class,
-                                    PROP_SUBTITLE_FONT_NAME,
-                                    "subtitle-font-name");
-  g_object_class_override_property (object_class,
-                                    PROP_AUDIO_VOLUME, "audio-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_FILL, "buffer-fill");
-
-  g_object_class_override_property (object_class,
-                                    PROP_IDLE, "idle");
-  g_object_class_override_property (object_class,
-                                    PROP_USER_AGENT, "user-agent");
-  g_object_class_override_property (object_class,
-                                    PROP_SEEK_FLAGS, "seek-flags");
-
-  g_object_class_override_property (object_class,
-                                    PROP_AUDIO_STREAMS, "audio-streams");
-  g_object_class_override_property (object_class,
-                                    PROP_AUDIO_STREAM, "audio-stream");
-
-  g_object_class_override_property (object_class,
-                                    PROP_SUBTITLE_TRACKS, "subtitle-tracks");
-  g_object_class_override_property (object_class,
-                                    PROP_SUBTITLE_TRACK, "subtitle-track");
-  g_object_class_override_property (object_class,
-                                    PROP_IN_SEEK, "in-seek");
-}
-
-static GstElement *
-get_pipeline (void)
-{
-  GstElement *pipeline, *audio_sink;
-
-  pipeline = gst_element_factory_make ("playbin", "pipeline");
-  if (!pipeline)
-    {
-      g_critical ("Unable to create playbin element");
-      return NULL;
-    }
-
-  audio_sink = gst_element_factory_make ("gconfaudiosink", "audio-sink");
-  if (!audio_sink)
-    {
-      audio_sink = gst_element_factory_make ("autoaudiosink", "audio-sink");
-      if (!audio_sink)
-       {
-         audio_sink = gst_element_factory_make ("alsasink", "audio-sink");
-         g_warning ("Could not create a GST audio_sink. "
-                    "Audio unavailable.");
-
-          /* do we even need to bother? */
-         if (!audio_sink)
-           audio_sink = gst_element_factory_make ("fakesink", "audio-sink");
-       }
-    }
-
-  g_object_set (G_OBJECT (pipeline),
-                "audio-sink", audio_sink,
-                "subtitle-font-desc", "Sans 16",
-                NULL);
-
-  return pipeline;
-}
-
-/* ClutterGstPlayerIface implementation */
-
-static GstElement *
-clutter_gst_player_get_pipeline_impl (ClutterGstPlayer *player)
-{
-  ClutterGstPlayerPrivate *priv;
-
-  priv = PLAYER_GET_PRIVATE (player);
-
-  return priv->pipeline;
-}
-
-static gchar *
-clutter_gst_player_get_user_agent_impl (ClutterGstPlayer *player)
-{
-  ClutterGstPlayerPrivate *priv;
-  GstElement *source;
-  GParamSpec *pspec;
-  gchar *user_agent;
-
-  priv = PLAYER_GET_PRIVATE (player);
-
-  /* If the user has set a custom user agent, we just return it even if it is
-   * not used by the current source element of the pipeline */
-  if (priv->user_agent)
-    return g_strdup (priv->user_agent);
-
-  /* If not, we try to retrieve the user agent used by the current source */
-  g_object_get (priv->pipeline, "source", &source, NULL);
-  if (source == NULL)
-    return NULL;
-
-  pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (source),
-                                        "user-agent");
-  if (pspec == NULL)
-    return NULL;
-
-  g_object_get (source, "user-agent", &user_agent, NULL);
-
-  return user_agent;
-}
-
-static void
-clutter_gst_player_set_user_agent_impl (ClutterGstPlayer *player,
-                                        const gchar      *user_agent)
-{
-  ClutterGstPlayerPrivate *priv;
-
-  priv = PLAYER_GET_PRIVATE (player);
-
-  g_free (priv->user_agent);
-  if (user_agent)
-    priv->user_agent = g_strdup (user_agent);
-  else
-    priv->user_agent = NULL;
-
-  player_set_user_agent (player, user_agent);
-}
-
-static ClutterGstSeekFlags
-clutter_gst_player_get_seek_flags_impl (ClutterGstPlayer *player)
-{
-  ClutterGstPlayerPrivate *priv;
-
-  priv = PLAYER_GET_PRIVATE (player);
-
-  if (priv->seek_flags == GST_SEEK_FLAG_ACCURATE)
-    return CLUTTER_GST_SEEK_FLAG_ACCURATE;
-  else
-    return CLUTTER_GST_SEEK_FLAG_NONE;
-}
-
-static void
-clutter_gst_player_set_seek_flags_impl (ClutterGstPlayer    *player,
-                                        ClutterGstSeekFlags  flags)
-{
-  ClutterGstPlayerPrivate *priv;
-
-  priv = PLAYER_GET_PRIVATE (player);
-
-  if (flags == CLUTTER_GST_SEEK_FLAG_NONE)
-    priv->seek_flags = GST_SEEK_FLAG_KEY_UNIT;
-  else if (flags & CLUTTER_GST_SEEK_FLAG_ACCURATE)
-    priv->seek_flags = GST_SEEK_FLAG_ACCURATE;
-}
-
-static ClutterGstBufferingMode
-clutter_gst_player_get_buffering_mode_impl (ClutterGstPlayer *player)
-{
-  ClutterGstPlayerPrivate *priv;
-  GstPlayFlags flags;
-
-  priv = PLAYER_GET_PRIVATE (player);
-
-  g_object_get (G_OBJECT (priv->pipeline), "flags", &flags, NULL);
-
-  if (flags & GST_PLAY_FLAG_DOWNLOAD)
-    return CLUTTER_GST_BUFFERING_MODE_DOWNLOAD;
-
-  return CLUTTER_GST_BUFFERING_MODE_STREAM;
-}
-
-static void
-clutter_gst_player_set_buffering_mode_impl (ClutterGstPlayer        *player,
-                                            ClutterGstBufferingMode  mode)
-{
-  ClutterGstPlayerPrivate *priv;
-  GstPlayFlags flags;
-
-  priv = PLAYER_GET_PRIVATE (player);
-
-  g_object_get (G_OBJECT (priv->pipeline), "flags", &flags, NULL);
-
-  switch (mode)
-    {
-    case CLUTTER_GST_BUFFERING_MODE_STREAM:
-      flags &= ~GST_PLAY_FLAG_DOWNLOAD;
-      break;
-
-    case CLUTTER_GST_BUFFERING_MODE_DOWNLOAD:
-      flags |= GST_PLAY_FLAG_DOWNLOAD;
-      break;
-
-    default:
-      g_warning ("Unexpected buffering mode %d", mode);
-      break;
-    }
-
-  g_object_set (G_OBJECT (priv->pipeline), "flags", flags, NULL);
-}
-
-static gint
-clutter_gst_player_get_buffer_size_impl (ClutterGstPlayer *player)
-{
-  ClutterGstPlayerPrivate *priv;
-  gint size;
-
-  priv = PLAYER_GET_PRIVATE (player);
-
-  g_object_get (G_OBJECT (priv->pipeline), "buffer-size", &size, NULL);
-
-  return size;
-}
-
-static void
-clutter_gst_player_set_buffer_size_impl (ClutterGstPlayer *player,
-                                         gint              size)
-{
-  ClutterGstPlayerPrivate *priv;
-
-  priv = PLAYER_GET_PRIVATE (player);
-
-  g_object_set (G_OBJECT (priv->pipeline), "buffer-size", size, NULL);
-}
-
-static gint64
-clutter_gst_player_get_buffer_duration_impl (ClutterGstPlayer *player)
-{
-  ClutterGstPlayerPrivate *priv;
-  gint64 duration;
-
-  priv = PLAYER_GET_PRIVATE (player);
-
-  g_object_get (G_OBJECT (priv->pipeline), "buffer-duration", &duration, NULL);
-
-  return duration;
-}
-
-static void
-clutter_gst_player_set_buffer_duration_impl (ClutterGstPlayer *player,
-                                             gint64            duration)
-{
-  ClutterGstPlayerPrivate *priv;
-
-  priv = PLAYER_GET_PRIVATE (player);
-
-  g_object_set (G_OBJECT (priv->pipeline), "buffer-duration", duration, NULL);
-}
-
-static GList *
-clutter_gst_player_get_audio_streams_impl (ClutterGstPlayer *player)
-{
-  ClutterGstPlayerPrivate *priv;
-
-  priv = PLAYER_GET_PRIVATE (player);
-
-  if (CLUTTER_GST_DEBUG_ENABLED (AUDIO_STREAM))
-    {
-      gchar *streams;
-
-      streams = list_to_string (priv->audio_streams);
-      CLUTTER_GST_NOTE (AUDIO_STREAM, "audio streams: %s", streams);
-      g_free (streams);
-    }
-
-  return priv->audio_streams;
-}
-
-static gint
-clutter_gst_player_get_audio_stream_impl (ClutterGstPlayer *player)
-{
-  ClutterGstPlayerPrivate *priv;
-  gint index_ = -1;
-
-  priv = PLAYER_GET_PRIVATE (player);
-
-  g_object_get (G_OBJECT (priv->pipeline),
-                "current-audio", &index_,
-                NULL);
-
-  CLUTTER_GST_NOTE (AUDIO_STREAM, "audio stream is #%d", index_);
-
-  return index_;
-}
-
-static void
-clutter_gst_player_set_audio_stream_impl (ClutterGstPlayer *player,
-                                          gint              index_)
-{
-  ClutterGstPlayerPrivate *priv;
-
-  priv = PLAYER_GET_PRIVATE (player);
-
-  g_return_if_fail (index_ >= 0 &&
-                    index_ < (gint) g_list_length (priv->audio_streams));
-
-  CLUTTER_GST_NOTE (AUDIO_STREAM, "set audio audio stream to #%d", index_);
-
-  g_object_set (G_OBJECT (priv->pipeline),
-                "current-audio", index_,
-                NULL);
-}
-
-static GList *
-clutter_gst_player_get_subtitle_tracks_impl (ClutterGstPlayer *player)
-{
-  ClutterGstPlayerPrivate *priv;
-
-  priv = PLAYER_GET_PRIVATE (player);
-
-  if (CLUTTER_GST_DEBUG_ENABLED (SUBTITLES))
-    {
-      gchar *tracks;
-
-      tracks = list_to_string (priv->subtitle_tracks);
-      CLUTTER_GST_NOTE (SUBTITLES, "subtitle tracks: %s", tracks);
-      g_free (tracks);
-    }
-
-  return priv->subtitle_tracks;
-}
-
-static gint
-clutter_gst_player_get_subtitle_track_impl (ClutterGstPlayer *player)
-{
-  ClutterGstPlayerPrivate *priv;
-  gint index_ = -1;
-
-  priv = PLAYER_GET_PRIVATE (player);
-
-  g_object_get (G_OBJECT (priv->pipeline),
-                "current-text", &index_,
-                NULL);
-
-  CLUTTER_GST_NOTE (SUBTITLES, "text track is #%d", index_);
-
-  return index_;
-}
-
-static void
-clutter_gst_player_set_subtitle_track_impl (ClutterGstPlayer *player,
-                                            gint              index_)
-{
-  ClutterGstPlayerPrivate *priv;
-  GstPlayFlags flags;
-
-  priv = PLAYER_GET_PRIVATE (player);
-
-  g_return_if_fail (index_ >= -1 &&
-                    index_ < (gint) g_list_length (priv->subtitle_tracks));
-
-  CLUTTER_GST_NOTE (SUBTITLES, "set subtitle track to #%d", index_);
-
-  g_object_get (priv->pipeline, "flags", &flags, NULL);
-  flags &= ~GST_PLAY_FLAG_TEXT;
-  g_object_set (priv->pipeline, "flags", flags, NULL);
-
-  if (index_ >= 0)
-    {
-      g_object_set (G_OBJECT (priv->pipeline),
-                    "current-text", index_,
-                    NULL);
-
-      flags |= GST_PLAY_FLAG_TEXT;
-      g_object_set (priv->pipeline, "flags", flags, NULL);
-    }
-}
-
-static gboolean
-clutter_gst_player_get_idle_impl (ClutterGstPlayer *player)
-{
-  ClutterGstPlayerPrivate *priv;
-
-  priv = PLAYER_GET_PRIVATE (player);
-
-  return priv->is_idle;
-}
-
-static gboolean
-clutter_gst_player_get_in_seek_impl (ClutterGstPlayer *player)
-{
-  ClutterGstPlayerPrivate *priv;
-
-  priv = PLAYER_GET_PRIVATE (player);
-
-  return priv->in_seek;
-}
-
-static gboolean
-clutter_gst_player_is_live_media_impl (ClutterGstPlayer *player)
-{
-  ClutterGstPlayerPrivate *priv;
-
-  priv = PLAYER_GET_PRIVATE (player);
-
-  return priv->is_live;
-}
-
-/**/
-
-#if defined (CLUTTER_WINDOWING_X11) && defined (HAVE_HW_DECODER_SUPPORT)
-static GstBusSyncReply
-on_sync_message (GstBus * bus, GstMessage * message, gpointer user_data)
-{
-  Display *display = user_data;
-  GstVideoContext *context;
-  const gchar **types;
-
-  if (gst_video_context_message_parse_prepare (message, &types, &context)) {
-    gint i;
-
-    for (i = 0; types[i]; i++) {
-
-      if (!strcmp(types[i], "x11-display")) {
-        gst_video_context_set_context_pointer (context, "x11-display", display);
-      }
-      else if (!strcmp(types[i], "x11-display-name")) {
-        gst_video_context_set_context_string (context, "x11-display-name",
-            DisplayString (display));
-      } else {
-        continue;
-      }
-
-      gst_message_unref (message);
-      return GST_BUS_DROP;
-    }
-  }
-
-  return GST_BUS_PASS;
-}
-#endif
-
-/**
- * clutter_gst_player_init:
- * @player: a #ClutterGstPlayer
- *
- * Initialize a #ClutterGstPlayer instance. You should call this
- * function at the beginning of the init method of the class
- * implementing #ClutterGstPlayer.
- *
- * When you're finished with the ClutterGstPlayer mixin features (usually in
- * the dispose or finalize vfuncs), call clutter_gst_player_deinit() to
- * desallocate the resources created by clutter_gst_player_init().
- *
- * Return value: TRUE if the initialization was successfull, FALSE otherwise.
- *
- * Since: 1.4
- */
-gboolean
-clutter_gst_player_init (ClutterGstPlayer *player)
-{
-  ClutterGstPlayerPrivate *priv;
-  ClutterGstPlayerIface *iface;
-
-  g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), FALSE);
-
-  priv = PLAYER_GET_PRIVATE (player);
-  if (priv)
-    return TRUE;
-
-  iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
-
-  iface->get_pipeline = clutter_gst_player_get_pipeline_impl;
-  iface->get_user_agent = clutter_gst_player_get_user_agent_impl;
-  iface->set_user_agent = clutter_gst_player_set_user_agent_impl;
-  iface->get_seek_flags = clutter_gst_player_get_seek_flags_impl;
-  iface->set_seek_flags = clutter_gst_player_set_seek_flags_impl;
-  iface->get_buffering_mode = clutter_gst_player_get_buffering_mode_impl;
-  iface->set_buffering_mode = clutter_gst_player_set_buffering_mode_impl;
-  iface->get_buffer_size = clutter_gst_player_get_buffer_size_impl;
-  iface->set_buffer_size = clutter_gst_player_set_buffer_size_impl;
-  iface->get_buffer_duration = clutter_gst_player_get_buffer_duration_impl;
-  iface->set_buffer_duration = clutter_gst_player_set_buffer_duration_impl;
-  iface->get_audio_streams = clutter_gst_player_get_audio_streams_impl;
-  iface->get_audio_stream = clutter_gst_player_get_audio_stream_impl;
-  iface->set_audio_stream = clutter_gst_player_set_audio_stream_impl;
-  iface->get_subtitle_tracks = clutter_gst_player_get_subtitle_tracks_impl;
-  iface->get_subtitle_track = clutter_gst_player_get_subtitle_track_impl;
-  iface->set_subtitle_track = clutter_gst_player_set_subtitle_track_impl;
-  iface->get_idle = clutter_gst_player_get_idle_impl;
-  iface->get_in_seek = clutter_gst_player_get_in_seek_impl;
-  iface->is_live_media = clutter_gst_player_is_live_media_impl;
-
-  priv = g_slice_new0 (ClutterGstPlayerPrivate);
-  PLAYER_SET_PRIVATE (player, priv);
-
-  priv->is_idle = TRUE;
-  priv->in_seek = FALSE;
-  priv->is_changing_uri = FALSE;
-  priv->in_download_buffering = FALSE;
-
-  priv->pipeline = get_pipeline ();
-  if (!priv->pipeline)
-    {
-      g_critical ("Unable to create pipeline");
-      return FALSE;
-    }
-
-  g_signal_connect (priv->pipeline, "notify::source",
-                    G_CALLBACK (on_source_changed), player);
-
-  /* We default to not playing until someone calls set_playing(TRUE) */
-  priv->target_state = GST_STATE_PAUSED;
-
-  /* Default to a fast seek, ie. same effect than set_seek_flags (NONE); */
-  priv->seek_flags = GST_SEEK_FLAG_KEY_UNIT;
-
-  priv->bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline));
-
-  gst_bus_add_signal_watch (priv->bus);
-
-  g_signal_connect_object (priv->bus, "message::error",
-                          G_CALLBACK (bus_message_error_cb),
-                          player, 0);
-  g_signal_connect_object (priv->bus, "message::eos",
-                          G_CALLBACK (bus_message_eos_cb),
-                          player, 0);
-  g_signal_connect_object (priv->bus, "message::buffering",
-                          G_CALLBACK (bus_message_buffering_cb),
-                          player, 0);
-  g_signal_connect_object (priv->bus, "message::duration-changed",
-                          G_CALLBACK (bus_message_duration_changed_cb),
-                          player, 0);
-  g_signal_connect_object (priv->bus, "message::state-changed",
-                          G_CALLBACK (bus_message_state_change_cb),
-                          player, 0);
-  g_signal_connect_object (priv->bus, "message::async-done",
-                           G_CALLBACK (bus_message_async_done_cb),
-                           player, 0);
-
-  g_signal_connect (priv->pipeline, "notify::volume",
-                   G_CALLBACK (on_volume_changed),
-                    player);
-
-  g_signal_connect (priv->pipeline, "audio-changed",
-                    G_CALLBACK (on_audio_changed),
-                    player);
-  g_signal_connect (priv->pipeline, "audio-tags-changed",
-                    G_CALLBACK (on_audio_tags_changed),
-                    player);
-  g_signal_connect (priv->pipeline, "notify::current-audio",
-                    G_CALLBACK (on_current_audio_changed),
-                    player);
-
-  g_signal_connect (priv->pipeline, "text-changed",
-                    G_CALLBACK (on_text_changed),
-                    player);
-  g_signal_connect (priv->pipeline, "text-tags-changed",
-                    G_CALLBACK (on_text_tags_changed),
-                    player);
-  g_signal_connect (priv->pipeline, "notify::current-text",
-                    G_CALLBACK (on_current_text_changed),
-                    player);
-
-#if defined(CLUTTER_WINDOWING_X11) && defined (HAVE_HW_DECODER_SUPPORT)
-  gst_bus_set_sync_handler (priv->bus, on_sync_message,
-      clutter_x11_get_default_display (), NULL);
-#endif
-
-  gst_object_unref (GST_OBJECT (priv->bus));
-
-  return TRUE;
-}
-
-/**
- * clutter_gst_player_deinit:
- * @player: a #ClutterGstPlayer
- *
- * Frees the resources created by clutter_gst_player_init(). After
- * clutter_gst_player_deinit() has been called, no other player method can be
- * called on the instance.
- *
- * Since: 1.4
- */
-void
-clutter_gst_player_deinit (ClutterGstPlayer *player)
-{
-  ClutterGstPlayerPrivate *priv;
-
-  g_return_if_fail (CLUTTER_GST_IS_PLAYER (player));
-
-  priv = PLAYER_GET_PRIVATE (player);
-
-  if (priv == NULL)
-    return;
-
-  PLAYER_SET_PRIVATE (player, NULL);
-
-  if (priv->tick_timeout_id)
-    {
-      g_source_remove (priv->tick_timeout_id);
-      priv->tick_timeout_id = 0;
-    }
-
-  if (priv->buffering_timeout_id)
-    {
-      g_source_remove (priv->buffering_timeout_id);
-      priv->buffering_timeout_id = 0;
-    }
-
-  if (priv->download_buffering_element)
-    {
-      g_object_unref (priv->download_buffering_element);
-      priv->download_buffering_element = NULL;
-    }
-
-  gst_element_set_state (priv->pipeline, GST_STATE_NULL);
-
-  if (priv->bus)
-    {
-      gst_bus_remove_signal_watch (priv->bus);
-      priv->bus = NULL;
-    }
-
-  if (priv->pipeline)
-    {
-      gst_object_unref (GST_OBJECT (priv->pipeline));
-      priv->pipeline = NULL;
-    }
-
-  g_free (priv->uri);
-  g_free (priv->font_name);
-  g_free (priv->user_agent);
-  free_tags_list (&priv->audio_streams);
-  free_tags_list (&priv->subtitle_tracks);
-
-  g_slice_free (ClutterGstPlayerPrivate, priv);
-}
-
-static void
-clutter_gst_player_default_init (ClutterGstPlayerIface *iface)
-{
-  GParamSpec *pspec;
-
-  /**
-   * ClutterGstPlayer:uri:
-   *
-   * The location of a media file, expressed as a valid URI.
-   */
-  pspec = g_param_spec_string ("uri",
-                               "URI",
-                               "URI of a media file",
-                               NULL,
-                               CLUTTER_GST_PARAM_READWRITE |
-                               G_PARAM_DEPRECATED);
-  g_object_interface_install_property (iface, pspec);
-
-  /**
-   * ClutterGstPlayer:playing:
-   *
-   * Whether the #ClutterGstPlayer actor is playing.
-   */
-  pspec = g_param_spec_boolean ("playing",
-                                "Playing",
-                                "Whether the player is playing",
-                                FALSE,
-                                CLUTTER_GST_PARAM_READWRITE |
-                                G_PARAM_DEPRECATED);
-  g_object_interface_install_property (iface, pspec);
-
-  /**
-   * ClutterGstPlayer:progress:
-   *
-   * The current progress of the playback, as a normalized
-   * value between 0.0 and 1.0.
-   */
-  pspec = g_param_spec_double ("progress",
-                               "Progress",
-                               "Current progress of the playback",
-                               0.0, 1.0, 0.0,
-                               CLUTTER_GST_PARAM_READWRITE |
-                               G_PARAM_DEPRECATED);
-  g_object_interface_install_property (iface, pspec);
-
-  /**
-   * ClutterGstPlayer:subtitle-uri:
-   *
-   * The location of a subtitle file, expressed as a valid URI.
-   */
-  pspec = g_param_spec_string ("subtitle-uri",
-                               "Subtitle URI",
-                               "URI of a subtitle file",
-                               NULL,
-                               CLUTTER_GST_PARAM_READWRITE |
-                               G_PARAM_DEPRECATED);
-  g_object_interface_install_property (iface, pspec);
-
-  /**
-   * ClutterGstPlayer:subtitle-font-name:
-   *
-   * The font used to display subtitles. The font description has to
-   * follow the same grammar as the one recognized by
-   * pango_font_description_from_string().
-   */
-  pspec = g_param_spec_string ("subtitle-font-name",
-                               "Subtitle Font Name",
-                               "The font used to display subtitles",
-                               NULL,
-                               CLUTTER_GST_PARAM_READWRITE |
-                               G_PARAM_DEPRECATED);
-  g_object_interface_install_property (iface, pspec);
-
-  /**
-   * ClutterGstPlayer:audio-volume:
-   *
-   * The volume of the audio, as a normalized value between
-   * 0.0 and 1.0.
-   */
-  pspec = g_param_spec_double ("audio-volume",
-                               "Audio Volume",
-                               "The volume of the audio",
-                               0.0, 1.0, 0.5,
-                               CLUTTER_GST_PARAM_READWRITE |
-                               G_PARAM_DEPRECATED);
-  g_object_interface_install_property (iface, pspec);
-
-  /**
-   * ClutterGstPlayer:can-seek:
-   *
-   * Whether the current stream is seekable.
-   */
-  pspec = g_param_spec_boolean ("can-seek",
-                                "Can Seek",
-                                "Whether the current stream is seekable",
-                                FALSE,
-                                CLUTTER_GST_PARAM_READABLE |
-                                G_PARAM_DEPRECATED);
-  g_object_interface_install_property (iface, pspec);
-
-  /**
-   * ClutterGstPlayer:buffer-fill:
-   *
-   * The fill level of the buffer for the current stream,
-   * as a value between 0.0 and 1.0.
-   */
-  pspec = g_param_spec_double ("buffer-fill",
-                               "Buffer Fill",
-                               "The fill level of the buffer",
-                               0.0, 1.0, 0.0,
-                               CLUTTER_GST_PARAM_READABLE |
-                               G_PARAM_DEPRECATED);
-  g_object_interface_install_property (iface, pspec);
-
-  /**
-   * ClutterGstPlayer:duration:
-   *
-   * The duration of the current stream, in seconds
-   */
-  pspec = g_param_spec_double ("duration",
-                               "Duration",
-                               "The duration of the stream, in seconds",
-                               0, G_MAXDOUBLE, 0,
-                               CLUTTER_GST_PARAM_READABLE);
-  g_object_interface_install_property (iface, pspec);
-
-  /**
-   * ClutterGstPlayer:idle:
-   *
-   * Whether the #ClutterGstPlayer is in idle mode.
-   *
-   * Since: 1.4
-   */
-  pspec = g_param_spec_boolean ("idle",
-                                "Idle",
-                                "Idle state of the player's pipeline",
-                                TRUE,
-                                CLUTTER_GST_PARAM_READABLE);
-  g_object_interface_install_property (iface, pspec);
-
-  /**
-   * ClutterGstPlayer:user-agent:
-   *
-   * The User Agent used by #ClutterGstPlayer with network protocols.
-   *
-   * Since: 1.4
-   */
-  pspec = g_param_spec_string ("user-agent",
-                               "User Agent",
-                               "User Agent used with network protocols",
-                               NULL,
-                               CLUTTER_GST_PARAM_READWRITE);
-  g_object_interface_install_property (iface, pspec);
-
-  /**
-   * ClutterGstPlayer:seek-flags:
-   *
-   * Flags to use when seeking.
-   *
-   * Since: 1.4
-   */
-  pspec = g_param_spec_flags ("seek-flags",
-                              "Seek Flags",
-                              "Flags to use when seeking",
-                              CLUTTER_GST_TYPE_SEEK_FLAGS,
-                              CLUTTER_GST_SEEK_FLAG_NONE,
-                              CLUTTER_GST_PARAM_READWRITE);
-  g_object_interface_install_property (iface, pspec);
-
-  /**
-   * ClutterGstPlayer:audio-streams:
-   *
-   * List of audio streams available on the current media.
-   *
-   * Since: 1.4
-   */
-  pspec = g_param_spec_pointer ("audio-streams",
-                                "Audio Streams",
-                                "List of the audio streams of the media",
-                                CLUTTER_GST_PARAM_READABLE);
-  g_object_interface_install_property (iface, pspec);
-
-  /**
-   * ClutterGstPlayer:audio-stream:
-   *
-   * Index of the current audio stream.
-   *
-   * Since: 1.4
-   */
-  pspec = g_param_spec_int ("audio-stream",
-                            "Audio Stream",
-                            "Index of the current audio stream",
-                            -1, G_MAXINT, -1,
-                            CLUTTER_GST_PARAM_READWRITE);
-  g_object_interface_install_property (iface, pspec);
-
-  pspec = g_param_spec_pointer ("subtitle-tracks",
-                                "Subtitles Tracks",
-                                "List of the subtitles tracks of the media",
-                                CLUTTER_GST_PARAM_READABLE);
-  g_object_interface_install_property (iface, pspec);
-
-  pspec = g_param_spec_int ("subtitle-track",
-                            "Subtitles Track",
-                            "Index of the current subtitles track",
-                            -1, G_MAXINT, -1,
-                            CLUTTER_GST_PARAM_READWRITE);
-  g_object_interface_install_property (iface, pspec);
-
-
-  /**
-   * ClutterGstPlayer:in-seek:
-   *
-   * Whether or not the stream is being seeked.
-   *
-   * Since: 1.6
-   */
-  pspec = g_param_spec_boolean ("in-seek",
-                                "In seek mode",
-                                "If currently seeking",
-                                FALSE,
-                                CLUTTER_GST_PARAM_READABLE);
-  g_object_interface_install_property (iface, pspec);
-
-
-  /* Signals */
-
-  /**
-   * ClutterGstPlayer::eos:
-   * @media: the #ClutterGstPlayer instance that received the signal
-   *
-   * The ::eos signal is emitted each time the media stream ends.
-   */
-  signals[EOS_SIGNAL] =
-    g_signal_new ("eos",
-                  CLUTTER_GST_TYPE_PLAYER,
-                  G_SIGNAL_RUN_LAST,
-                  G_STRUCT_OFFSET (ClutterGstPlayerIface, eos),
-                  NULL, NULL,
-                  g_cclosure_marshal_VOID__VOID,
-                  G_TYPE_NONE, 0);
-  /**
-   * ClutterGstPlayer::error:
-   * @media: the #ClutterGstPlayer instance that received the signal
-   * @error: the #GError
-   *
-   * The ::error signal is emitted each time an error occurred.
-   */
-  signals[ERROR_SIGNAL] =
-    g_signal_new ("error",
-                  CLUTTER_GST_TYPE_PLAYER,
-                  G_SIGNAL_RUN_LAST,
-                  G_STRUCT_OFFSET (ClutterGstPlayerIface, error),
-                  NULL, NULL,
-                  g_cclosure_marshal_VOID__BOXED,
-                  G_TYPE_NONE, 1,
-                  G_TYPE_ERROR);
-
-  /**
-   * ClutterGstPlayer::download-buffering:
-   * @player: the #ClutterGstPlayer instance that received the signal
-   * @start: start position of the buffering
-   * @stop: start position of the buffering
-   *
-   * The ::download-buffering signal is emitted each time their an
-   * update about the buffering of the current media.
-   *
-   * Since: 1.4
-   */
-  signals[DOWNLOAD_BUFFERING_SIGNAL] =
-    g_signal_new ("download-buffering",
-                  CLUTTER_GST_TYPE_PLAYER,
-                  G_SIGNAL_RUN_LAST,
-                  G_STRUCT_OFFSET (ClutterGstPlayerIface,
-                                   download_buffering),
-                  NULL, NULL,
-                  _clutter_gst_marshal_VOID__DOUBLE_DOUBLE,
-                  G_TYPE_NONE, 2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
-
-  /* Setup a quark for per instance private data */
-  if (!clutter_gst_player_private_quark)
-    {
-      clutter_gst_player_private_quark =
-        g_quark_from_static_string ("clutter-gst-player-private-quark");
-      clutter_gst_player_class_quark =
-        g_quark_from_static_string ("clutter-gst-player-class-quark");
-    }
-}
-
-/* ClutterGstIface */
-
-/**
- * clutter_gst_player_get_pipeline:
- * @player: a #ClutterGstPlayer
- *
- * Retrieves the #GstPipeline used by the @player, for direct use with
- * GStreamer API.
- *
- * Return value: (transfer none): the #GstPipeline element used by the player
- *
- * Since: 1.4
- */
-GstElement *
-clutter_gst_player_get_pipeline (ClutterGstPlayer *player)
-{
-  ClutterGstPlayerIface *iface;
-
-  g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), NULL);
-
-  iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
-
-  return iface->get_pipeline (player);
-}
-
-/**
- * clutter_gst_player_set_uri:
- * @player: a #ClutterGstPlayer
- * @uri: the URI of the media stream
- *
- * Sets the URI of @player to @uri.
- */
-void
-clutter_gst_player_set_uri (ClutterGstPlayer *player,
-                            const gchar      *uri)
-{
-  g_return_if_fail (CLUTTER_GST_IS_PLAYER (player));
-
-  g_object_set (G_OBJECT (player), "uri", uri, NULL);
-}
-
-/**
- * clutter_gst_player_get_uri:
- * @player: a #ClutterGstPlayer
- *
- * Retrieves the URI from @player.
- *
- * Return value: the URI of the media stream. Use g_free()
- *   to free the returned string
- */
-gchar *
-clutter_gst_player_get_uri (ClutterGstPlayer *player)
-{
-  gchar *retval = NULL;
-
-  g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), NULL);
-
-  g_object_get (G_OBJECT (player), "uri", &retval, NULL);
-
-  return retval;
-}
-
-/**
- * clutter_gst_player_set_filename:
- * @player: a #ClutterGstPlayer
- * @filename: A filename
- *
- * Sets the source of @player using a file path.
- */
-void
-clutter_gst_player_set_filename (ClutterGstPlayer *player,
-                                 const gchar      *filename)
-{
-  gchar *uri;
-  GError *uri_error = NULL;
-
-  if (!g_path_is_absolute (filename))
-    {
-      gchar *abs_path;
-
-      abs_path = g_build_filename (g_get_current_dir (), filename, NULL);
-      uri = g_filename_to_uri (abs_path, NULL, &uri_error);
-      g_free (abs_path);
-    }
-  else
-    uri = g_filename_to_uri (filename, NULL, &uri_error);
-
-  if (uri_error)
-    {
-      g_signal_emit (player, signals[ERROR_SIGNAL], 0, uri_error);
-      g_error_free (uri_error);
-      return;
-    }
-
-  clutter_gst_player_set_uri (player, uri);
-
-  g_free (uri);
-}
-
-/**
- * clutter_gst_player_set_playing:
- * @player: a #ClutterGstPlayer
- * @playing: %TRUE to start playing
- *
- * Starts or stops playing of @player.
- *
- * The implementation might be asynchronous, so the way to know whether
- * the actual playing state of the @player is to use the #GObject::notify
- * signal on the #ClutterGstPlayer:playing property and then retrieve the
- * current state with clutter_gst_player_is_playing(). ClutterGstVideoActor
- * in clutter-gst is an example of such an asynchronous implementation.
- */
-void
-clutter_gst_player_set_playing (ClutterGstPlayer *player,
-                                gboolean          playing)
-{
-  g_return_if_fail (CLUTTER_GST_IS_PLAYER (player));
-
-  g_object_set (G_OBJECT (player), "playing", playing, NULL);
-}
-
-/**
- * clutter_gst_player_is_playing:
- * @player: A #ClutterGstPlayer object
- *
- * Retrieves the playing status of @player.
- *
- * Return value: %TRUE if playing, %FALSE if stopped.
- */
-gboolean
-clutter_gst_player_is_playing (ClutterGstPlayer *player)
-{
-  gboolean is_playing = FALSE;
-
-  g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), FALSE);
-
-  g_object_get (G_OBJECT (player), "playing", &is_playing, NULL);
-
-  return is_playing;
-}
-
-/**
- * clutter_gst_player_get_user_agent:
- * @player: a #ClutterGstPlayer
- *
- * Retrieves the user agent used when streaming.
- *
- * Return value: the user agent used. The returned string has to be freed with
- * g_free()
- *
- * Since: 1.4
- */
-gchar *
-clutter_gst_player_get_user_agent (ClutterGstPlayer *player)
-{
-  ClutterGstPlayerIface *iface;
-
-  g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), NULL);
-
-  iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
-
-  return iface->get_user_agent (player);
-}
-
-/**
- * clutter_gst_player_set_user_agent:
- * @player: a #ClutterGstPlayer
- * @user_agent: the user agent
- *
- * Sets the user agent to use when streaming.
- *
- * When streaming content, you might want to set a custom user agent, eg. to
- * promote your software, make it appear in statistics or because the server
- * requires a special user agent you want to impersonate.
- *
- * Since: 1.4
- */
-void
-clutter_gst_player_set_user_agent (ClutterGstPlayer *player,
-                                   const gchar      *user_agent)
-{
-  ClutterGstPlayerIface *iface;
-
-  g_return_if_fail (CLUTTER_GST_IS_PLAYER (player));
-
-  iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
-
-  iface->set_user_agent (player, user_agent);
-}
-
-/**
- * clutter_gst_player_get_seek_flags:
- * @player: a #ClutterGstPlayer
- *
- * Get the current value of the seek-flags property.
- *
- * Return value: a combination of #ClutterGstSeekFlags
- *
- * Since: 1.4
- */
-ClutterGstSeekFlags
-clutter_gst_player_get_seek_flags (ClutterGstPlayer *player)
-{
-  ClutterGstPlayerIface *iface;
-
-  g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player),
-                        CLUTTER_GST_SEEK_FLAG_NONE);
-
-  iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
-
-  return iface->get_seek_flags (player);
-}
-
-/**
- * clutter_gst_player_set_seek_flags:
- * @player: a #ClutterGstPlayer
- * @flags: a combination of #ClutterGstSeekFlags
- *
- * Seeking can be done with several trade-offs. Clutter-gst defaults
- * to %CLUTTER_GST_SEEK_FLAG_NONE.
- *
- * Since: 1.4
- */
-void
-clutter_gst_player_set_seek_flags (ClutterGstPlayer    *player,
-                                   ClutterGstSeekFlags  flags)
-{
-  ClutterGstPlayerIface *iface;
-
-  g_return_if_fail (CLUTTER_GST_IS_PLAYER (player));
-
-  iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
-
-  iface->set_seek_flags (player, flags);
-}
-
-/**
- * clutter_gst_player_get_buffering_mode:
- * @player: a #ClutterGstPlayer
- *
- * Return value: a #ClutterGstBufferingMode
- *
- * Since: 1.4
- */
-ClutterGstBufferingMode
-clutter_gst_player_get_buffering_mode (ClutterGstPlayer *player)
-{
-  ClutterGstPlayerIface *iface;
-
-  g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player),
-                        CLUTTER_GST_BUFFERING_MODE_STREAM);
-
-  iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
-
-  return iface->get_buffering_mode (player);
-}
-
-/**
- * clutter_gst_player_set_buffering_mode:
- * @player: a #ClutterGstPlayer
- * @mode: a #ClutterGstBufferingMode
- *
- * Since: 1.4
- */
-void
-clutter_gst_player_set_buffering_mode (ClutterGstPlayer        *player,
-                                       ClutterGstBufferingMode  mode)
-{
-  ClutterGstPlayerIface *iface;
-
-  g_return_if_fail (CLUTTER_GST_IS_PLAYER (player));
-
-  iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
-
-  iface->set_buffering_mode (player, mode);
-}
-
-/**
- * clutter_gst_player_get_buffer_fill:
- * @player: a #ClutterGstPlayer
- *
- * Retrieves the amount of the stream that is buffered.
- *
- * Return value: the fill level, between 0.0 and 1.0
- */
-gdouble
-clutter_gst_player_get_buffer_fill (ClutterGstPlayer *player)
-{
-  gdouble retval = 0.0;
-
-  g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), 0);
-
-  g_object_get (G_OBJECT (player), "buffer-fill", &retval, NULL);
-
-  return retval;
-}
-
-/*
- * clutter_gst_player_get_buffer_size:
- * @player: a #ClutterGstPlayer
- *
- * Retrieves the buffer size when buffering network streams.
- *
- * Return value: The buffer size
- */
-gint
-clutter_gst_player_get_buffer_size (ClutterGstPlayer *player)
-{
-  ClutterGstPlayerIface *iface;
-
-  g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), -1);
-
-  iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
-
-  return iface->get_buffer_size (player);
-}
-
-/**
- * clutter_gst_player_set_buffer_size:
- * @player: a #ClutterGstPlayer
- * @size: The new size
- *
- * Sets the buffer size to be used when buffering network streams.
- */
-void
-clutter_gst_player_set_buffer_size (ClutterGstPlayer *player,
-                                    gint              size)
-{
-  ClutterGstPlayerIface *iface;
-
-  g_return_if_fail (CLUTTER_GST_IS_PLAYER (player));
-
-  iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
-
-  iface->set_buffer_size (player, size);
-}
-
-/**
- * clutter_gst_player_get_buffer_duration:
- * @player: a #ClutterGstPlayer
- *
- * Retrieves the buffer duration when buffering network streams.
- *
- * Return value: The buffer duration
- */
-gint64
-clutter_gst_player_get_buffer_duration (ClutterGstPlayer *player)
-{
-  ClutterGstPlayerIface *iface;
-
-  g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), -1);
+#include "clutter-gst-player.h"
+#include "clutter-gst-private.h"
 
-  iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
+typedef ClutterGstPlayerIface ClutterGstPlayerInterface;
 
-  return iface->get_buffer_duration (player);
-}
+G_DEFINE_INTERFACE (ClutterGstPlayer, clutter_gst_player, G_TYPE_OBJECT)
 
-/**
- * clutter_gst_player_set_buffer_duration:
- * @player: a #ClutterGstPlayer
- * @duration: The new duration
- *
- * Sets the buffer duration to be used when buffering network streams.
- */
-void
-clutter_gst_player_set_buffer_duration (ClutterGstPlayer *player,
-                                        gint64            duration)
+enum
 {
-  ClutterGstPlayerIface *iface;
-
-  g_return_if_fail (CLUTTER_GST_IS_PLAYER (player));
+  NEW_FRAME,
+  READY_SIGNAL,
+  EOS_SIGNAL,
+  SIZE_CHANGE,
+  ERROR_SIGNAL, /* can't be called 'ERROR' otherwise it clashes with wingdi.h */
 
-  iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
+  LAST_SIGNAL
+};
 
-  iface->set_buffer_duration (player, duration);
-}
+static guint signals[LAST_SIGNAL] = { 0, };
 
-/**
- * clutter_gst_player_set_audio_volume:
- * @player: a #ClutterGstPlayer
- * @volume: the volume as a double between 0.0 and 1.0
- *
- * Sets the playback volume of @player to @volume.
- */
-void
-clutter_gst_player_set_audio_volume (ClutterGstPlayer *player,
-                                     gdouble           volume)
+static void
+clutter_gst_player_default_init (ClutterGstPlayerIface *iface)
 {
-  g_return_if_fail (CLUTTER_GST_IS_PLAYER (player));
+  GParamSpec *pspec;
 
-  g_object_set (G_OBJECT (player), "audio-volume", volume, NULL);
-}
+  /**
+   * ClutterGstPlayer:playing:
+   *
+   * Whether the #ClutterGstPlayer actor is playing.
+   */
+  pspec = g_param_spec_boolean ("playing",
+                                "Playing",
+                                "Whether the player is playing",
+                                FALSE,
+                                CLUTTER_GST_PARAM_READWRITE |
+                                G_PARAM_DEPRECATED);
+  g_object_interface_install_property (iface, pspec);
 
-/**
- * clutter_gst_player_get_audio_volume:
- * @player: a #ClutterGstPlayer
- *
- * Retrieves the playback volume of @player.
- *
- * Return value: The playback volume between 0.0 and 1.0
- */
-gdouble
-clutter_gst_player_get_audio_volume (ClutterGstPlayer *player)
-{
-  gdouble retval = 0.0;
+  /**
+   * ClutterGstPlayer:audio-volume:
+   *
+   * The volume of the audio, as a normalized value between
+   * 0.0 and 1.0.
+   */
+  pspec = g_param_spec_double ("audio-volume",
+                               "Audio Volume",
+                               "The volume of the audio",
+                               0.0, 1.0, 0.5,
+                               CLUTTER_GST_PARAM_READWRITE |
+                               G_PARAM_DEPRECATED);
+  g_object_interface_install_property (iface, pspec);
+
+  /**
+   * ClutterGstPlayer:idle:
+   *
+   * Whether the #ClutterGstPlayer is in idle mode.
+   *
+   * Since: 1.4
+   */
+  pspec = g_param_spec_boolean ("idle",
+                                "Idle",
+                                "Idle state of the player's pipeline",
+                                TRUE,
+                                CLUTTER_GST_PARAM_READABLE);
+  g_object_interface_install_property (iface, pspec);
 
-  g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), 0.0);
+  /* Signals */
 
-  g_object_get (G_OBJECT (player), "audio-volume", &retval, NULL);
+  /**
+   * ClutterGstPlayer::new-frame:
+   * @player: the #ClutterGstPlayer instance that received the signal
+   *
+   * The ::ready signal is emitted each time the gstreamer pipeline
+   * becomes ready.
+   */
+  signals[NEW_FRAME] =
+    g_signal_new ("new-frame",
+                  CLUTTER_GST_TYPE_PLAYER,
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (ClutterGstPlayerIface, new_frame),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__BOXED,
+                  G_TYPE_NONE, 1,
+                  CLUTTER_GST_TYPE_FRAME);
+  /**
+   * ClutterGstPlayer::ready:
+   * @player: the #ClutterGstPlayer instance that received the signal
+   *
+   * The ::ready signal is emitted each time the gstreamer pipeline
+   * becomes ready.
+   */
+  signals[READY_SIGNAL] =
+    g_signal_new ("ready",
+                  CLUTTER_GST_TYPE_PLAYER,
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (ClutterGstPlayerIface, ready),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+  /**
+   * ClutterGstPlayer::eos:
+   * @player: the #ClutterGstPlayer instance that received the signal
+   *
+   * The ::eos signal is emitted each time the media stream ends.
+   */
+  signals[EOS_SIGNAL] =
+    g_signal_new ("eos",
+                  CLUTTER_GST_TYPE_PLAYER,
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (ClutterGstPlayerIface, eos),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+  /**
+   * ClutterGstPlayer::error:
+   * @player: the #ClutterGstPlayer instance that received the signal
+   * @error: the #GError
+   *
+   * The ::error signal is emitted each time an error occurred.
+   */
+  signals[ERROR_SIGNAL] =
+    g_signal_new ("error",
+                  CLUTTER_GST_TYPE_PLAYER,
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (ClutterGstPlayerIface, error),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__BOXED,
+                  G_TYPE_NONE, 1,
+                  G_TYPE_ERROR);
 
-  return retval;
+  /**
+   * ClutterGstPlayer::size-change:
+   * @player: the #ClutterGstPlayer instance that received the signal
+   * @width: new width of the frames
+   * @height: new height of the frames
+   *
+   * The ::size-change signal is emitted each time the gstreamer pipeline
+   * becomes ready.
+   */
+  signals[SIZE_CHANGE] =
+    g_signal_new ("size-change",
+                  CLUTTER_GST_TYPE_PLAYER,
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (ClutterGstPlayerIface, size_change),
+                  NULL, NULL,
+                  _clutter_gst_marshal_VOID__INT_INT,
+                  G_TYPE_NONE, 2,
+                  G_TYPE_INT, G_TYPE_INT);
 }
 
+/* ClutterGstIface */
+
 /**
- * clutter_gst_player_get_audio_streams:
- * @player: a #ClutterGstPlayer
+ * clutter_gst_player_get_frame:
+ * @self: a #ClutterGstPlayer
  *
- * Get the list of audio streams of the current media.
+ * Retrieves the #CoglHandle of the last frame produced by @self.
  *
- * Return value: (transfer none) (element-type utf8): a list of
- * strings describing the available audio streams
+ * Return value: (transfer none): the #CoglHandle of the last frame.
  *
- * Since: 1.4
+ * Since: 3.0
  */
-GList *
-clutter_gst_player_get_audio_streams (ClutterGstPlayer *player)
+ClutterGstFrame *
+clutter_gst_player_get_frame (ClutterGstPlayer *self)
 {
   ClutterGstPlayerIface *iface;
 
-  g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), NULL);
+  g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (self), COGL_INVALID_HANDLE);
 
-  iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
+  iface = CLUTTER_GST_PLAYER_GET_INTERFACE (self);
 
-  return iface->get_audio_streams (player);
+  return iface->get_frame (self);
 }
 
 /**
- * clutter_gst_player_get_audio_stream:
- * @player: a #ClutterGstPlayer
+ * clutter_gst_player_get_pipeline:
+ * @self: a #ClutterGstPlayer
  *
- * Get the current audio stream. The number returned in the index of the
- * audio stream playing in the list returned by
- * clutter_gst_player_get_audio_streams().
+ * Retrieves the #GstPipeline used by the @self, for direct use with
+ * GStreamer API.
  *
- * Return value: the index of the current audio stream, -1 if the media has no
- * audio stream
+ * Return value: (transfer none): the #GstPipeline element used by the player
  *
- * Since: 1.4
+ * Since: 3.0
  */
-gint
-clutter_gst_player_get_audio_stream (ClutterGstPlayer *player)
+GstElement *
+clutter_gst_player_get_pipeline (ClutterGstPlayer *self)
 {
   ClutterGstPlayerIface *iface;
 
-  g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), -1);
+  g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (self), NULL);
 
-  iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
+  iface = CLUTTER_GST_PLAYER_GET_INTERFACE (self);
 
-  return iface->get_audio_stream (player);
+  return iface->get_pipeline (self);
 }
 
 /**
- * clutter_gst_player_set_audio_stream:
- * @player: a #ClutterGstPlayer
- * @index_: the index of the audio stream
+ * clutter_gst_player_get_playing:
+ * @self: A #ClutterGstPlayer object
+ *
+ * Retrieves the playing status of @self.
  *
- * Set the audio stream to play. @index_ is the index of the stream
- * in the list returned by clutter_gst_player_get_audio_streams().
+ * Return value: %TRUE if playing, %FALSE if stopped.
  *
- * Since: 1.4
+ * Since: 3.0
  */
-void
-clutter_gst_player_set_audio_stream (ClutterGstPlayer *player,
-                                     gint              index_)
+gboolean
+clutter_gst_player_get_playing (ClutterGstPlayer *self)
 {
   ClutterGstPlayerIface *iface;
 
-  g_return_if_fail (CLUTTER_GST_IS_PLAYER (player));
-
-  iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
-
-  iface->set_audio_stream (player, index_);
-}
+  g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (self), TRUE);
 
-/**
- * clutter_gst_player_set_subtitle_uri:
- * @player: a #ClutterGstPlayer
- * @uri: the URI of a subtitle file
- *
- * Sets the location of a subtitle file to display while playing @player.
- */
-void
-clutter_gst_player_set_subtitle_uri (ClutterGstPlayer *player,
-                                     const char       *uri)
-{
-  g_return_if_fail (CLUTTER_GST_IS_PLAYER (player));
+  iface = CLUTTER_GST_PLAYER_GET_INTERFACE (self);
 
-  g_object_set (G_OBJECT (player), "subtitle-uri", uri, NULL);
+  return iface->get_playing (self);
 }
 
 /**
- * clutter_gst_player_get_subtitle_uri:
- * @player: a #ClutterGstPlayer
- *
- * Retrieves the URI of the subtitle file in use.
+ * clutter_gst_player_set_playing:
+ * @self: a #ClutterGstPlayer
+ * @playing: %TRUE to start playing
  *
- * Return value: the URI of the subtitle file. Use g_free()
- *   to free the returned string
- */
-gchar *
-clutter_gst_player_get_subtitle_uri (ClutterGstPlayer *player)
-{
-  gchar *retval = NULL;
-
-  g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), NULL);
-
-  g_object_get (G_OBJECT (player), "subtitle-uri", &retval, NULL);
-
-  return retval;
-}
-
-/**
- * clutter_gst_player_set_subtitle_font_name:
- * @player: a #ClutterGstPlayer
- * @font_name: a font name, or %NULL to set the default font name
+ * Starts or stops playing of @self.
  *
- * Sets the font used by the subtitle renderer. The @font_name string must be
- * either %NULL, which means that the default font name of the underlying
- * implementation will be used; or must follow the grammar recognized by
- * pango_font_description_from_string() like:
+ * The implementation might be asynchronous, so the way to know whether
+ * the actual playing state of the @self is to use the #GObject::notify
+ * signal on the #ClutterGstPlayer:playing property and then retrieve the
+ * current state with clutter_gst_player_get_playing(). ClutterGstVideoActor
+ * in clutter-gst is an example of such an asynchronous implementation.
  *
- * |[
- *   clutter_gst_player_set_subtitle_font_name (player, "Sans 24pt");
- * ]|
+ * Since: 3.0
  */
 void
-clutter_gst_player_set_subtitle_font_name (ClutterGstPlayer *player,
-                                      const char   *font_name)
-{
-  g_return_if_fail (CLUTTER_GST_IS_PLAYER (player));
-
-  g_object_set (G_OBJECT (player), "subtitle-font-name", font_name, NULL);
-}
-
-/**
- * clutter_gst_player_get_subtitle_font_name:
- * @player: a #ClutterGstPlayer
- *
- * Retrieves the font name currently used.
- *
- * Return value: a string containing the font name. Use g_free()
- *   to free the returned string
- */
-gchar *
-clutter_gst_player_get_subtitle_font_name (ClutterGstPlayer *player)
-{
-  gchar *retval = NULL;
-
-  g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), NULL);
-
-  g_object_get (G_OBJECT (player), "subtitle-font-name", &retval, NULL);
-
-  return retval;
-}
-
-/**
- * clutter_gst_player_get_subtitle_tracks:
- * @player: a #ClutterGstPlayer
- *
- * Get the list of subtitles tracks of the current media.
- *
- * Return value: (transfer none) (element-type utf8): a list of
- * strings describing the available subtitles tracks
- *
- * Since: 1.4
- */
-GList *
-clutter_gst_player_get_subtitle_tracks (ClutterGstPlayer *player)
+clutter_gst_player_set_playing (ClutterGstPlayer *self,
+                                gboolean          playing)
 {
   ClutterGstPlayerIface *iface;
 
-  g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), NULL);
+  g_return_if_fail (CLUTTER_GST_IS_PLAYER (self));
 
-  iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
+  iface = CLUTTER_GST_PLAYER_GET_INTERFACE (self);
 
-  return iface->get_subtitle_tracks (player);
+  iface->set_playing (self, playing);
 }
 
 /**
- * clutter_gst_player_get_subtitle_track:
- * @player: a #ClutterGstPlayer
+ * clutter_gst_player_get_audio_volume:
+ * @self: a #ClutterGstPlayer
  *
- * Get the current subtitles track. The number returned is the index of the
- * subtiles track in the list returned by
- * clutter_gst_player_get_subtitle_tracks().
+ * Retrieves the playback volume of @self.
  *
- * Return value: the index of the current subtitlest track, -1 if the media has
- * no subtitles track or if the subtitles have been turned off
+ * Return value: The playback volume between 0.0 and 1.0
  *
- * Since: 1.4
+ * Since: 3.0
  */
-gint
-clutter_gst_player_get_subtitle_track (ClutterGstPlayer *player)
+gdouble
+clutter_gst_player_get_audio_volume (ClutterGstPlayer *self)
 {
   ClutterGstPlayerIface *iface;
 
-  g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), -1);
+  g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (self), TRUE);
 
-  iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
+  iface = CLUTTER_GST_PLAYER_GET_INTERFACE (self);
 
-  return iface->get_subtitle_track (player);
+  return iface->get_audio_volume (self);
 }
 
 /**
- * clutter_gst_player_set_subtitle_track:
- * @player: a #ClutterGstPlayer
- * @index_: the index of the subtitles track
- *
- * Set the subtitles track to play. @index_ is the index of the stream
- * in the list returned by clutter_gst_player_get_subtitle_tracks().
+ * clutter_gst_player_set_audio_volume:
+ * @self: a #ClutterGstPlayer
+ * @volume: the volume as a double between 0.0 and 1.0
  *
- * If @index_ is -1, the subtitles are turned off.
+ * Sets the playback volume of @self to @volume.
  *
- * Since: 1.4
+ * Since: 3.0
  */
 void
-clutter_gst_player_set_subtitle_track (ClutterGstPlayer *player,
-                                       gint              index_)
+clutter_gst_player_set_audio_volume (ClutterGstPlayer *self,
+                                     gdouble           volume)
 {
   ClutterGstPlayerIface *iface;
 
-  g_return_if_fail (CLUTTER_GST_IS_PLAYER (player));
+  g_return_if_fail (CLUTTER_GST_IS_PLAYER (self));
 
-  iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
+  iface = CLUTTER_GST_PLAYER_GET_INTERFACE (self);
 
-  iface->set_subtitle_track (player, index_);
+  iface->set_audio_volume (self, volume);
 }
 
 /**
  * clutter_gst_player_get_idle:
- * @player: a #ClutterGstPlayer
+ * @self: a #ClutterGstPlayer
  *
  * Get the idle state of the pipeline.
  *
  * Return value: TRUE if the pipline is in idle mode, FALSE otherwise.
  *
- * Since: 1.4
- */
-gboolean
-clutter_gst_player_get_idle (ClutterGstPlayer *player)
-{
-  ClutterGstPlayerIface *iface;
-
-  g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), TRUE);
-
-  iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
-
-  return iface->get_idle (player);
-}
-
-/**
- * clutter_gst_player_get_can_seek:
- * @player: a #ClutterGstPlayer
- *
- * Retrieves whether @player is seekable or not.
- *
- * Return value: %TRUE if @player can seek, %FALSE otherwise.
- */
-gboolean
-clutter_gst_player_get_can_seek (ClutterGstPlayer *player)
-{
-  gboolean retval = FALSE;
-
-  g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), FALSE);
-
-  g_object_get (G_OBJECT (player), "can-seek", &retval, NULL);
-
-  return retval;
-}
-
-/**
- * clutter_gst_player_get_in_seek:
- * @player: a #ClutterGstPlayer
- *
- * Whether the player is seeking.
- *
- * Return value: TRUE if the player is seeking, FALSE otherwise.
- *
- * Since: 1.6
- */
-gboolean
-clutter_gst_player_get_in_seek (ClutterGstPlayer *player)
-{
-  ClutterGstPlayerIface *iface;
-
-  g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), FALSE);
-
-  iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
-
-  return iface->get_in_seek (player);
-}
-
-/**
- * clutter_gst_player_set_progress:
- * @player: a #ClutterGstPlayer
- * @progress: the progress of the playback, between 0.0 and 1.0
- *
- * Sets the playback progress of @player. The @progress is
- * a normalized value between 0.0 (begin) and 1.0 (end).
- */
-void
-clutter_gst_player_set_progress (ClutterGstPlayer *player,
-                                 gdouble           progress)
-{
-  g_return_if_fail (CLUTTER_GST_IS_PLAYER (player));
-
-  g_object_set (G_OBJECT (player), "progress", progress, NULL);
-}
-
-/**
- * clutter_gst_player_get_progress:
- * @player: a #ClutterGstPlayer
- *
- * Retrieves the playback progress of @player.
- *
- * Return value: the playback progress, between 0.0 and 1.0
- */
-gdouble
-clutter_gst_player_get_progress (ClutterGstPlayer *player)
-{
-  gdouble retval = 0.0;
-
-  g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), 0);
-
-  g_object_get (G_OBJECT (player), "progress", &retval, NULL);
-
-  return retval;
-}
-
-/**
- * clutter_gst_player_get_duration:
- * @player: a #ClutterGstPlayer
- *
- * Retrieves the duration of the media stream that @player represents.
- *
- * Return value: the duration of the media stream, in seconds
- */
-gdouble
-clutter_gst_player_get_duration (ClutterGstPlayer *player)
-{
-  gdouble retval = 0;
-
-  g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), 0);
-
-  g_object_get (G_OBJECT (player), "duration", &retval, NULL);
-
-  return retval;
-}
-
-/**
- * clutter_gst_player_is_live_media:
- * @player: a #ClutterGstPlayer
- *
- * Whether the player is using a live media.
- *
- * Return value: TRUE if the player is using a live media, FALSE otherwise.
+ * Since: 3.0
  */
 gboolean
-clutter_gst_player_is_live_media (ClutterGstPlayer *player)
+clutter_gst_player_get_idle (ClutterGstPlayer *self)
 {
   ClutterGstPlayerIface *iface;
 
-  g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (player), FALSE);
+  g_return_val_if_fail (CLUTTER_GST_IS_PLAYER (self), TRUE);
 
-  iface = CLUTTER_GST_PLAYER_GET_INTERFACE (player);
+  iface = CLUTTER_GST_PLAYER_GET_INTERFACE (self);
 
-  return iface->is_live_media (player);
+  return iface->get_idle (self);
 }
diff --git a/clutter-gst/clutter-gst-player.h b/clutter-gst/clutter-gst-player.h
index 3626520..012d2e1 100644
--- a/clutter-gst/clutter-gst-player.h
+++ b/clutter-gst/clutter-gst-player.h
@@ -12,8 +12,7 @@
  *             Andre Moreira Magalhaes <andre magalhaes collabora co uk>
  *
  * Copyright (C) 2006 OpenedHand
- * Copyright (C) 2009-2011 Intel Corporation
- * Copyright (C) 2011 Intel Corporation
+ * Copyright (C) 2009-2013 Intel Corporation
  * Copyright (C) 2012 Collabora Ltd. <http://www.collabora.co.uk/>
  *
  * This library is free software; you can redistribute it and/or
@@ -36,8 +35,8 @@
 #define __CLUTTER_GST_PLAYER_H__
 
 #include <glib-object.h>
-
-#include <clutter/clutter.h>
+#include <cogl/cogl.h>
+#include <gst/gst.h>
 
 #include <clutter-gst/clutter-gst-types.h>
 
@@ -88,148 +87,60 @@ struct _ClutterGstPlayerIface
   ClutterGstPlayerIfacePrivate *priv;
 
   /*< public >*/
-  GstElement * (* get_pipeline)   (ClutterGstPlayer *player);
-
-  gchar * (* get_user_agent) (ClutterGstPlayer *player);
-  void    (* set_user_agent) (ClutterGstPlayer *player,
-                              const gchar      *user_agent);
-
-  ClutterGstSeekFlags (* get_seek_flags) (ClutterGstPlayer *player);
-  void                (* set_seek_flags) (ClutterGstPlayer    *player,
-                                          ClutterGstSeekFlags  flags);
-
-  ClutterGstBufferingMode (* get_buffering_mode) (ClutterGstPlayer *player);
-  void                    (* set_buffering_mode) (ClutterGstPlayer        *player,
-                                                  ClutterGstBufferingMode  mode);
-
-  GList * (* get_audio_streams) (ClutterGstPlayer *player);
-  gint    (* get_audio_stream)  (ClutterGstPlayer *player);
-  void    (* set_audio_stream)  (ClutterGstPlayer *player,
-                                 gint              index_);
-
-  GList * (* get_subtitle_tracks) (ClutterGstPlayer *player);
-  gint    (* get_subtitle_track)  (ClutterGstPlayer *player);
-  void    (* set_subtitle_track)  (ClutterGstPlayer *player,
-                                   gint              index_);
-
-  gboolean (*get_idle) (ClutterGstPlayer *player);
-
-  gboolean (*get_in_seek) (ClutterGstPlayer *player);
-
-  gint   (* get_buffer_size) (ClutterGstPlayer *player);
-  void   (* set_buffer_size) (ClutterGstPlayer *player,
-                              gint              size);
-
-  gint64 (* get_buffer_duration) (ClutterGstPlayer *player);
-  void   (* set_buffer_duration) (ClutterGstPlayer *player,
-                                  gint64            duration);
-
-  gboolean (* is_live_media) (ClutterGstPlayer *player);
-
-  void (* _iface_reserved21) (void);
-  void (* _iface_reserved22) (void);
-  void (* _iface_reserved23) (void);
-  void (* _iface_reserved24) (void);
-  void (* _iface_reserved25) (void);
-  void (* _iface_reserved26) (void);
-  void (* _iface_reserved27) (void);
-  void (* _iface_reserved28) (void);
-  void (* _iface_reserved29) (void);
-  void (* _iface_reserved30) (void);
-  void (* _iface_reserved31) (void);
-  void (* _iface_reserved32) (void);
-  void (* _iface_reserved33) (void);
-  void (* _iface_reserved34) (void);
-  void (* _iface_reserved35) (void);
+  ClutterGstFrame * (* get_frame)        (ClutterGstPlayer *self);
+  GstElement *      (* get_pipeline)     (ClutterGstPlayer *self);
+
+  gboolean          (* get_idle)         (ClutterGstPlayer *self);
+
+  gdouble           (* get_audio_volume) (ClutterGstPlayer *self);
+  void              (* set_audio_volume) (ClutterGstPlayer *self,
+                                          gdouble           volume);
+
+  gboolean          (* get_playing)      (ClutterGstPlayer *self);
+  void              (* set_playing)      (ClutterGstPlayer *self,
+                                          gboolean          playing);
+
+  void (* _iface_reserved7)  (void);
+  void (* _iface_reserved8)  (void);
+  void (* _iface_reserved9)  (void);
+  void (* _iface_reserved10) (void);
+  void (* _iface_reserved11) (void);
+  void (* _iface_reserved12) (void);
 
   /* signals */
-  void (* download_buffering)  (ClutterGstPlayer *player,
-                                gdouble           start,
-                                gdouble           stop);
-  void (* eos)                 (ClutterGstPlayer *player);
-  void (* error)               (ClutterGstPlayer *player,
-                                const GError *error);
-
-  void (* _clutter_reserved4)  (void);
-  void (* _clutter_reserved5)  (void);
+  void (* new_frame)           (ClutterGstPlayer *self, ClutterGstFrame *frame);
+  void (* ready)               (ClutterGstPlayer *self);
+  void (* eos)                 (ClutterGstPlayer *self);
+  void (* error)               (ClutterGstPlayer *self,
+                                const GError     *error);
+  void (* size_change)         (ClutterGstPlayer *self,
+                                gint              width,
+                                gint              height);
+
   void (* _clutter_reserved6)  (void);
   void (* _clutter_reserved7)  (void);
   void (* _clutter_reserved8)  (void);
   void (* _clutter_reserved9)  (void);
   void (* _clutter_reserved10) (void);
+  void (* _clutter_reserved11) (void);
+  void (* _clutter_reserved12) (void);
 };
 
 GType clutter_gst_player_get_type (void) G_GNUC_CONST;
 
-void                      clutter_gst_player_class_init          (GObjectClass *object_class);
-
-gboolean                  clutter_gst_player_init                (ClutterGstPlayer        *player);
-void                      clutter_gst_player_deinit              (ClutterGstPlayer        *player);
-
-GstElement *              clutter_gst_player_get_pipeline        (ClutterGstPlayer        *player);
-
-void                      clutter_gst_player_set_uri             (ClutterGstPlayer        *player,
-                                                                  const gchar             *uri);
-gchar *                   clutter_gst_player_get_uri             (ClutterGstPlayer        *player);
-void                      clutter_gst_player_set_filename        (ClutterGstPlayer        *player,
-                                                                  const gchar             *filename);
-
-void                      clutter_gst_player_set_playing         (ClutterGstPlayer        *player,
-                                                                  gboolean                 playing);
-gboolean                  clutter_gst_player_is_playing          (ClutterGstPlayer        *player);
-
-
-gchar *                   clutter_gst_player_get_user_agent      (ClutterGstPlayer        *player);
-void                      clutter_gst_player_set_user_agent      (ClutterGstPlayer        *player,
-                                                                  const gchar             *user_agent);
-
-ClutterGstSeekFlags       clutter_gst_player_get_seek_flags      (ClutterGstPlayer        *player);
-void                      clutter_gst_player_set_seek_flags      (ClutterGstPlayer        *player,
-                                                                  ClutterGstSeekFlags      flags);
-
-ClutterGstBufferingMode   clutter_gst_player_get_buffering_mode  (ClutterGstPlayer        *player);
-void                      clutter_gst_player_set_buffering_mode  (ClutterGstPlayer        *player,
-                                                                  ClutterGstBufferingMode  mode);
-gdouble                   clutter_gst_player_get_buffer_fill     (ClutterGstPlayer        *player);
-gint                      clutter_gst_player_get_buffer_size     (ClutterGstPlayer        *player);
-void                      clutter_gst_player_set_buffer_size     (ClutterGstPlayer        *player,
-                                                                  gint                     size);
-gint64                    clutter_gst_player_get_buffer_duration (ClutterGstPlayer        *player);
-void                      clutter_gst_player_set_buffer_duration (ClutterGstPlayer        *player,
-                                                                  gint64                   duration);
-
-void                      clutter_gst_player_set_audio_volume    (ClutterGstPlayer        *player,
-                                                                  gdouble                  volume);
-gdouble                   clutter_gst_player_get_audio_volume    (ClutterGstPlayer        *player);
-GList *                   clutter_gst_player_get_audio_streams   (ClutterGstPlayer        *player);
-gint                      clutter_gst_player_get_audio_stream    (ClutterGstPlayer        *player);
-void                      clutter_gst_player_set_audio_stream    (ClutterGstPlayer        *player,
-                                                                  gint                     index_);
-
-void                      clutter_gst_player_set_subtitle_uri    (ClutterGstPlayer        *player,
-                                                                  const gchar             *uri);
-gchar *                   clutter_gst_player_get_subtitle_uri    (ClutterGstPlayer        *player);
-void                      clutter_gst_player_set_subtitle_font_name
-                                                                 (ClutterGstPlayer        *player,
-                                                                  const char              *font_name);
-gchar *                   clutter_gst_player_get_subtitle_font_name
-                                                                 (ClutterGstPlayer        *player);
-GList *                   clutter_gst_player_get_subtitle_tracks (ClutterGstPlayer       *player);
-gint                      clutter_gst_player_get_subtitle_track  (ClutterGstPlayer       *player);
-void                      clutter_gst_player_set_subtitle_track  (ClutterGstPlayer       *player,
-                                                                  gint                    index_);
-
-gboolean                  clutter_gst_player_get_idle            (ClutterGstPlayer        *player);
-
-gboolean                  clutter_gst_player_get_can_seek        (ClutterGstPlayer        *player);
-gboolean                  clutter_gst_player_get_in_seek         (ClutterGstPlayer        *player);
-
-void                      clutter_gst_player_set_progress        (ClutterGstPlayer        *player,
-                                                                  gdouble                  progress);
-gdouble                   clutter_gst_player_get_progress        (ClutterGstPlayer        *player);
-gdouble                   clutter_gst_player_get_duration        (ClutterGstPlayer        *player);
-
-gboolean                  clutter_gst_player_is_live_media       (ClutterGstPlayer        *player);
+ClutterGstFrame *         clutter_gst_player_get_frame        (ClutterGstPlayer        *self);
+
+GstElement *              clutter_gst_player_get_pipeline     (ClutterGstPlayer        *self);
+
+gboolean                  clutter_gst_player_get_idle         (ClutterGstPlayer        *self);
+
+gboolean                  clutter_gst_player_get_playing      (ClutterGstPlayer        *self);
+void                      clutter_gst_player_set_playing      (ClutterGstPlayer        *self,
+                                                               gboolean                 playing);
+
+gdouble                   clutter_gst_player_get_audio_volume (ClutterGstPlayer        *self);
+void                      clutter_gst_player_set_audio_volume (ClutterGstPlayer        *self,
+                                                               gdouble                  volume);
 
 G_END_DECLS
 
diff --git a/clutter-gst/clutter-gst-private.h b/clutter-gst/clutter-gst-private.h
index a7e08e7..18b3c66 100644
--- a/clutter-gst/clutter-gst-private.h
+++ b/clutter-gst/clutter-gst-private.h
@@ -27,6 +27,7 @@
 #define __CLUTTER_GST_PRIVATE_H__
 
 #include <glib.h>
+#include "clutter-gst.h"
 
 G_BEGIN_DECLS
 
@@ -47,6 +48,12 @@ G_BEGIN_DECLS
 gboolean
 _internal_plugin_init (GstPlugin *plugin);
 
+ClutterGstFrame *clutter_gst_frame_new (CoglPipeline *pipeline);
+
+void clutter_gst_util_update_frame (ClutterGstPlayer *player,
+                                    ClutterGstFrame **frame,
+                                    CoglPipeline     *pipeline);
+
 G_END_DECLS
 
 #endif /* __CLUTTER_GST_PRIVATE_H__ */
diff --git a/clutter-gst/clutter-gst-types.c b/clutter-gst/clutter-gst-types.c
new file mode 100644
index 0000000..d4f632d
--- /dev/null
+++ b/clutter-gst/clutter-gst-types.c
@@ -0,0 +1,75 @@
+/*
+ * Clutter-GStreamer.
+ *
+ * GStreamer integration library for Clutter.
+ *
+ * clutter-gst-types.c - Some basic types.
+ *
+ * Authored by Lionel Landwerlin <lionel g landwerlin linux intel com>
+ *
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * 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 "clutter-gst-types.h"
+
+ClutterGstFrame *
+clutter_gst_frame_new (CoglPipeline *pipeline)
+{
+  ClutterGstFrame *frame = g_slice_new0 (ClutterGstFrame);
+  CoglTexture *texture;
+
+  frame->pipeline = cogl_object_ref (pipeline);
+  texture = cogl_pipeline_get_layer_texture (pipeline, 0);
+
+  frame->resolution.width = cogl_texture_get_width (texture);
+  frame->resolution.height = cogl_texture_get_width (texture);
+}
+
+static gpointer
+clutter_gst_frame_copy (gpointer data)
+{
+  if (G_LIKELY (data))
+    {
+      ClutterGstFrame *frame = g_slice_dup (ClutterGstFrame, data);
+
+      if (frame->pipeline != COGL_INVALID_HANDLE)
+        frame->pipeline = cogl_handle_ref (frame->pipeline);
+
+      return frame;
+    }
+
+  return NULL;
+}
+
+static void
+clutter_gst_frame_free (gpointer data)
+{
+  if (G_LIKELY (data))
+    {
+      ClutterGstFrame *frame = (ClutterGstFrame *) data;
+
+      if (frame->pipeline != COGL_INVALID_HANDLE)
+        cogl_handle_unref (frame->pipeline);
+      g_slice_free (ClutterGstFrame, frame);
+    }
+}
+
+G_DEFINE_BOXED_TYPE (ClutterGstFrame,
+                     clutter_gst_frame,
+                     clutter_gst_frame_copy,
+                     clutter_gst_frame_free);
diff --git a/clutter-gst/clutter-gst-types.h b/clutter-gst/clutter-gst-types.h
index 60b8d95..ffff545 100644
--- a/clutter-gst/clutter-gst-types.h
+++ b/clutter-gst/clutter-gst-types.h
@@ -29,9 +29,14 @@
 #error "Only <clutter-gst/clutter-gst.h> can be included directly."
 #endif
 
+#include <cogl/cogl.h>
+
 #ifndef __CLUTTER_GST_TYPES_H__
 #define __CLUTTER_GST_TYPES_H__
 
+#define CLUTTER_GST_TYPE_FRAME            (clutter_gst_frame_get_type ())
+
+typedef struct _ClutterGstFrame           ClutterGstFrame;
 typedef struct _ClutterGstVideoResolution ClutterGstVideoResolution;
 
 /**
@@ -77,4 +82,20 @@ struct _ClutterGstVideoResolution
   gint height;
 };
 
+/**
+ * ClutterGstFrame:
+ * @resolution: a #ClutterGstVideoResolution
+ * @frame: a #CoglHandle to the pipeline to paint a frame
+ *
+ * Represents a frame outputted by the #ClutterGstVideoSink.
+ */
+struct _ClutterGstFrame
+{
+  ClutterGstVideoResolution  resolution;
+  CoglPipeline              *pipeline;
+};
+
+
+GType clutter_gst_frame_get_type (void) G_GNUC_CONST;
+
 #endif /* __CLUTTER_GST_TYPES_H__ */
diff --git a/clutter-gst/clutter-gst-util.c b/clutter-gst/clutter-gst-util.c
index d5b5cb6..9d6f80a 100644
--- a/clutter-gst/clutter-gst-util.c
+++ b/clutter-gst/clutter-gst-util.c
@@ -148,7 +148,7 @@ clutter_gst_init (int    *argc,
                              GST_VERSION_MINOR,
                              "cluttersink",
                              "Element to render to ClutterGst actors",
-                             _internal_plugin_init,
+                             /* _internal_plugin_init */NULL,
                              VERSION,
                              "LGPL", /* license */
                              "clutter-gst", PACKAGE,
@@ -228,7 +228,7 @@ clutter_gst_init_with_args (int            *argc,
                              GST_VERSION_MINOR,
                              "cluttersink",
                              "Element to render to ClutterGst actors",
-                             _internal_plugin_init,
+                             /* _internal_plugin_init */NULL,
                              VERSION,
                              "LGPL", /* license */
                              "clutter-gst", PACKAGE,
@@ -239,3 +239,28 @@ clutter_gst_init_with_args (int            *argc,
 
   return CLUTTER_INIT_SUCCESS;
 }
+
+void
+clutter_gst_util_update_frame (ClutterGstPlayer *player,
+                               ClutterGstFrame **frame,
+                               CoglPipeline     *pipeline)
+{
+  ClutterGstFrame *old_frame = *frame;
+  ClutterGstFrame *new_frame = clutter_gst_frame_new (pipeline);
+
+  *frame = new_frame;
+
+  if (old_frame == NULL ||
+      new_frame->resolution.width != old_frame->resolution.width ||
+      new_frame->resolution.height != old_frame->resolution.height)
+    {
+      g_signal_emit_by_name (player, "size-change",
+                             new_frame->resolution.width,
+                             new_frame->resolution.height);
+    }
+
+  if (old_frame)
+    g_boxed_free (CLUTTER_GST_TYPE_FRAME, old_frame);
+
+  g_signal_emit_by_name (player, "new-frame", new_frame);
+}
diff --git a/clutter-gst/clutter-gst-video-sink.c b/clutter-gst/clutter-gst-video-sink.c
index 742b3a7..2104f70 100644
--- a/clutter-gst/clutter-gst-video-sink.c
+++ b/clutter-gst/clutter-gst-video-sink.c
@@ -131,10 +131,17 @@ GST_DEBUG_CATEGORY_STATIC (clutter_gst_video_sink_debug);
 enum
 {
   PROP_0,
-  PROP_ACTOR,
+  PROP_COGL_PIPELINE,
   PROP_UPDATE_PRIORITY
 };
 
+enum
+{
+  SEND_EVENT,
+
+  LAST_SIGNAL
+};
+
 typedef enum
 {
   CLUTTER_GST_NOFORMAT,
@@ -194,8 +201,10 @@ typedef struct _ClutterGstRenderer
 
 struct _ClutterGstVideoSinkPrivate
 {
-  ClutterActor *actor;
+  ClutterStage *default_stage;
+
   CoglMaterial *material_template;
+  CoglMaterial *cogl_pipeline;
 
   GstFlowReturn flow_ret;
 
@@ -227,8 +236,7 @@ G_DEFINE_TYPE_WITH_CODE (ClutterGstVideoSink, clutter_gst_video_sink,
     GST_TYPE_BASE_SINK, G_IMPLEMENT_INTERFACE (GST_TYPE_NAVIGATION,
         clutter_gst_navigation_interface_init));
 
-static void clutter_gst_video_sink_set_actor (ClutterGstVideoSink * sink,
-    ClutterActor * actor);
+static guint sink_signals[LAST_SIGNAL] = { 0, };
 
 /*
  * ClutterGstSource implementation
@@ -297,18 +305,19 @@ ensure_texture_pixel_aspect_ratio (ClutterGstVideoSink * sink)
   GParamSpec *pspec;
   GValue par = { 0, };
 
-  if (priv->actor == NULL)
-    return;
+  /* if (priv->actor == NULL) */
+  /*   return; */
 
-  pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (priv->actor),
-      "pixel-aspect-ratio");
-  if (pspec) {
+  /* pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (priv->actor), */
+  /*     "pixel-aspect-ratio"); */
+  /* if (pspec) { */
     g_value_init (&par, GST_TYPE_FRACTION);
     gst_value_set_fraction (&par, priv->info.par_n, priv->info.par_d);
-    g_object_set_property (G_OBJECT (priv->actor),
-        "pixel-aspect-ratio", &par);
+    /* TODO: propagate the value through property/signal */
+    /* g_object_set_property (G_OBJECT (priv->actor), */
+    /*     "pixel-aspect-ratio", &par); */
     g_value_unset (&par);
-  }
+  /* } */
 }
 
 static gboolean
@@ -417,47 +426,47 @@ no_suitable_renderer:
   }
 }
 
-static gboolean
-on_stage_destroyed (ClutterStage * stage,
-    ClutterEvent * event, gpointer user_data)
-{
-  ClutterGstSource *gst_source = user_data;
-  ClutterGstVideoSinkPrivate *priv = gst_source->sink->priv;
+/* static gboolean */
+/* on_stage_destroyed (ClutterStage * stage, */
+/*     ClutterEvent * event, gpointer user_data) */
+/* { */
+/*   ClutterGstSource *gst_source = user_data; */
+/*   ClutterGstVideoSinkPrivate *priv = gst_source->sink->priv; */
 
-  g_mutex_lock (&gst_source->buffer_lock);
+/*   g_mutex_lock (&gst_source->buffer_lock); */
 
-  clutter_actor_hide (CLUTTER_ACTOR (stage));
-  clutter_actor_remove_child (CLUTTER_ACTOR (stage), priv->actor);
+/*   clutter_actor_hide (CLUTTER_ACTOR (stage)); */
+/*   clutter_actor_remove_child (CLUTTER_ACTOR (stage), priv->actor); */
 
-  if (gst_source->buffer)
-    gst_buffer_unref (gst_source->buffer);
+/*   if (gst_source->buffer) */
+/*     gst_buffer_unref (gst_source->buffer); */
 
-  gst_source->stage_lost = TRUE;
-  gst_source->buffer = NULL;
-  priv->actor = NULL;
+/*   gst_source->stage_lost = TRUE; */
+/*   gst_source->buffer = NULL; */
+/*   priv->actor = NULL; */
 
-  g_mutex_unlock (&gst_source->buffer_lock);
+/*   g_mutex_unlock (&gst_source->buffer_lock); */
 
-  return TRUE;
-}
+/*   return TRUE; */
+/* } */
 
-static void
-on_stage_allocation_changed (ClutterStage * stage,
-    ClutterActorBox * box, ClutterAllocationFlags flags, gpointer user_data)
-{
-  ClutterGstSource *gst_source = user_data;
-  ClutterGstVideoSinkPrivate *priv = gst_source->sink->priv;
-  gint width, height;
+/* static void */
+/* on_stage_allocation_changed (ClutterStage * stage, */
+/*     ClutterActorBox * box, ClutterAllocationFlags flags, gpointer user_data) */
+/* { */
+/*   ClutterGstSource *gst_source = user_data; */
+/*   ClutterGstVideoSinkPrivate *priv = gst_source->sink->priv; */
+/*   gint width, height; */
 
-  if (gst_source->stage_lost)
-    return;
+/*   if (gst_source->stage_lost) */
+/*     return; */
 
-  width = (gint) (box->x2 - box->x1);
-  height = (gint) (box->y2 - box->y1);
+/*   width = (gint) (box->x2 - box->x1); */
+/*   height = (gint) (box->y2 - box->y1); */
 
-  GST_DEBUG ("Size changed to %i/%i", width, height);
-  clutter_actor_set_size (priv->actor, width, height);
-}
+/*   GST_DEBUG ("Size changed to %i/%i", width, height); */
+/*   clutter_actor_set_size (priv->actor, width, height); */
+/* } */
 
 static gboolean
 clutter_gst_source_dispatch (GSource * source,
@@ -486,35 +495,35 @@ clutter_gst_source_dispatch (GSource * source,
       goto negotiation_fail;
     gst_source->has_new_caps = FALSE;
 
-    if (!priv->actor) {
-      ClutterActor *stage;
-      ClutterActor *actor;
+    /* if (!priv->actor) { */
+      /* ClutterActor *stage; */
+      /* ClutterActor *actor; */
 
-      GST_DEBUG_OBJECT (gst_source->sink,
-          "No existing texture, creating stage and actor");
-      stage = clutter_stage_new ();
-      actor = g_object_new (CLUTTER_GST_TYPE_ACTOR, NULL);
+      /* GST_DEBUG_OBJECT (gst_source->sink, */
+      /*     "No existing texture, creating stage and actor"); */
+      /* stage = clutter_stage_new (); */
+      /* actor = g_object_new (CLUTTER_GST_TYPE_ACTOR, NULL); */
 
-      clutter_gst_video_sink_set_actor (gst_source->sink, actor);
-      clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE);
-      clutter_actor_add_child (stage, actor);
-      clutter_stage_set_no_clear_hint (CLUTTER_STAGE (stage), TRUE);
+      /* clutter_gst_video_sink_set_actor (gst_source->sink, actor); */
+      /* clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE); */
+      /* clutter_actor_add_child (stage, actor); */
+      /* clutter_stage_set_no_clear_hint (CLUTTER_STAGE (stage), TRUE); */
 
-      g_signal_connect (stage, "delete-event",
-          G_CALLBACK (on_stage_destroyed), gst_source);
-      g_signal_connect (stage, "allocation-changed",
-          G_CALLBACK (on_stage_allocation_changed), gst_source);
+      /* g_signal_connect (stage, "delete-event", */
+      /*     G_CALLBACK (on_stage_destroyed), gst_source); */
+      /* g_signal_connect (stage, "allocation-changed", */
+      /*     G_CALLBACK (on_stage_allocation_changed), gst_source); */
 
       /* FIXME : We already call this above ? */
       if (!clutter_gst_parse_caps (caps, gst_source->sink, TRUE))
         goto negotiation_fail;
-      clutter_actor_set_size (stage, priv->info.width, priv->info.height);
-      clutter_actor_show (stage);
-    } else {
+      /* clutter_actor_set_size (stage, priv->info.width, priv->info.height); */
+      /* clutter_actor_show (stage); */
+    /* } else { */
       /* FIXME : We already call this above ? */
-      if (!clutter_gst_parse_caps (caps, gst_source->sink, TRUE))
-        goto negotiation_fail;
-    }
+    /*   if (!clutter_gst_parse_caps (caps, gst_source->sink, TRUE)) */
+    /*     goto negotiation_fail; */
+    /* } */
 
     if (priv->material_template)
       cogl_object_unref (priv->material_template);
@@ -736,8 +745,13 @@ _create_paint_material (ClutterGstVideoSink * sink,
     cogl_handle_unref (tex2);
   }
 
-  clutter_gst_actor_set_cogl_material (CLUTTER_GST_ACTOR (priv->actor), material);
-  cogl_object_unref (material);
+  cogl_handle_unref (priv->cogl_pipeline);
+  priv->cogl_pipeline = material;
+
+  g_object_notify (sink, "cogl-pipeline");
+
+  /* clutter_gst_actor_set_cogl_material (CLUTTER_GST_ACTOR (priv->actor), material); */
+  /* cogl_object_unref (material); */
 }
 
 static void
@@ -1088,78 +1102,78 @@ static ClutterGstRenderer ayuv_glsl_renderer = {
  * HW Surfaces
  */
 
-#ifdef HAVE_HW_DECODER_SUPPORT
-static CoglMaterial *
-clutter_gst_hw_init (ClutterGstVideoSink * sink)
-{
-  ClutterGstVideoSinkPrivate *priv = sink->priv;
-  CoglHandle tex;
-  CoglHandle material;
-
-  /* Default texture is 1x1, let's replace it with one big enough. */
-  tex = cogl_texture_new_with_size (priv->info.width, priv->info.height,
-      CLUTTER_GST_TEXTURE_FLAGS, COGL_PIXEL_FORMAT_BGRA_8888);
-
-  material = cogl_material_new ();
-  cogl_material_set_layer (material, 0, tex);
-  clutter_gst_actor_set_cogl_material (CLUTTER_GST_ACTOR (priv->actor), material);
-
-  cogl_object_unref (tex);
-
-  return material;
-}
-
-static void
-clutter_gst_hw_deinit (ClutterGstVideoSink * sink)
-{
-  ClutterGstVideoSinkPrivate *priv = sink->priv;
-
-  if (priv->converter != NULL)
-    g_object_unref (priv->converter);
-  priv->converter = NULL;
-}
-
-static void
-clutter_gst_hw_upload (ClutterGstVideoSink * sink, GstBuffer * buffer)
-{
-  ClutterGstVideoSinkPrivate *priv = sink->priv;
-  GstSurfaceMeta *surface = gst_buffer_get_surface_meta (buffer);
-
-  g_return_if_fail (surface != NULL);
-
-  if (G_UNLIKELY (priv->converter == NULL)) {
-    CoglHandle tex;
-    unsigned int gl_texture;
-    unsigned int gl_target;
-    GValue value = { 0 };
-
-    tex = clutter_gst_actor_get_cogl_texture (CLUTTER_GST_ACTOR (priv->actor));
-    cogl_texture_get_gl_texture (tex, &gl_texture, &gl_target);
-
-    g_value_init (&value, G_TYPE_UINT);
-    g_value_set_uint (&value, gl_texture);
-
-    priv->converter =
-        gst_surface_meta_create_converter (surface, "opengl", &value);
-    g_return_if_fail (priv->converter);
-  }
-
-  gst_surface_converter_upload (priv->converter, buffer);
-
-  /* The actor is dirty, schedule a redraw */
-  clutter_actor_queue_redraw (priv->actor);
-}
-
-static ClutterGstRenderer hw_renderer = {
-  "HW surface",
-  CLUTTER_GST_SURFACE,
-  0,
-  GST_STATIC_CAPS ("x-video/surface, opengl=true"),
-  clutter_gst_hw_init,
-  clutter_gst_hw_deinit,
-  clutter_gst_hw_upload,
-};
-#endif
+/* #ifdef HAVE_HW_DECODER_SUPPORT */
+/* static CoglMaterial * */
+/* clutter_gst_hw_init (ClutterGstVideoSink * sink) */
+/* { */
+/*   ClutterGstVideoSinkPrivate *priv = sink->priv; */
+/*   CoglHandle tex; */
+/*   CoglHandle material; */
+
+/*   /\* Default texture is 1x1, let's replace it with one big enough. *\/ */
+/*   tex = cogl_texture_new_with_size (priv->info.width, priv->info.height, */
+/*       CLUTTER_GST_TEXTURE_FLAGS, COGL_PIXEL_FORMAT_BGRA_8888); */
+
+/*   material = cogl_material_new (); */
+/*   cogl_material_set_layer (material, 0, tex); */
+/*   clutter_gst_actor_set_cogl_material (CLUTTER_GST_ACTOR (priv->actor), material); */
+
+/*   cogl_object_unref (tex); */
+
+/*   return material; */
+/* } */
+
+/* static void */
+/* clutter_gst_hw_deinit (ClutterGstVideoSink * sink) */
+/* { */
+/*   ClutterGstVideoSinkPrivate *priv = sink->priv; */
+
+/*   if (priv->converter != NULL) */
+/*     g_object_unref (priv->converter); */
+/*   priv->converter = NULL; */
+/* } */
+
+/* static void */
+/* clutter_gst_hw_upload (ClutterGstVideoSink * sink, GstBuffer * buffer) */
+/* { */
+/*   ClutterGstVideoSinkPrivate *priv = sink->priv; */
+/*   GstSurfaceMeta *surface = gst_buffer_get_surface_meta (buffer); */
+
+/*   g_return_if_fail (surface != NULL); */
+
+/*   if (G_UNLIKELY (priv->converter == NULL)) { */
+/*     CoglHandle tex; */
+/*     unsigned int gl_texture; */
+/*     unsigned int gl_target; */
+/*     GValue value = { 0 }; */
+
+/*     tex = clutter_gst_actor_get_cogl_texture (CLUTTER_GST_ACTOR (priv->actor)); */
+/*     cogl_texture_get_gl_texture (tex, &gl_texture, &gl_target); */
+
+/*     g_value_init (&value, G_TYPE_UINT); */
+/*     g_value_set_uint (&value, gl_texture); */
+
+/*     priv->converter = */
+/*         gst_surface_meta_create_converter (surface, "opengl", &value); */
+/*     g_return_if_fail (priv->converter); */
+/*   } */
+
+/*   gst_surface_converter_upload (priv->converter, buffer); */
+
+/*   /\* The actor is dirty, schedule a redraw *\/ */
+/*   clutter_actor_queue_redraw (priv->actor); */
+/* } */
+
+/* static ClutterGstRenderer hw_renderer = { */
+/*   "HW surface", */
+/*   CLUTTER_GST_SURFACE, */
+/*   0, */
+/*   GST_STATIC_CAPS ("x-video/surface, opengl=true"), */
+/*   clutter_gst_hw_init, */
+/*   clutter_gst_hw_deinit, */
+/*   clutter_gst_hw_upload, */
+/* }; */
+/* #endif */
 
 static GSList *
 clutter_gst_build_renderers_list (void)
@@ -1295,9 +1309,20 @@ navigation_event (ClutterActor * actor,
 }
 
 static void
+_default_stage_changed (ClutterStageManager *manager,
+                        GParamSpec *param,
+                        ClutterGstVideoSink *self)
+{
+  ClutterGstVideoSinkPrivate *priv = self->priv;
+
+  priv->default_stage = clutter_stage_manager_get_default_stage (manager);
+}
+
+static void
 clutter_gst_video_sink_init (ClutterGstVideoSink * sink)
 {
   ClutterGstVideoSinkPrivate *priv;
+  ClutterStageManager *manager;
 
   sink->priv = priv =
       G_TYPE_INSTANCE_GET_PRIVATE (sink, CLUTTER_GST_TYPE_VIDEO_SINK,
@@ -1312,6 +1337,11 @@ clutter_gst_video_sink_init (ClutterGstVideoSink * sink)
 
   priv->signal_handler_ids = g_array_new (FALSE, TRUE, sizeof (gulong));
   priv->priority = CLUTTER_GST_DEFAULT_PRIORITY;
+
+  manager = clutter_stage_manager_get_default ();
+  priv->default_stage = clutter_stage_manager_get_default_stage (manager);
+  g_signal_connect (manager, "notify::default-stage",
+                    G_CALLBACK (_default_stage_changed), sink);
 }
 
 static GstFlowReturn
@@ -1390,7 +1420,6 @@ clutter_gst_video_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
   return TRUE;
 }
 
-
 static void
 clutter_gst_video_sink_dispose (GObject * object)
 {
@@ -1405,8 +1434,9 @@ clutter_gst_video_sink_dispose (GObject * object)
     priv->renderer = NULL;
   }
 
-  if (priv->actor)
-    clutter_gst_video_sink_set_actor (self, NULL);
+  g_object_notify (self, "cogl-pipeline");
+  /* if (priv->actor) */
+  /*   clutter_gst_video_sink_set_actor (self, NULL); */
 
   if (priv->caps) {
     gst_caps_unref (priv->caps);
@@ -1433,52 +1463,12 @@ clutter_gst_video_sink_finalize (GObject * object)
 }
 
 static void
-clutter_gst_video_sink_set_actor (ClutterGstVideoSink * sink,
-    ClutterActor * actor)
-{
-  const char const *events[] = {
-    "key-press-event",
-    "key-release-event",
-    "button-press-event",
-    "button-release-event",
-    "motion-event"
-  };
-  ClutterGstVideoSinkPrivate *priv = sink->priv;
-  guint i;
-
-  if (priv->actor) {
-    for (i = 0; i < priv->signal_handler_ids->len; i++) {
-      gulong id = g_array_index (priv->signal_handler_ids, gulong, i);
-      g_signal_handler_disconnect (priv->actor, id);
-    }
-    g_array_set_size (priv->signal_handler_ids, 0);
-  }
-
-  priv->actor = actor;
-  if (priv->actor == NULL)
-    return;
-
-  clutter_actor_set_reactive (priv->actor, TRUE);
-  g_object_add_weak_pointer (G_OBJECT (priv->actor), (gpointer *) &(priv->actor));
-
-  for (i = 0; i < G_N_ELEMENTS (events); i++) {
-    gulong id;
-    id = g_signal_connect (priv->actor, events[i],
-        G_CALLBACK (navigation_event), sink);
-    g_array_append_val (priv->signal_handler_ids, id);
-  }
-}
-
-static void
 clutter_gst_video_sink_set_property (GObject * object,
     guint prop_id, const GValue * value, GParamSpec * pspec)
 {
   ClutterGstVideoSink *sink = CLUTTER_GST_VIDEO_SINK (object);
 
   switch (prop_id) {
-    case PROP_ACTOR:
-      clutter_gst_video_sink_set_actor (sink, g_value_get_object (value));
-      break;
     case PROP_UPDATE_PRIORITY:
       clutter_gst_video_sink_set_priority (sink, g_value_get_int (value));
       break;
@@ -1496,8 +1486,8 @@ clutter_gst_video_sink_get_property (GObject * object,
   ClutterGstVideoSinkPrivate *priv = sink->priv;
 
   switch (prop_id) {
-    case PROP_ACTOR:
-      g_value_set_object (value, priv->actor);
+    case PROP_COGL_PIPELINE:
+      g_value_set_object (value, priv->cogl_pipeline);
       break;
     case PROP_UPDATE_PRIORITY:
       g_value_set_int (value, priv->priority);
@@ -1542,6 +1532,22 @@ clutter_gst_video_sink_stop (GstBaseSink * base_sink)
   return TRUE;
 }
 
+static gboolean
+_clutter_gst_point_handled_accumulator (GSignalInvocationHint *ihint,
+                                        GValue                *return_accu,
+                                        const GValue          *handler_return,
+                                        gpointer               dummy)
+{
+  gboolean continue_emission;
+  gpointer translated_point;
+
+  translated_point = g_value_get_boxed (handler_return);
+  g_value_set_boxed (return_accu, translated_point);
+  continue_emission = (translated_point == NULL);
+
+  return continue_emission;
+}
+
 static void
 clutter_gst_video_sink_class_init (ClutterGstVideoSinkClass * klass)
 {
@@ -1579,35 +1585,61 @@ clutter_gst_video_sink_class_init (ClutterGstVideoSinkClass * klass)
   gstbase_sink_class->get_caps = clutter_gst_video_sink_get_caps;
 
   /**
-   * ClutterGstVideoSink:actor:
-   *
-   * This is the actor the video is decoded into. It can be any
-   * #ClutterGstActor, however Cluter-Gst has a handy subclass,
-   * #ClutterGstVideoActor, that implements the #ClutterGstPlayer
-   * interface.
-   */
-  pspec = g_param_spec_object ("actor",
-      "Actor",
-      "ClutterGstActor the video will be decoded into",
-      CLUTTER_GST_TYPE_ACTOR,
-      CLUTTER_GST_PARAM_READWRITE);
-  g_object_class_install_property (gobject_class, PROP_ACTOR, pspec);
-
-  /**
    * ClutterGstVideoSink:update-priority:
    *
    * Clutter-Gst installs a #GSource to signal that a new frame is ready to
    * the Clutter thread. This property allows to tweak the priority of the
    * source (Lower value is higher priority).
    *
-   * Since 1.0
+   * Since 3.0
    */
   pspec = g_param_spec_int ("update-priority",
-      "Update Priority",
-      "Priority of video updates in the Clutter thread",
-      -G_MAXINT, G_MAXINT,
-      CLUTTER_GST_DEFAULT_PRIORITY, CLUTTER_GST_PARAM_READWRITE);
+                            "Update Priority",
+                            "Priority of video updates in the Clutter thread",
+                            -G_MAXINT, G_MAXINT,
+                            CLUTTER_GST_DEFAULT_PRIORITY,
+                            CLUTTER_GST_PARAM_READWRITE);
   g_object_class_install_property (gobject_class, PROP_UPDATE_PRIORITY, pspec);
+
+  /**
+   * ClutterGstVideoSink:cogl-pipeline:
+   *
+   * Cogl pipeline to be used to paint a video frame
+   *
+   * Since 3.0
+   */
+  pspec = g_param_spec_boxed ("frame",
+                              "Update Priority",
+                              "Priority of video updates in the Clutter thread",
+                              COGL_TYPE_HANDLE,
+                              CLUTTER_GST_PARAM_READABLE);
+  g_object_class_install_property (gobject_class, PROP_COGL_PIPELINE, pspec);
+
+  /**
+   * ClutterGstVideoSink::send-event:
+   * @sink: the #ClutterGstVideoSink that emitted the signal
+   * @point: the position of the event
+   *
+   * The #ClutterGstVideoSink::send-event signal is emitted each time
+   * there is a need to get the coordinates of an event onto the
+   * screen.
+   *
+   * Return value: a #ClutterPoint if the position of the point in the
+   * stream can be translated into the window's coordinates, NULL
+   * otherwise.
+   *
+   * Since: 3.0
+   */
+  sink_signals[SEND_EVENT] =
+    g_signal_new ("send-event",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE,
+                  0,
+                  _clutter_gst_point_handled_accumulator,
+                  NULL,
+                  NULL,
+                  CLUTTER_TYPE_POINT, 1,
+                  CLUTTER_TYPE_POINT);
 }
 
 static void
@@ -1625,20 +1657,23 @@ clutter_gst_navigation_send_event (GstNavigation * navigation,
    * if the structure contains pointer coordinates */
   if (gst_structure_get_double (structure, "pointer_x", &x) &&
       gst_structure_get_double (structure, "pointer_y", &y)) {
-    if (clutter_actor_transform_stage_point (CLUTTER_ACTOR (priv->actor), x,
-            y, &x_out, &y_out) == FALSE) {
-      g_warning ("Failed to convert non-scaled coordinates for video-sink");
-      return;
-    }
 
-    x = x_out * priv->info.width /
-        clutter_actor_get_width (CLUTTER_ACTOR (priv->actor));
-    y = y_out * priv->info.height /
-        clutter_actor_get_height (CLUTTER_ACTOR (priv->actor));
+    /* TODO: emit signal to get transformed point */
+
+    /* if (clutter_actor_transform_stage_point (CLUTTER_ACTOR (priv->actor), x, */
+    /*         y, &x_out, &y_out) == FALSE) { */
+    /*   g_warning ("Failed to convert non-scaled coordinates for video-sink"); */
+    /*   return; */
+    /* } */
 
-    gst_structure_set (structure,
-        "pointer_x", G_TYPE_DOUBLE, (gdouble) x,
-        "pointer_y", G_TYPE_DOUBLE, (gdouble) y, NULL);
+    /* x = x_out * priv->info.width / */
+    /*     clutter_actor_get_width (CLUTTER_ACTOR (priv->actor)); */
+    /* y = y_out * priv->info.height / */
+    /*     clutter_actor_get_height (CLUTTER_ACTOR (priv->actor)); */
+
+    /* gst_structure_set (structure, */
+    /*     "pointer_x", G_TYPE_DOUBLE, (gdouble) x, */
+    /*     "pointer_y", G_TYPE_DOUBLE, (gdouble) y, NULL); */
   }
 
   event = gst_event_new_navigation (structure);
@@ -1658,16 +1693,37 @@ clutter_gst_navigation_interface_init (GstNavigationInterface * iface)
   iface->send_event = clutter_gst_navigation_send_event;
 }
 
+/**
+ * clutter_gst_video_sink_get_frame:
+ * @self: a #ClutterGstVideoSink
+ *
+ * Retrieves the last frame from @self to present on the screen.
+ *
+ * Return value: (transfer none): A CoglHandle on a CoglPipeline
+ */
+ClutterGstFrame *
+clutter_gst_video_sink_get_frame (ClutterGstVideoSink *self)
+{
+  ClutterGstVideoSinkPrivate *priv;
+
+  g_return_val_if_fail (CLUTTER_GST_IS_VIDEO_SINK (self), COGL_INVALID_HANDLE);
+
+  priv = self->priv;
+
+  return priv->cogl_pipeline;
+}
+
+
 gboolean
 _internal_plugin_init (GstPlugin * plugin)
 {
   gboolean ret = gst_element_register (plugin,
-      "cluttersink",
-      GST_RANK_PRIMARY,
-      CLUTTER_GST_TYPE_VIDEO_SINK);
+                                       "coglsink",
+                                       GST_RANK_PRIMARY,
+                                       CLUTTER_GST_TYPE_VIDEO_SINK);
 
   GST_DEBUG_CATEGORY_INIT (clutter_gst_video_sink_debug,
-      "cluttersink", 0, "clutter video sink");
+                           "coglsink", 0, "cogl video sink");
 
   return ret;
 }
diff --git a/clutter-gst/clutter-gst-video-sink.h b/clutter-gst/clutter-gst-video-sink.h
index 92eb3e4..4726267 100644
--- a/clutter-gst/clutter-gst-video-sink.h
+++ b/clutter-gst/clutter-gst-video-sink.h
@@ -106,6 +106,8 @@ struct _ClutterGstVideoSinkClass
 
 GType       clutter_gst_video_sink_get_type    (void) G_GNUC_CONST;
 
+CoglHandle  clutter_gst_video_sink_get_frame   (ClutterGstVideoSink *self);
+
 G_END_DECLS
 
 #endif /* __CLUTTER_GST_VIDEO_SINK_H__ */
diff --git a/clutter-gst/clutter-gst.h b/clutter-gst/clutter-gst.h
index cb657f9..b3790dd 100644
--- a/clutter-gst/clutter-gst.h
+++ b/clutter-gst/clutter-gst.h
@@ -33,12 +33,11 @@
 #include "clutter-gst-types.h"
 #include "clutter-gst-enum-types.h"
 #include "clutter-gst-actor.h"
-#include "clutter-gst-video-sink.h"
-#include "clutter-gst-video-actor.h"
 #include "clutter-gst-camera-device.h"
-#include "clutter-gst-camera-actor.h"
+#include "clutter-gst-camera.h"
 #include "clutter-gst-util.h"
 #include "clutter-gst-version.h"
 #include "clutter-gst-player.h"
+#include "clutter-gst-playback.h"
 
 #endif /* __CLUTTER_GST_H__ */
diff --git a/configure.ac b/configure.ac
index 690f8b6..cc55ef6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -80,6 +80,7 @@ AC_SUBST([CLUTTER_GST_RELEASE_STATUS], [clutter_gst_release_status])
 # pkg-config requirements
 GLIB_REQ_VERSION=2.18.0
 COGL_REQ_VERSION=1.10.0
+COGL_GST_REQ_VERSION=1.99.0
 CLUTTER_REQ_VERSION=1.6.0
 GSTREAMER_REQ_VERSION=1.0.0
 GST_PLUGINS_BAD_REQ_VERSION=1.0.0
@@ -142,6 +143,7 @@ dnl ========================================================================
 PKG_CHECK_MODULES(CLUTTER_GST,
                   [clutter-1.0 >= $CLUTTER_REQ_VERSION
                    cogl-1.0 >= $COGL_REQ_VERSION
+                   cogl-gst >= $COGL_GST_REQ_VERSION
                    gio-2.0 >= $GLIB_REQ_VERSION])
 
 dnl ========================================================================
diff --git a/examples/camera-player.c b/examples/camera-player.c
index 1b816a7..e02ed5e 100644
--- a/examples/camera-player.c
+++ b/examples/camera-player.c
@@ -33,6 +33,7 @@ typedef struct _CameraApp
 {
   ClutterActor *stage;
   ClutterActor *camera_actor;
+  ClutterGstCamera *camera_player;
   const GPtrArray *camera_devices;
   guint selected_camera_device;
   gboolean decrease_selected;
@@ -57,24 +58,20 @@ update_gamma (CameraApp *app)
 {
   gdouble min, max, cur;
 
-  if (!clutter_gst_camera_actor_supports_gamma_correction (
-          CLUTTER_GST_CAMERA_ACTOR (app->camera_actor)))
+  if (!clutter_gst_camera_supports_gamma_correction (app->camera_player))
     {
       g_print ("Cannot update gamma, not supported\n");
       return;
     }
 
-  if (!clutter_gst_camera_actor_get_gamma_range (
-          CLUTTER_GST_CAMERA_ACTOR (app->camera_actor),
-          &min, &max, NULL))
+  if (!clutter_gst_camera_get_gamma_range (app->camera_player,
+                                           &min, &max, NULL))
     {
       g_print ("Cannot update gamma, unable to get allowed range\n");
       return;
     }
 
-  if (!clutter_gst_camera_actor_get_gamma (
-          CLUTTER_GST_CAMERA_ACTOR (app->camera_actor),
-          &cur))
+  if (!clutter_gst_camera_get_gamma (app->camera_player, &cur))
     {
       g_print ("Cannot update gamma, unable to get current value\n");
       return;
@@ -98,9 +95,7 @@ update_gamma (CameraApp *app)
     }
 
   g_print ("\tnew value: %0.2f\n", cur);
-  clutter_gst_camera_actor_set_gamma (
-      CLUTTER_GST_CAMERA_ACTOR (app->camera_actor),
-      cur);
+  clutter_gst_camera_set_gamma (app->camera_player, cur);
 }
 
 static void
@@ -109,8 +104,7 @@ update_color_balance (CameraApp *app,
 {
   gdouble min, max, cur;
 
-  if (!clutter_gst_camera_actor_supports_color_balance (
-          CLUTTER_GST_CAMERA_ACTOR (app->camera_actor)))
+  if (!clutter_gst_camera_supports_color_balance (app->camera_player))
     {
       g_print ("Cannot update color balance property %s, "
                "not supported\n",
@@ -118,9 +112,8 @@ update_color_balance (CameraApp *app,
       return;
     }
 
-  if (!clutter_gst_camera_actor_get_color_balance_property_range (
-          CLUTTER_GST_CAMERA_ACTOR (app->camera_actor),
-          property, &min, &max, NULL))
+  if (!clutter_gst_camera_get_color_balance_property_range (app->camera_player,
+                                                            property, &min, &max, NULL))
     {
       g_print ("Cannot update color balance property %s, "
                "unable to get allowed range\n",
@@ -128,9 +121,8 @@ update_color_balance (CameraApp *app,
       return;
     }
 
-  if (!clutter_gst_camera_actor_get_color_balance_property (
-          CLUTTER_GST_CAMERA_ACTOR (app->camera_actor),
-          property, &cur))
+  if (!clutter_gst_camera_get_color_balance_property (app->camera_player,
+                                                      property, &cur))
     {
       g_print ("Cannot update color balance property %s, "
                "unable to get current value\n",
@@ -156,9 +148,8 @@ update_color_balance (CameraApp *app,
     }
 
   g_print ("\tnew value: %0.2f\n", cur);
-  clutter_gst_camera_actor_set_color_balance_property (
-      CLUTTER_GST_CAMERA_ACTOR (app->camera_actor),
-      property, cur);
+  clutter_gst_camera_set_color_balance_property (app->camera_player,
+                                                 property, cur);
 }
 
 static gboolean
@@ -214,8 +205,7 @@ input_cb (ClutterStage *stage,
               g_print ("Selecting device %s (node=%s)\n",
                        clutter_gst_camera_device_get_name (device),
                        clutter_gst_camera_device_get_node (device));
-              clutter_gst_camera_actor_set_camera_device (
-                  CLUTTER_GST_CAMERA_ACTOR (app->camera_actor), device);
+              clutter_gst_camera_set_camera_device (app->camera_player, device);
               break;
             }
 
@@ -229,16 +219,13 @@ input_cb (ClutterStage *stage,
               gchar *filename;
               static guint photos_cnt = 0;
 
-              if (clutter_gst_camera_actor_is_recording_video (
-                      CLUTTER_GST_CAMERA_ACTOR (app->camera_actor)))
+              if (clutter_gst_camera_is_recording_video (app->camera_player))
                 {
                   g_print ("Stopping video recording\n");
 
-                  clutter_gst_camera_actor_stop_video_recording (
-                      CLUTTER_GST_CAMERA_ACTOR (app->camera_actor));
+                  clutter_gst_camera_stop_video_recording (app->camera_player);
                 }
-              else if (!clutter_gst_camera_actor_is_ready_for_capture (
-                           CLUTTER_GST_CAMERA_ACTOR (app->camera_actor)))
+              else if (!clutter_gst_camera_is_ready_for_capture (app->camera_player))
                 g_print ("Unable to record video as the camera is not ready for capture\n");
               else
                 {
@@ -246,9 +233,8 @@ input_cb (ClutterStage *stage,
 
                   filename = g_strdup_printf ("camera-video-%d.ogv", photos_cnt++);
 
-                  clutter_gst_camera_actor_start_video_recording (
-                      CLUTTER_GST_CAMERA_ACTOR (app->camera_actor),
-                      filename);
+                  clutter_gst_camera_start_video_recording (app->camera_player,
+                                                            filename);
                   g_free (filename);
                 }
               break;
@@ -259,11 +245,9 @@ input_cb (ClutterStage *stage,
               gchar *filename;
               static guint photos_cnt = 0;
 
-              if (clutter_gst_camera_actor_is_recording_video (
-                      CLUTTER_GST_CAMERA_ACTOR (app->camera_actor)))
+              if (clutter_gst_camera_is_recording_video (app->camera_player))
                 g_print ("Unable to take photo as the camera is recording video\n");
-              else if (!clutter_gst_camera_actor_is_ready_for_capture (
-                           CLUTTER_GST_CAMERA_ACTOR (app->camera_actor)))
+              else if (!clutter_gst_camera_is_ready_for_capture (app->camera_player))
                 g_print ("Unable to take photo as the camera is not ready for capture\n");
               else
                 {
@@ -271,9 +255,8 @@ input_cb (ClutterStage *stage,
 
                   filename = g_strdup_printf ("camera-photo-%d.jpg", photos_cnt++);
 
-                  clutter_gst_camera_actor_take_photo (
-                      CLUTTER_GST_CAMERA_ACTOR (app->camera_actor),
-                      filename);
+                  clutter_gst_camera_take_photo (app->camera_player,
+                                                 filename);
                   g_free (filename);
                 }
               break;
@@ -289,8 +272,7 @@ input_cb (ClutterStage *stage,
                 {
                   g_print ("ERROR: Unable to create 'dicetv' element, cannot set filter\n");
                 }
-              ret = clutter_gst_camera_actor_set_filter (
-                CLUTTER_GST_CAMERA_ACTOR (app->camera_actor), filter);
+              ret = clutter_gst_camera_set_filter (app->camera_player, filter);
               if (ret)
                 g_print ("Filter set successfully\n");
               else
@@ -300,8 +282,7 @@ input_cb (ClutterStage *stage,
             }
 
           case CLUTTER_r:
-            clutter_gst_camera_actor_remove_filter (
-                CLUTTER_GST_CAMERA_ACTOR (app->camera_actor));
+            clutter_gst_camera_remove_filter (app->camera_player);
             break;
 
           default:
@@ -316,7 +297,7 @@ input_cb (ClutterStage *stage,
 }
 
 static void
-ready_for_capture (ClutterGstCameraActor *camera_actor,
+ready_for_capture (ClutterGstCamera *camera_player,
                    gboolean ready)
 {
   if (ready)
@@ -324,13 +305,13 @@ ready_for_capture (ClutterGstCameraActor *camera_actor,
 }
 
 static void
-photo_saved (ClutterGstCameraActor *camera_actor)
+photo_saved (ClutterGstCamera *camera_player)
 {
   g_print ("Photo saved!\n");
 }
 
 static void
-video_saved (ClutterGstCameraActor *camera_actor)
+video_saved (ClutterGstCamera *camera_player)
 {
   g_print ("Video saved!\n");
 }
@@ -406,16 +387,16 @@ main (int argc, char *argv[])
 
   app = g_new0(CameraApp, 1);
   app->stage = stage;
-  app->camera_actor = clutter_gst_camera_actor_new ();
+  app->camera_actor = g_object_new (CLUTTER_GST_TYPE_ACTOR, NULL);
 
-  if (app->camera_actor == NULL)
+  app->camera_player = clutter_gst_camera_new ();
+  if (app->camera_player == NULL)
     {
-      g_error ("failed to create camera_actor");
+      g_error ("failed to create camera player");
       return EXIT_FAILURE;
     }
 
-  app->camera_devices = clutter_gst_camera_actor_get_camera_devices (
-      CLUTTER_GST_CAMERA_ACTOR (app->camera_actor));
+  app->camera_devices = clutter_gst_camera_get_camera_devices (app->camera_player);
   if (!app->camera_devices)
     {
       g_error ("no suitable camera device available");
@@ -435,13 +416,13 @@ main (int argc, char *argv[])
     }
   app->selected_camera_device = 0;
 
-  g_signal_connect (app->camera_actor, "ready-for-capture",
+  g_signal_connect (app->camera_player, "ready-for-capture",
                     G_CALLBACK (ready_for_capture),
                     app);
-  g_signal_connect (app->camera_actor, "photo-saved",
+  g_signal_connect (app->camera_player, "photo-saved",
                     G_CALLBACK (photo_saved),
                     app);
-  g_signal_connect (app->camera_actor, "video-saved",
+  g_signal_connect (app->camera_player, "video-saved",
                     G_CALLBACK (video_saved),
                     app);
   /* Handle it ourselves so can scale up for fullscreen better */
@@ -457,8 +438,7 @@ main (int argc, char *argv[])
   /* Hook up other events */
   g_signal_connect (stage, "event", G_CALLBACK (input_cb), app);
 
-  clutter_gst_camera_actor_set_playing (
-      CLUTTER_GST_CAMERA_ACTOR (app->camera_actor), TRUE);
+  clutter_gst_player_set_playing (CLUTTER_GST_PLAYER (app->camera_player), TRUE);
 
   clutter_actor_show (stage);
 
diff --git a/examples/video-player.c b/examples/video-player.c
index 1d1ebbf..69c9364 100644
--- a/examples/video-player.c
+++ b/examples/video-player.c
@@ -41,6 +41,7 @@ typedef struct _VideoApp
   ClutterActor *stage;
 
   ClutterActor *vactor;
+  ClutterGstPlayback *player;
 
   ClutterActor *control;
   ClutterActor *control_bg;
@@ -163,16 +164,16 @@ toggle_pause_state (VideoApp *app)
 
   if (app->paused)
     {
-      clutter_gst_player_set_playing (CLUTTER_GST_PLAYER(app->vactor),
-                                 TRUE);
+      clutter_gst_player_set_playing (CLUTTER_GST_PLAYER (app->player),
+                                      TRUE);
       app->paused = FALSE;
       clutter_actor_hide (app->control_play);
       clutter_actor_show (app->control_pause);
     }
   else
     {
-      clutter_gst_player_set_playing (CLUTTER_GST_PLAYER(app->vactor),
-                                 FALSE);
+      clutter_gst_player_set_playing (CLUTTER_GST_PLAYER (app->player),
+                                      FALSE);
       app->paused = TRUE;
       clutter_actor_hide (app->control_pause);
       clutter_actor_show (app->control_play);
@@ -232,8 +233,7 @@ input_cb (ClutterStage *stage,
 
               progress = (gdouble) dist / SEEK_W;
 
-              clutter_gst_player_set_progress (CLUTTER_GST_PLAYER (app->vactor),
-                                          progress);
+              clutter_gst_playback_set_progress (app->player, progress);
             }
         }
       handled = TRUE;
@@ -302,10 +302,10 @@ input_cb (ClutterStage *stage,
 }
 
 static void
-size_change (ClutterActor   *actor,
-             gint            base_width,
-             gint            base_height,
-             VideoApp       *app)
+size_change (ClutterGstPlayer *player,
+             gint              base_width,
+             gint              base_height,
+             VideoApp         *app)
 {
   ClutterActor *stage = app->stage;
   gfloat new_x, new_y, new_width, new_height;
@@ -317,7 +317,9 @@ size_change (ClutterActor   *actor,
   /* base_width and base_height are the actual dimensions of the buffers before
    * taking the pixel aspect ratio into account. We need to get the actual
    * size of the actor to display */
-  clutter_actor_get_size (actor, &frame_width, &frame_height);
+  /* clutter_actor_get_size (app->vactor, &frame_width, &frame_height); */
+  frame_width = base_width;
+  frame_height = base_height;
 
   new_height = (frame_height * stage_width) / frame_width;
   if (new_height <= stage_height)
@@ -336,8 +338,8 @@ size_change (ClutterActor   *actor,
       new_y = 0;
     }
 
-  clutter_actor_set_position (actor, new_x, new_y);
-  clutter_actor_set_size (actor, new_width, new_height);
+  clutter_actor_set_position (app->vactor, new_x, new_y);
+  clutter_actor_set_size (app->vactor, new_width, new_height);
 }
 
 static void
@@ -370,8 +372,7 @@ tick (GObject      *object,
       GParamSpec   *pspec,
       VideoApp     *app)
 {
-  ClutterGstPlayer *vactor = CLUTTER_GST_PLAYER (object);
-  gdouble progress = clutter_gst_player_get_progress (vactor);
+  gdouble progress = clutter_gst_playback_get_progress (app->player);
 
   clutter_actor_set_size (app->control_seekbar,
                           progress * SEEK_W,
@@ -384,7 +385,7 @@ on_video_actor_eos (ClutterGstPlayer *player,
 {
   if (opt_loop)
     {
-      clutter_gst_player_set_progress (player, 0.0);
+      clutter_gst_playback_set_progress (CLUTTER_GST_PLAYBACK (player), 0.0);
       clutter_gst_player_set_playing (player, TRUE);
     }
 }
@@ -509,7 +510,10 @@ main (int argc, char *argv[])
 
   app = g_new0(VideoApp, 1);
   app->stage = stage;
-  app->vactor = clutter_gst_video_actor_new ();
+  app->vactor = g_object_new (CLUTTER_GST_TYPE_ACTOR, NULL);
+  app->player = clutter_gst_playback_new ();
+
+  clutter_gst_actor_set_player (CLUTTER_GST_ACTOR (app->vactor), CLUTTER_GST_PLAYER (app->player));
 
   if (app->vactor == NULL)
     g_error("failed to create vactor");
@@ -519,10 +523,10 @@ main (int argc, char *argv[])
    * goes to the key frame position that can be quite far from where you
    * clicked. Using the ACCURATE flag tells playbin2 to seek to the actual
    * frame */
-  clutter_gst_player_set_seek_flags (CLUTTER_GST_PLAYER (app->vactor),
-                                     CLUTTER_GST_SEEK_FLAG_ACCURATE);
+  clutter_gst_playback_set_seek_flags (app->player,
+                                       CLUTTER_GST_SEEK_FLAG_ACCURATE);
 
-  g_signal_connect (app->vactor,
+  g_signal_connect (app->player,
                     "eos",
                     G_CALLBACK (on_video_actor_eos),
                     app);
@@ -532,13 +536,9 @@ main (int argc, char *argv[])
       g_print ("Remote media detected, setting up buffering\n");
 
       /* configure to 10 seconds of buffer duration */
-      clutter_gst_player_set_buffer_duration (
-                        CLUTTER_GST_PLAYER (app->vactor),
-                        10 * GST_SECOND);
-      clutter_gst_player_set_buffering_mode (
-                        CLUTTER_GST_PLAYER (app->vactor),
-                        CLUTTER_GST_BUFFERING_MODE_STREAM);
-      g_signal_connect (app->vactor,
+      clutter_gst_playback_set_buffer_duration (app->player, 10 * GST_SECOND);
+      clutter_gst_playback_set_buffering_mode (app->player, CLUTTER_GST_BUFFERING_MODE_STREAM);
+      g_signal_connect (app->player,
                         "notify::buffer-fill",
                         G_CALLBACK (on_video_actor_notify_buffer_fill),
                         app);
@@ -557,20 +557,20 @@ main (int argc, char *argv[])
                     NULL);
 
   /* Handle it ourselves so can scale up for fullscreen better */
-  g_signal_connect_after (app->vactor,
+  g_signal_connect_after (app->player,
                           "size-change",
                           G_CALLBACK (size_change), app);
 
   /* Load up out video actor */
-  clutter_gst_player_set_uri (CLUTTER_GST_PLAYER (app->vactor), uri);
+  clutter_gst_playback_set_filename (app->player, uri);
 
-  if (clutter_gst_player_is_live_media (CLUTTER_GST_PLAYER (app->vactor)))
+  if (clutter_gst_playback_is_live_media (app->player))
     g_print ("Playing live media\n");
   else
     g_print ("Playing non-live media\n");
 
   /* Set up things so that a visualisation is played if there's no video */
-  pipe = clutter_gst_player_get_pipeline (CLUTTER_GST_PLAYER (app->vactor));
+  pipe = clutter_gst_player_get_pipeline (CLUTTER_GST_PLAYER (app->player));
   if (!pipe)
     g_error ("Unable to get gstreamer pipeline!\n");
 
@@ -659,11 +659,11 @@ main (int argc, char *argv[])
   /* Hook up other events */
   g_signal_connect (stage, "event", G_CALLBACK (input_cb), app);
 
-  g_signal_connect (app->vactor,
+  g_signal_connect (app->player,
                     "notify::progress", G_CALLBACK (tick),
                     app);
 
-  clutter_gst_player_set_playing (CLUTTER_GST_PLAYER (app->vactor), TRUE);
+  clutter_gst_player_set_playing (CLUTTER_GST_PLAYER (app->player), TRUE);
 
   clutter_actor_show (stage);
 
diff --git a/examples/video-sink.c b/examples/video-sink.c
index 82030d7..9fc7ab6 100644
--- a/examples/video-sink.c
+++ b/examples/video-sink.c
@@ -29,10 +29,10 @@
 #include <clutter-gst/clutter-gst.h>
 
 void
-size_change (ClutterActor   *actor,
-             gint            width,
-             gint            height,
-             gpointer        user_data)
+size_change (ClutterGstPlayer *player,
+             gint              width,
+             gint              height,
+             ClutterActor     *actor)
 {
   ClutterActor *stage;
   gfloat new_x, new_y, new_width, new_height;
@@ -68,14 +68,14 @@ size_change (ClutterActor   *actor,
 int
 main (int argc, char *argv[])
 {
-  ClutterTimeline  *timeline;
-  ClutterActor     *stage;
-  ClutterActor     *actor;
-  GstPipeline      *pipeline;
-  GstElement       *src;
-  GstElement       *warp;
-  GstElement       *colorspace;
-  GstElement       *sink;
+  ClutterTimeline    *timeline;
+  ClutterActor       *stage;
+  ClutterActor       *actor;
+  GstElement         *src;
+  GstElement         *warp;
+  GstElement         *bin;
+  GstElement         *pipeline;
+  ClutterGstPlayback *player;
 
   if (argc < 1)
     {
@@ -98,24 +98,23 @@ main (int argc, char *argv[])
 
   actor = g_object_new (CLUTTER_GST_TYPE_ACTOR, NULL);
 
-  g_signal_connect (actor,
-                    "size-change",
-                    G_CALLBACK (size_change), NULL);
-
   /* Set up pipeline */
-  pipeline = GST_PIPELINE (gst_pipeline_new (NULL));
+  player = clutter_gst_playback_new ();
+  pipeline = clutter_gst_player_get_pipeline (CLUTTER_GST_PLAYER (player));
+
+  g_signal_connect (player, "size-change",
+                    G_CALLBACK (size_change), actor);
 
   src = gst_element_factory_make ("videotestsrc", NULL);
   warp = gst_element_factory_make ("warptv", NULL);
-  colorspace = gst_element_factory_make ("videoconvert", NULL);
-  sink = gst_element_factory_make ("cluttersink", NULL);
-  g_object_set (sink, "actor", actor, NULL);
+  bin = gst_bin_new ("video-test-source");
+
+  gst_bin_add_many (GST_BIN (bin), src, warp, NULL);
+  gst_element_link_many (src, warp, NULL);
 
-  // g_object_set (src , "pattern", 10, NULL);
+  g_object_set (pipeline, "source", bin);
 
-  gst_bin_add_many (GST_BIN (pipeline), src, warp, colorspace, sink, NULL);
-  gst_element_link_many (src, warp, colorspace, sink, NULL);
-  gst_element_set_state (GST_ELEMENT(pipeline), GST_STATE_PLAYING);
+  clutter_gst_player_set_playing (CLUTTER_GST_PLAYER (player), TRUE);
 
   /* start the timeline */
   clutter_timeline_start (timeline);
diff --git a/tests/test-start-stop.c b/tests/test-start-stop.c
index 5908e4e..d9b9e7e 100644
--- a/tests/test-start-stop.c
+++ b/tests/test-start-stop.c
@@ -76,17 +76,17 @@ gboolean
 test (gpointer data)
 {
   static int count = 1;
-  static ClutterGstPlayer *player = NULL;
+  static ClutterGstPlayback *player = NULL;
   static char *uri[2] = {NULL, NULL};
   const char *playing_uri = NULL;
 
   /* Check until we get video playing */
-  if (!clutter_gst_player_is_playing (CLUTTER_GST_PLAYER (data)))
+  if (!clutter_gst_player_get_playing (CLUTTER_GST_PLAYER (data)))
     return TRUE;
 
-  if (CLUTTER_GST_PLAYER (data) != player)
+  if (CLUTTER_GST_PLAYBACK (data) != player)
     {
-      player = CLUTTER_GST_PLAYER (data);
+      player = CLUTTER_GST_PLAYBACK (data);
       count = 1;
       g_free(uri[0]);
       uri[0] = NULL;
@@ -94,25 +94,25 @@ test (gpointer data)
       uri[1] = NULL;
     }
 
-  clutter_gst_player_set_filename (player, video_files[count & 1]);
+  clutter_gst_playback_set_filename (player, video_files[count & 1]);
   g_print ("playing %s\n", video_files[count & 1]);
 
   if (uri[count & 1] == NULL)
     {
-      uri[count & 1] = g_strdup (clutter_gst_player_get_uri (player));
+      uri[count & 1] = g_strdup (clutter_gst_playback_get_uri (player));
       g_assert (uri[count & 1] != NULL);
     }
 
   /* See if it's still playing */
-  g_assert (clutter_gst_player_is_playing (player));
+  g_assert (clutter_gst_player_get_playing (CLUTTER_GST_PLAYER (player)));
 
   /* See if it's already change to play correct file */
-  playing_uri = clutter_gst_player_get_uri (player);
+  playing_uri = clutter_gst_playback_get_uri (player);
   g_assert_cmpstr (playing_uri, ==, uri[count & 1]);
 
   if (count ++ > 10)
     {
-      clutter_gst_player_set_playing (player, FALSE);
+      clutter_gst_player_set_playing (CLUTTER_GST_PLAYER (player), FALSE);
       clutter_main_quit ();
       return FALSE;
     }
@@ -124,10 +124,11 @@ test (gpointer data)
 int
 main (int argc, char *argv[])
 {
-  ClutterInitError error;
-  ClutterColor     stage_color = { 0x00, 0x00, 0x00, 0x00 };
-  ClutterActor    *stage = NULL;
-  ClutterActor    *video = NULL;
+  ClutterInitError    error;
+  ClutterColor        stage_color = { 0x00, 0x00, 0x00, 0x00 };
+  ClutterActor       *stage = NULL;
+  ClutterActor       *video = NULL;
+  ClutterGstPlayback *player = NULL;
 
   if (argc < 3)
     {
@@ -144,23 +145,27 @@ main (int argc, char *argv[])
   stage = clutter_stage_new ();
   clutter_actor_set_background_color (stage, &stage_color);
 
-  video = clutter_gst_video_actor_new ();
-  g_assert (CLUTTER_GST_IS_VIDEO_ACTOR(video));
+  player = clutter_gst_playback_new ();
+
+  video = /* clutter_gst_actor_new () */ g_object_new (CLUTTER_GST_TYPE_ACTOR,
+                                                       NULL);
+  g_assert (CLUTTER_GST_IS_ACTOR (video));
+  clutter_gst_actor_set_player (CLUTTER_GST_ACTOR (video), CLUTTER_GST_PLAYER (player));
+  clutter_actor_add_child (stage, video);
 
   g_signal_connect (video,
                     "size-change",
                     G_CALLBACK(size_change),
                     stage);
-  g_signal_connect (video,
+  g_signal_connect (player,
                     "error",
                     G_CALLBACK(on_error),
                     stage);
   g_timeout_add (5000, test, video);
-  clutter_gst_player_set_filename (CLUTTER_GST_PLAYER (video), video_files[0]);
-  clutter_gst_player_set_audio_volume (CLUTTER_GST_PLAYER (video), 0.5);
-  clutter_gst_player_set_playing (CLUTTER_GST_PLAYER (video), TRUE);
+  clutter_gst_playback_set_filename (player, video_files[0]);
+  clutter_gst_player_set_audio_volume (CLUTTER_GST_PLAYER (player), 0.5);
+  clutter_gst_player_set_playing (CLUTTER_GST_PLAYER (player), TRUE);
 
-  clutter_actor_add_child (stage, video);
   clutter_actor_show (stage);
   clutter_main ();
 
diff --git a/tests/test-video-actor-new-unref-loop.c b/tests/test-video-actor-new-unref-loop.c
index 5a611f2..942f56a 100644
--- a/tests/test-video-actor-new-unref-loop.c
+++ b/tests/test-video-actor-new-unref-loop.c
@@ -43,7 +43,7 @@ main (int argc, char *argv[])
   for (i = 0; ; i++)
   {
     g_debug("VideoActor #%d", i);
-    vactor = clutter_gst_video_actor_new ();
+    vactor = g_object_new (CLUTTER_GST_TYPE_ACTOR, NULL);
     g_object_ref_sink (vactor);
     g_object_unref (vactor);
   }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]