[Cogl] [PATCH] Include CoglGst

Neil Roberts neil at linux.intel.com
Fri Feb 22 06:56:05 PST 2013


From: Plamena Manolova <plamena.n.manolova at intel.com>

Hi,

Thanks for the patch implementing the feedback. Reading through it
again I have a few more notes to discuss. I'm also attaching an
updated patch with squashes in your work and some more minor changes.

As far as I can tell the changes to the basic video player to make it
not continously redraw effectively make it busy-wait until the
conditions for drawing are met. The program installs an idle handler
which returns TRUE. This will make it continuously wake up the main
loop so it will always use 100% CPU to play the video even if the
decompression can be done much quicker. I think the only way you could
get this to work properly would be if GStreamer provides some sort of
event to notify that it has finished rendering a frame. If GStreamer
doesn't provide that then maybe CoglGstVideoSink could have its own
signal which gets emitted when a new frame is uploaded. Perhaps we
could consult some GStreamer experts to find out what is the best
thing to do here.

It's still using GStreamer 0.10. Surely we should be using GStreamer
1.0?

In cogl_gst_play_video, it has special handling for when the URL
passed is NULL. However it then just makes the program abort. If this
is meant to be interpreted as a programmer error, then it should
probably just do g_return_if_fail (url != NULL).

When the video player is constructed with a URI and is set to play, it
creates the video pipeline for that URI and then immediately calls
cogl_gst_video_play_video which creates the pipeline again. Maybe the
URI should become a property that you can set and it will lazily
create the pipeline the first time it is played?

cogl_gst_source_push() has a call to g_mutex_free. That doesn't look
right. Shouldn't the mutex be freed in the finalize implementation
instead? In fact freeing mutexes is now deprecated so we should use
g_mutex_clear instead. I've made this change myself in the attached
patch.

It looks like cogl_gst_video_player_stop should set
player->priv->pipeline to NULL otherwise it will probably crash if
someone stops the video twice.

In the updated patch I have made the following changes:

• All the C files now include config.h. Effectively all C files in an
  autotooled project should include config.h

• I've made the private data for CoglGstVideoPlayer use the GObject
  mechanism for allocating the private data instead of manually
  allocating the data. That will make it allocate the private data and
  the object data in a single allocation.

• The CoglContext is now set as a construct-only property. Otherwise
  it is not possible to construct a CoglGstVideoPlayer object without
  calling cogl_gst_video_player_new and this upsets some users.

• I've moved the static strings for the GLSL shader code out of the
  private headers and put them into their own C file. It's a bit weird
  to put static data in the header because if more than one file
  included that it would get a separate copy of the data.

• I've split some lines that are over 80 characters and removed some
  trailing whitespace.

Regards,
- Neil

-- >8 --

CoglGst is a GStreamer integration library that facilitates
video playback using the Cogl API. It works by retrieving
each video frame from the GStreamer pipeline and attaching
it to a Cogl pipeline in the form of a Cogl texture along
with possible color model conversion shaders. The pipeline
is then retrieved by the user during each draw. An example
use of the CoglGst API is included in the examples directory.
---
 .gitignore                         |   1 +
 Makefile.am                        |   7 +-
 cogl-gst/Makefile.am               |  58 +++
 cogl-gst/cogl-gst-shader.c         |  75 +++
 cogl-gst/cogl-gst-shader.h         |  45 ++
 cogl-gst/cogl-gst-util.c           |  51 ++
 cogl-gst/cogl-gst-util.h           |  43 ++
 cogl-gst/cogl-gst-video-player.c   | 273 +++++++++++
 cogl-gst/cogl-gst-video-player.h   | 121 +++++
 cogl-gst/cogl-gst-video-sink.c     | 926 +++++++++++++++++++++++++++++++++++++
 cogl-gst/cogl-gst-video-sink.h     | 112 +++++
 cogl-gst/cogl-gst.h                |  40 ++
 cogl-gst/cogl-gst.pc.in            |  13 +
 configure.ac                       |  36 ++
 examples/Makefile.am               |   7 +
 examples/cogl-basic-video-player.c | 162 +++++++
 16 files changed, 1969 insertions(+), 1 deletion(-)
 create mode 100644 cogl-gst/Makefile.am
 create mode 100644 cogl-gst/cogl-gst-shader.c
 create mode 100644 cogl-gst/cogl-gst-shader.h
 create mode 100644 cogl-gst/cogl-gst-util.c
 create mode 100644 cogl-gst/cogl-gst-util.h
 create mode 100644 cogl-gst/cogl-gst-video-player.c
 create mode 100644 cogl-gst/cogl-gst-video-player.h
 create mode 100644 cogl-gst/cogl-gst-video-sink.c
 create mode 100644 cogl-gst/cogl-gst-video-sink.h
 create mode 100644 cogl-gst/cogl-gst.h
 create mode 100644 cogl-gst/cogl-gst.pc.in
 create mode 100644 examples/cogl-basic-video-player.c

diff --git a/.gitignore b/.gitignore
index 1adb397..d7842f8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -68,6 +68,7 @@ depcomp
 /examples/cogl-x11-foreign
 /examples/cogl-x11-tfp
 /examples/cogland
+/examples/cogl-basic-video-player
 gtk-doc.make
 install-sh
 libtool
diff --git a/Makefile.am b/Makefile.am
index c764b46..15fb589 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -8,6 +8,10 @@ if BUILD_COGL_GLES2
 SUBDIRS += cogl-gles2
 endif
 
+if BUILD_COGL_GST
+SUBDIRS += cogl-gst
+endif
+
 SUBDIRS += examples doc po build
 
 ACLOCAL_AMFLAGS = -I build/autotools ${ACLOCAL_FLAGS}
@@ -32,6 +36,7 @@ DISTCHECK_CONFIGURE_FLAGS = \
 	--enable-xlib-egl-platform \
 	--enable-wayland-egl-platform \
 	--enable-glx \
-	--enable-wayland-egl-server
+	--enable-wayland-egl-server  \
+	--enable-cogl-gst
 
 include $(top_srcdir)/build/autotools/Makefile.am.release
diff --git a/cogl-gst/Makefile.am b/cogl-gst/Makefile.am
new file mode 100644
index 0000000..c33dd98
--- /dev/null
+++ b/cogl-gst/Makefile.am
@@ -0,0 +1,58 @@
+include $(top_srcdir)/build/autotools/Makefile.am.silent
+
+NULL =
+
+CLEANFILES =
+DISTCLEANFILES =
+
+EXTRA_DIST =
+
+source_c = \
+	cogl-gst-shader.c \
+	cogl-gst-util.c \
+	cogl-gst-video-player.c \
+	cogl-gst-video-sink.c \
+	$(NULL)
+
+source_h = \
+	cogl-gst.h \
+	cogl-gst-util.h \
+	cogl-gst-video-player.h \
+	cogl-gst-video-sink.h \
+	$(NULL)
+
+source_h_priv = \
+	$(NULL)
+
+lib_LTLIBRARIES = libcogl-gst.la
+
+libcogl_gst_la_SOURCES = $(source_c) $(source_h) $(source_h_priv)
+libcogl_gst_la_CFLAGS = $(COGL_DEP_CFLAGS) $(COGL_GST_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS) $(MAINTAINER_CFLAGS)
+libcogl_gst_la_LIBADD = $(top_builddir)/cogl/libcogl2.la
+libcogl_gst_la_LIBADD += $(COGL_DEP_LIBS) $(COGL_GST_DEP_LIBS) $(COGL_EXTRA_LDFLAGS)
+libcogl_gst_la_LDFLAGS = \
+	-export-dynamic \
+	-export-symbols-regex "^cogl_gst_.*" \
+	-no-undefined \
+	-version-info @COGL_LT_CURRENT@:@COGL_LT_REVISION@:@COGL_LT_AGE@
+
+AM_CPPFLAGS = \
+	-DCOGL_COMPILATION		\
+	-DG_LOG_DOMAIN=\"CoglGst\"	\
+	-I$(top_srcdir)/cogl		\
+	-I$(top_builddir)/cogl		\
+	-I$(top_srcdir)/cogl/winsys	\
+	-I$(top_srcdir)			\
+	-I$(top_builddir)
+
+cogl_gstheadersdir = $(includedir)/cogl/cogl-gst
+cogl_gstheaders_HEADERS = $(source_h)
+
+pc_files = cogl-gst.pc
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = $(pc_files)
+
+EXTRA_DIST += cogl-gst.pc.in
+DISTCLEANFILES += $(pc_files)
+
diff --git a/cogl-gst/cogl-gst-shader.c b/cogl-gst/cogl-gst-shader.c
new file mode 100644
index 0000000..cdc627f
--- /dev/null
+++ b/cogl-gst/cogl-gst-shader.c
@@ -0,0 +1,75 @@
+/*
+ * Cogl-GStreamer.
+ *
+ * GStreamer integration library for Cogl.
+ *
+ * cogl-gst-video-sink-private.h - Miscellaneous video sink functions
+ *
+ * Authored by Jonathan Matthew  <jonathan at kaolin.wh9.net>,
+ *             Chris Lord        <chris at openedhand.com>
+ *             Damien Lespiau    <damien.lespiau at intel.com>
+ *             Matthew Allum     <mallum at openedhand.com>
+ *             Plamena Manolova  <plamena.n.manolova at intel.com>
+ *
+ * Copyright (C) 2007, 2008 OpenedHand
+ * Copyright (C) 2009, 2010, 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "cogl-gst-shader.h"
+
+const char
+_cogl_gst_shader_yv12_to_rgba_decl[] =
+  "uniform sampler2D ytex;\n"
+  "uniform sampler2D utex;\n"
+  "uniform sampler2D vtex;\n"
+  "varying vec4 rgb_color;\n"
+  "vec4 cogl_gst_sample_video (vec2 UV) {\n"
+  "  float y = 1.1640625 * (texture2D (ytex, UV).g - 0.0625);\n"
+  "  float u = texture2D (utex, UV).g - 0.5;\n"
+  "  float v = texture2D (vtex, UV).g - 0.5;\n"
+  "  vec4 color;\n"
+  "  color.r = y + 1.59765625 * v;\n"
+  "  color.g = y - 0.390625 * u - 0.8125 * v;\n"
+  "  color.b = y + 2.015625 * u;\n"
+  "  color.a = 1.0;\n"
+  "  return color;\n"
+  "}";
+
+const char
+_cogl_gst_shader_ayuv_to_rgba_decl[] =
+  "uniform sampler2D tex;\n"
+  "varying vec4 rgb_color;\n"
+  "vec4 cogl_gst_sample_video (vec2 UV) {\n"
+  "  vec4 color = texture2D (tex, UV);\n"
+  "  float y = 1.1640625 * (color.g - 0.0625);\n"
+  "  float u = color.b - 0.5;\n"
+  "  float v = color.a - 0.5;\n"
+  "  color.a = color.r;\n"
+  "  color.r = y + 1.59765625 * v;\n"
+  "  color.g = y - 0.390625 * u - 0.8125 * v;\n"
+  "  color.b = y + 2.015625 * u;\n"
+  "  return color;\n"
+  "}";
+
+const char
+_cogl_gst_shader_default_post[] =
+  "cogl_color_out = cogl_gst_sample_video (cogl_tex_coord0_in.st);";
diff --git a/cogl-gst/cogl-gst-shader.h b/cogl-gst/cogl-gst-shader.h
new file mode 100644
index 0000000..ac45a8c
--- /dev/null
+++ b/cogl-gst/cogl-gst-shader.h
@@ -0,0 +1,45 @@
+/*
+ * Cogl-GStreamer.
+ *
+ * GStreamer integration library for Cogl.
+ *
+ * cogl-gst-video-sink-private.h - Miscellaneous video sink functions
+ *
+ * Authored by Jonathan Matthew  <jonathan at kaolin.wh9.net>,
+ *             Chris Lord        <chris at openedhand.com>
+ *             Damien Lespiau    <damien.lespiau at intel.com>
+ *             Matthew Allum     <mallum at openedhand.com>
+ *             Plamena Manolova  <plamena.n.manolova at intel.com>
+ *
+ * Copyright (C) 2007, 2008 OpenedHand
+ * Copyright (C) 2009, 2010, 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.
+ */
+
+#ifndef __COGL_GST_SHADER_PRIVATE_H__
+#define __COGL_GST_SHADER_PRIVATE_H__
+
+extern const char
+_cogl_gst_shader_yv12_to_rgba_decl[];
+
+extern const char
+_cogl_gst_shader_ayuv_to_rgba_decl[];
+
+extern const char
+_cogl_gst_shader_default_post[];
+
+#endif /* __COGL_GST_SHADER_PRIVATE_H__ */
diff --git a/cogl-gst/cogl-gst-util.c b/cogl-gst/cogl-gst-util.c
new file mode 100644
index 0000000..fe15073
--- /dev/null
+++ b/cogl-gst/cogl-gst-util.c
@@ -0,0 +1,51 @@
+/*
+ * Cogl-GStreamer.
+ *
+ * GStreamer integration library for Cogl.
+ *
+ * cogl-gst-util.h - Miscellaneous functions.
+ *
+ * Authored by Jonathan Matthew  <jonathan at kaolin.wh9.net>,
+ *             Chris Lord        <chris at openedhand.com>
+ *             Damien Lespiau    <damien.lespiau at intel.com>
+ *             Matthew Allum     <mallum at openedhand.com>
+ *             Plamena Manolova  <plamena.n.manolova at intel.com>
+ *
+ * Copyright (C) 2007, 2008 OpenedHand
+ * Copyright (C) 2009, 2010, 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <cogl-gst/cogl-gst-util.h>
+#include <gst/gst.h>
+
+void
+cogl_gst_init (int* argc,
+               char*** argv)
+{
+  GError *error = NULL;
+  CoglBool success;
+
+  success = gst_init_check (argc, argv, &error);
+
+  if (success == FALSE && error != NULL)
+    g_error ("COGL-GST: Failed to initialize GStreamer: %s\n", error->message);
+}
diff --git a/cogl-gst/cogl-gst-util.h b/cogl-gst/cogl-gst-util.h
new file mode 100644
index 0000000..fe92004
--- /dev/null
+++ b/cogl-gst/cogl-gst-util.h
@@ -0,0 +1,43 @@
+/*
+ * Cogl-GStreamer.
+ *
+ * GStreamer integration library for Cogl.
+ *
+ * cogl-gst-util.h - Miscellaneous functions.
+ *
+ * Authored by Jonathan Matthew  <jonathan at kaolin.wh9.net>,
+ *             Chris Lord        <chris at openedhand.com>
+ *             Damien Lespiau    <damien.lespiau at intel.com>
+ *             Matthew Allum     <mallum at openedhand.com>
+ *             Plamena Manolova  <plamena.n.manolova at intel.com>
+ *
+ * Copyright (C) 2007, 2008 OpenedHand
+ * Copyright (C) 2009, 2010, 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.
+ */
+
+
+#ifndef __GOGL_GST_UTILS_H__
+#define __GOGL_GST_UTILS_H__
+
+#include <cogl/cogl.h>
+
+void
+cogl_gst_init (int* argc,
+               char*** argv);
+
+#endif
diff --git a/cogl-gst/cogl-gst-video-player.c b/cogl-gst/cogl-gst-video-player.c
new file mode 100644
index 0000000..e5800a9
--- /dev/null
+++ b/cogl-gst/cogl-gst-video-player.c
@@ -0,0 +1,273 @@
+/*
+ * Cogl-GStreamer.
+ *
+ * GStreamer integration library for Cogl.
+ *
+ * cogl-gst-video-player.c - A basic video player for user convinience.
+ *
+ * Authored by Plamena Manolova  <plamena.n.manolova at 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "cogl-gst-video-player.h"
+
+G_DEFINE_TYPE (CoglGstVideoPlayer, cogl_gst_video_player, G_TYPE_OBJECT);
+
+#define COGL_GST_VIDEO_PLAYER_GET_PRIVATE(obj) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((obj), COGL_GST_TYPE_VIDEO_PLAYER, \
+                                CoglGstVideoPlayerPrivate))
+
+struct _CoglGstVideoPlayerPrivate
+{
+  CoglContext *ctx;
+  GstElement *sink;
+  GstElement *pipeline;
+  GstElement *bin;
+  char *uri;
+  unsigned int bus_watch;
+};
+
+#define COGL_GST_SEEK_FLAGS (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT)
+
+enum
+{
+  PROP_0,
+  PROP_COGL_CONTEXT
+};
+
+static void
+cogl_gst_video_player_set_property (GObject *object,
+                                    unsigned int prop_id,
+                                    const GValue *value,
+                                    GParamSpec *pspec)
+{
+  CoglGstVideoPlayer *player = COGL_GST_VIDEO_PLAYER (object);
+  CoglGstVideoPlayerPrivate *priv = player->priv;
+
+  switch (prop_id)
+    {
+    case PROP_COGL_CONTEXT:
+      priv->ctx = cogl_object_ref (g_value_get_pointer (value));
+      break;
+
+     default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+   }
+}
+
+static void
+cogl_gst_video_player_finalize (GObject *object)
+{
+  CoglGstVideoPlayer *player = COGL_GST_VIDEO_PLAYER (object);
+  CoglGstVideoPlayerPrivate *priv = player->priv;
+
+  if (priv->ctx)
+    cogl_object_unref (priv->ctx);
+
+  G_OBJECT_CLASS (cogl_gst_video_player_parent_class)->finalize (object);
+}
+
+static void
+cogl_gst_video_player_class_init (CoglGstVideoPlayerClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GParamSpec *pspec;
+
+  object_class->set_property = cogl_gst_video_player_set_property;
+  object_class->finalize = cogl_gst_video_player_finalize;
+
+  g_type_class_add_private (klass, sizeof (CoglGstVideoPlayerPrivate));
+
+  pspec = g_param_spec_pointer ("cogl-context",
+                                "The Cogl Context",
+                                "The Cogl Context",
+                                G_PARAM_WRITABLE |
+                                G_PARAM_CONSTRUCT_ONLY |
+                                G_PARAM_STATIC_NAME |
+                                G_PARAM_STATIC_NICK |
+                                G_PARAM_STATIC_BLURB);
+  g_object_class_install_property (object_class, PROP_COGL_CONTEXT, pspec);
+}
+
+static void
+cogl_gst_video_player_init (CoglGstVideoPlayer *self)
+{
+  self->priv = COGL_GST_VIDEO_PLAYER_GET_PRIVATE (self);
+}
+
+static void
+_cogl_gst_prepare_new_video_pipeline (CoglContext *ctx,
+                                      CoglGstVideoPlayer *player,
+                                      char *uri)
+{
+  CoglGstVideoPlayerPrivate* priv = player->priv;
+  priv->pipeline = gst_pipeline_new ("gst-player");
+  priv->bin = gst_element_factory_make ("playbin", "bin");
+  priv->sink = gst_element_factory_make ("coglsink", "videosink");
+  priv->uri = uri;
+  priv->ctx = ctx;
+  priv->bus_watch = 0;
+
+  cogl_gst_video_sink_set_context (COGL_GST_VIDEO_SINK (priv->sink), ctx);
+
+  g_object_set (G_OBJECT (priv->bin), "video-sink", priv->sink, NULL);
+
+
+  gst_bin_add (GST_BIN (priv->pipeline), priv->bin);
+
+  if (priv->uri != NULL)
+    g_object_set (G_OBJECT (priv->bin), "uri", priv->uri, NULL);
+}
+
+CoglGstVideoPlayer*
+cogl_gst_video_player_new (CoglContext *ctx,
+                           CoglBool play,
+                           char *uri)
+{
+  CoglGstVideoPlayer *player =
+    g_object_new (COGL_GST_TYPE_VIDEO_PLAYER,
+                  "cogl-context", ctx,
+                  NULL);
+
+  _cogl_gst_prepare_new_video_pipeline (ctx, player, uri);
+
+  if (play == TRUE)
+    cogl_gst_play_video (player, player->priv->uri);
+
+  return player;
+}
+
+void
+cogl_gst_play_video (CoglGstVideoPlayer *player,
+                     char *uri)
+{
+  if (uri)
+    {
+      cogl_gst_video_player_stop (player);
+      _cogl_gst_prepare_new_video_pipeline (player->priv->ctx, player, uri);
+      gst_element_set_state (player->priv->pipeline, GST_STATE_PLAYING);
+    }
+  else
+    {
+      gst_element_set_state (player->priv->pipeline, GST_STATE_NULL);
+      g_error ("COGL-GST: Invalid uri");
+    }
+}
+
+CoglGstVideoSink*
+cogl_gst_video_player_get_sink (CoglGstVideoPlayer *player)
+{
+  return COGL_GST_VIDEO_SINK (player->priv->sink);
+}
+
+void
+cogl_gst_video_player_add_bus_watch (CoglGstVideoPlayer *player,
+                                     GstBusFunc func,
+                                     void *user_data)
+{
+  GstBus *bus;
+  bus = gst_pipeline_get_bus (GST_PIPELINE (player->priv->pipeline));
+  if (player->priv->bus_watch != 0)
+    g_source_remove (player->priv->bus_watch);
+
+  player->priv->bus_watch = gst_bus_add_watch (bus, func, user_data);
+  gst_object_unref (bus);
+}
+
+void
+cogl_gst_video_player_stop (CoglGstVideoPlayer *player)
+{
+  if (player->priv->pipeline)
+    {
+      gst_element_set_state (player->priv->pipeline, GST_STATE_NULL);
+      gst_object_unref (GST_OBJECT (player->priv->pipeline));
+    }
+}
+
+void
+cogl_gst_video_player_reset (CoglGstVideoPlayer *player)
+{
+  gst_element_seek (player->priv->pipeline, 1.0,
+                    GST_FORMAT_TIME, COGL_GST_SEEK_FLAGS,
+                    GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE,
+                    GST_CLOCK_TIME_NONE);
+}
+
+void
+cogl_gst_video_player_pause (CoglGstVideoPlayer *player)
+{
+  gst_element_set_state (player->priv->pipeline, GST_STATE_PAUSED);
+}
+
+void
+cogl_gst_video_player_resume (CoglGstVideoPlayer *player)
+{
+  gst_element_set_state (player->priv->pipeline, GST_STATE_PLAYING);
+}
+
+void
+cogl_gst_video_player_seek (CoglGstVideoPlayer *player,
+                            int value)
+{
+  gst_element_seek (player->priv->pipeline, 1.0,
+                    GST_FORMAT_TIME, COGL_GST_SEEK_FLAGS,
+                    GST_SEEK_TYPE_CUR, value * GST_SECOND, GST_SEEK_TYPE_NONE,
+                    GST_CLOCK_TIME_NONE);
+}
+
+void
+cogl_gst_video_player_seek_absolute (CoglGstVideoPlayer *player,
+                                     uint64_t value)
+{
+  gst_element_seek (player->priv->pipeline, 1.0, GST_FORMAT_TIME,
+                    COGL_GST_SEEK_FLAGS,
+                    GST_SEEK_TYPE_SET, value, GST_SEEK_TYPE_NONE,
+                    GST_CLOCK_TIME_NONE);
+}
+
+int64_t
+cogl_gst_video_player_get_progress (CoglGstVideoPlayer *player)
+{
+  GstFormat format = GST_FORMAT_TIME;
+  int64_t prog;
+
+  gst_element_query_position (player->priv->pipeline, &format, &prog);
+  if (format != GST_FORMAT_TIME)
+    return GST_CLOCK_TIME_NONE;
+
+  return prog;
+}
+
+int64_t
+cogl_gst_video_player_get_duration (CoglGstVideoPlayer *player)
+{
+  GstFormat format = GST_FORMAT_TIME;
+  int64_t dur;
+
+  gst_element_query_duration (player->priv->pipeline, &format, &dur);
+  if (format != GST_FORMAT_TIME)
+    return GST_CLOCK_TIME_NONE;
+
+  return dur;
+}
diff --git a/cogl-gst/cogl-gst-video-player.h b/cogl-gst/cogl-gst-video-player.h
new file mode 100644
index 0000000..d83aa30
--- /dev/null
+++ b/cogl-gst/cogl-gst-video-player.h
@@ -0,0 +1,121 @@
+/*
+ * Cogl-GStreamer.
+ *
+ * GStreamer integration library for Cogl.
+ *
+ * cogl-gst-video-player.h - A basic video player for user convinience.
+ *
+ * Authored by Plamena Manolova  <plamena.n.manolova at 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.
+ */
+
+#ifndef __COGL_GST_VIDEO_PLAYER_H__
+#define __COGL_GST_VIDEO_PLAYER_H__
+
+#include <cogl-gst/cogl-gst-video-sink.h>
+
+G_BEGIN_DECLS
+
+#define COGL_GST_TYPE_VIDEO_PLAYER cogl_gst_video_player_get_type()
+
+#define COGL_GST_VIDEO_PLAYER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  COGL_GST_TYPE_VIDEO_PLAYER, CoglGstVideoPlayer))
+
+#define COGL_GST_VIDEO_PLAYER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  COGL_GST_TYPE_VIDEO_PLAYER, CoglGstVideoPlayerClass))
+
+#define COGL_GST_IS_VIDEO_PLAYER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  COGL_GST_TYPE_VIDEO_PLAYER))
+
+#define COGL_GST_IS_VIDEO_PLAYER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  COGL_GST_TYPE_VIDEO_PLAYER))
+
+#define COGL_GST_VIDEO_PLAYER_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  COGL_GST_TYPE_VIDEO_PLAYER, CoglGstVideoPlayerClass))
+
+
+typedef struct _CoglGstVideoPlayer   CoglGstVideoPlayer;
+typedef struct _CoglGstVideoPlayerClass   CoglGstVideoPlayerClass;
+typedef struct _CoglGstVideoPlayerPrivate CoglGstVideoPlayerPrivate;
+typedef struct _CoglGstVideoPlayerPrivate CoglGstVideoPlayerPrivate;
+
+struct _CoglGstVideoPlayer
+{
+  GObject parent;
+  CoglGstVideoPlayerPrivate *priv;
+};
+
+struct _CoglGstVideoPlayerClass
+{
+  GObjectClass parent_class;
+};
+
+GType cogl_gst_video_player_get_type (void) G_GNUC_CONST;
+
+CoglGstVideoPlayer*
+cogl_gst_video_player_new (CoglContext *ctx,
+                           CoglBool play,
+                           char *uri);
+
+void
+cogl_gst_play_video (CoglGstVideoPlayer* player,
+                     char* uri);
+
+CoglGstVideoSink*
+cogl_gst_video_player_get_sink (CoglGstVideoPlayer *player);
+
+void
+cogl_gst_video_player_add_bus_watch (CoglGstVideoPlayer *player,
+                                     GstBusFunc func,
+                                     void *user_data);
+
+void
+cogl_gst_video_player_stop (CoglGstVideoPlayer* player);
+
+void
+cogl_gst_video_player_reset (CoglGstVideoPlayer *player);
+
+void
+cogl_gst_video_player_pause (CoglGstVideoPlayer *player);
+
+void
+cogl_gst_video_player_resume (CoglGstVideoPlayer *player);
+
+void
+cogl_gst_video_player_seek (CoglGstVideoPlayer *player,
+                            int value);
+
+void
+cogl_gst_video_player_seek_absolute (CoglGstVideoPlayer *player,
+                                     uint64_t value);
+
+int64_t
+cogl_gst_video_player_get_progress (CoglGstVideoPlayer *player);
+
+int64_t
+cogl_gst_video_player_get_duration (CoglGstVideoPlayer *player);
+
+G_END_DECLS
+
+#endif
diff --git a/cogl-gst/cogl-gst-video-sink.c b/cogl-gst/cogl-gst-video-sink.c
new file mode 100644
index 0000000..84a118f
--- /dev/null
+++ b/cogl-gst/cogl-gst-video-sink.c
@@ -0,0 +1,926 @@
+/*
+ * Cogl-GStreamer.
+ *
+ * GStreamer integration library for Cogl.
+ *
+ * cogl-gst-video-sink.c - Gstreamer Video Sink that renders to a
+ *                         Cogl Pipeline.
+ *
+ * Authored by Jonathan Matthew  <jonathan at kaolin.wh9.net>,
+ *             Chris Lord        <chris at openedhand.com>
+ *             Damien Lespiau    <damien.lespiau at intel.com>
+ *             Matthew Allum     <mallum at openedhand.com>
+ *             Plamena Manolova  <plamena.n.manolova at intel.com>
+ *
+ * Copyright (C) 2007, 2008 OpenedHand
+ * Copyright (C) 2009, 2010, 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/gstvalue.h>
+#include <gst/video/video.h>
+#include <gst/riff/riff-ids.h>
+#include <cogl/cogl.h>
+#include <string.h>
+
+#include "cogl-gst-video-sink.h"
+#include "cogl-gst-shader.h"
+
+#define COGL_GST_TEXTURE_FLAGS \
+       (COGL_TEXTURE_NO_SLICING | COGL_TEXTURE_NO_ATLAS)
+#define PACKAGE "GStreamer"
+#define VERSION "0.10"
+#define COGL_GST_DEFAULT_PRIORITY    (G_PRIORITY_HIGH_IDLE)
+
+static GstStaticPadTemplate sinktemplate_all =
+       GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
+       GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") ";" \
+                        GST_VIDEO_CAPS_YUV ("YV12") ";" \
+                        GST_VIDEO_CAPS_YUV ("I420") ";" \
+                        GST_VIDEO_CAPS_RGBA         ";" \
+                        GST_VIDEO_CAPS_BGRA         ";" \
+                        GST_VIDEO_CAPS_RGB          ";" \
+                        GST_VIDEO_CAPS_BGR));
+
+static GstElementDetails cogl_gst_video_sink_details =
+       GST_ELEMENT_DETAILS ("Cogl video sink", "Sink/Video",
+       "Sends video data from a GStreamer pipeline to a Cogl pipeline",
+       "Jonathan Matthew <jonathan at kaolin.wh9.net>, "
+       "Matthew Allum <mallum at o-hand.com, "
+       "Chris Lord <chris at o-hand.com>, "
+       "Plamena Manolova <plamena.n.manolova at intel.com>");
+
+enum
+{
+  PROP_0,
+  PROP_UPDATE_PRIORITY
+};
+
+typedef enum
+{
+  COGL_GST_NOFORMAT,
+  COGL_GST_RGB32,
+  COGL_GST_RGB24,
+  COGL_GST_AYUV,
+  COGL_GST_YV12,
+  COGL_GST_I420,
+}CoglGstVideoFormat;
+
+typedef struct _CoglGstSource
+{
+  GSource source;
+  CoglGstVideoSink *sink;
+  GMutex buffer_lock;
+  GstBuffer *buffer;
+}CoglGstSource;
+
+typedef void (CoglGstRendererPaint) (CoglGstVideoSink*);
+typedef void (CoglGstRendererPostPaint) (CoglGstVideoSink*);
+
+typedef struct _CoglGstRenderer
+{
+  const char *name;
+  CoglGstVideoFormat format;
+  int flags;
+  GstStaticCaps caps;
+  void (*init)   (CoglGstVideoSink *sink);
+  void (*deinit)  (CoglGstVideoSink *sink);
+  void (*upload) (CoglGstVideoSink *sink,
+                  GstBuffer *buffer);
+}CoglGstRenderer;
+
+typedef enum _CoglGstRendererState
+{
+  COGL_GST_RENDERER_STOPPED,
+  COGL_GST_RENDERER_RUNNING,
+  COGL_GST_RENDERER_NEED_GC,
+}CoglGstRendererState;
+
+struct _CoglGstVideoSinkPrivate
+{
+  CoglContext *ctx;
+  CoglPipeline *pipeline;
+  CoglGstVideoFormat format;
+  CoglBool bgr;
+  int width;
+  int height;
+  int fps_n, fps_d;
+  int par_n, par_d;
+  int free_layer;
+  CoglGstSource *source;
+  GSList *renderers;
+  GstCaps *caps;
+  CoglGstRenderer *renderer;
+  CoglGstRendererState renderer_state;
+  GMainContext *g_ctx;
+  GMainLoop *loop;
+  CoglSnippetHook hook;
+};
+
+
+GST_BOILERPLATE (CoglGstVideoSink,
+                 cogl_gst_video_sink,
+                 GstBaseSink,
+                 GST_TYPE_BASE_SINK
+                 );
+
+static void
+cogl_gst_source_finalize (GSource *source)
+{
+  CoglGstSource *gst_source = (CoglGstSource*) source;
+
+  g_mutex_lock (&gst_source->buffer_lock);
+  if (gst_source->buffer)
+    gst_buffer_unref (gst_source->buffer);
+  gst_source->buffer = NULL;
+  g_mutex_unlock (&gst_source->buffer_lock);
+  g_mutex_clear (&gst_source->buffer_lock);
+}
+
+static void
+cogl_gst_source_push (CoglGstSource *gst_source,
+                      GstBuffer *buffer)
+{
+  CoglGstVideoSinkPrivate *priv = gst_source->sink->priv;
+  g_mutex_lock (&gst_source->buffer_lock);
+  if (gst_source->buffer)
+    gst_buffer_unref (gst_source->buffer);
+  gst_source->buffer = gst_buffer_ref (buffer);
+  g_mutex_unlock (&gst_source->buffer_lock);
+
+  g_main_context_wakeup (priv->g_ctx);
+}
+
+
+void
+cogl_gst_video_sink_set_context (CoglGstVideoSink *vt, CoglContext *ctx)
+{
+  vt->priv->ctx = ctx;
+}
+
+void
+cogl_gst_set_shader_hook (CoglGstVideoSink *sink, CoglSnippetHook hook)
+{
+  sink->priv->hook = hook;
+}
+
+
+CoglPipeline*
+cogl_gst_video_sink_get_pipeline (CoglGstVideoSink *vt)
+{
+  return vt->priv->pipeline;
+}
+
+GMainLoop*
+cogl_gst_video_sink_get_main_loop (CoglGstVideoSink *sink)
+{
+  return sink->priv->loop;
+}
+
+int
+cogl_gst_video_sink_get_free_layer (CoglGstVideoSink* sink)
+{
+  return sink->priv->free_layer;
+}
+
+static CoglBool
+cogl_gst_source_prepare (GSource *source,
+                         int *timeout)
+{
+  CoglGstSource *gst_source = (CoglGstSource*) source;
+
+  *timeout = -1;
+
+  return gst_source->buffer != NULL;
+}
+
+static CoglBool
+cogl_gst_source_check (GSource *source)
+{
+  CoglGstSource *gst_source = (CoglGstSource*) source;
+
+  return gst_source->buffer != NULL;
+}
+
+static CoglBool
+cogl_gst_source_dispatch (GSource *source,
+                          GSourceFunc callback,
+                          void* user_data)
+{
+  CoglGstSource *gst_source= (CoglGstSource*) source;
+  CoglGstVideoSinkPrivate *priv = gst_source->sink->priv;
+  GstBuffer *buffer;
+
+  if (G_UNLIKELY (priv->renderer_state == COGL_GST_RENDERER_NEED_GC))
+    {
+      priv->renderer->deinit (gst_source->sink);
+      priv->renderer_state = COGL_GST_RENDERER_STOPPED;
+    }
+  if (G_UNLIKELY (priv->renderer_state == COGL_GST_RENDERER_STOPPED))
+    {
+      priv->renderer->init (gst_source->sink);
+      priv->renderer_state = COGL_GST_RENDERER_RUNNING;
+    }
+
+  g_mutex_lock (&gst_source->buffer_lock);
+  buffer = gst_source->buffer;
+  gst_source->buffer = NULL;
+  g_mutex_unlock (&gst_source->buffer_lock);
+
+  if (buffer)
+    {
+      priv->renderer->upload (gst_source->sink, buffer);
+      gst_buffer_unref (buffer);
+    }
+
+  return TRUE;
+}
+
+static GSourceFuncs gst_source_funcs =
+{
+  cogl_gst_source_prepare,
+  cogl_gst_source_check,
+  cogl_gst_source_dispatch,
+  cogl_gst_source_finalize
+};
+
+static CoglGstSource*
+cogl_gst_source_new (CoglGstVideoSink *sink)
+{
+  GSource *source;
+  CoglGstSource *gst_source;
+
+  source = g_source_new (&gst_source_funcs, sizeof (CoglGstSource));
+  gst_source = (CoglGstSource*) source;
+
+  g_source_set_can_recurse (source, TRUE);
+  g_source_set_priority (source, COGL_GST_DEFAULT_PRIORITY);
+
+  gst_source->sink = sink;
+  g_mutex_init (&gst_source->buffer_lock);
+  gst_source->buffer = NULL;
+
+  return gst_source;
+}
+
+static void
+cogl_gst_video_sink_set_priority (CoglGstVideoSink *sink,
+                                  int priority)
+{
+  g_source_set_priority ((GSource*) sink->priv->source, priority);
+}
+
+static void
+create_template_pipeline (CoglGstVideoSink *sink,
+                          const char *decl,
+                          const char *post,
+                          CoglBool set_uniforms,
+                          int n_layers)
+{
+  CoglGstVideoSinkPrivate *priv = sink->priv;
+  priv->free_layer = 1;
+
+  if (priv->pipeline)
+    {
+      CoglPipeline *pln = cogl_pipeline_copy (priv->pipeline);
+      cogl_object_unref (priv->pipeline);
+      priv->pipeline = pln;
+    }
+  else
+    priv->pipeline = cogl_pipeline_new (priv->ctx);
+
+    if (decl && post)
+      {
+        CoglSnippet *snippet = cogl_snippet_new (priv->hook, decl, post);
+        cogl_pipeline_add_snippet (priv->pipeline, snippet);
+        cogl_object_unref (snippet);
+      }
+
+    if (set_uniforms)
+      {
+        unsigned int location;
+        location = cogl_pipeline_get_uniform_location (priv->pipeline,
+                                                             "ytex");
+        cogl_pipeline_set_uniform_1i (priv->pipeline, location, 0);
+
+        if (n_layers > 1)
+          {
+            location = cogl_pipeline_get_uniform_location (priv->pipeline,
+                                                                 "utex");
+            cogl_pipeline_set_uniform_1i (priv->pipeline, location, 1);
+            priv->free_layer++;
+          }
+
+        if (n_layers > 2)
+          {
+            location = cogl_pipeline_get_uniform_location (priv->pipeline,
+                                                             "vtex");
+            cogl_pipeline_set_uniform_1i (priv->pipeline, location, 2);
+            priv->free_layer++;
+          }
+      }
+
+  g_signal_emit_by_name (sink, "cogl-pipeline-ready", 0);
+}
+
+static void
+create_paint_pipeline (CoglGstVideoSink *sink,
+                       CoglTexture *tex0,
+                       CoglTexture *tex1,
+                       CoglTexture *tex2)
+{
+  CoglGstVideoSinkPrivate *priv = sink->priv;
+
+  CoglPipeline *pln = cogl_pipeline_copy (priv->pipeline);
+  cogl_object_unref (priv->pipeline);
+  priv->pipeline = pln;
+
+  if (tex0 != NULL)
+    {
+      cogl_pipeline_set_layer_texture (priv->pipeline, 0, tex0);
+      cogl_object_unref (tex0);
+    }
+  if (tex1 != NULL)
+    {
+      cogl_pipeline_set_layer_texture (priv->pipeline, 1, tex1);
+      cogl_object_unref (tex1);
+    }
+  if (tex2 != NULL)
+    {
+      cogl_pipeline_set_layer_texture (priv->pipeline, 2, tex2);
+      cogl_object_unref (tex2);
+    }
+}
+
+static void
+cogl_gst_dummy_deinit (CoglGstVideoSink *sink)
+{
+}
+
+static void
+cogl_gst_rgb_init (CoglGstVideoSink *sink)
+{
+  create_template_pipeline (sink, NULL, NULL, FALSE, 1);
+}
+
+static void
+cogl_gst_rgb24_upload (CoglGstVideoSink *sink,
+                       GstBuffer *buffer)
+{
+  CoglGstVideoSinkPrivate *priv = sink->priv;
+  CoglPixelFormat format;
+  CoglTexture *tex;
+
+  if (priv->bgr)
+    format = COGL_PIXEL_FORMAT_BGR_888;
+  else
+    format = COGL_PIXEL_FORMAT_RGB_888;
+
+  tex = cogl_texture_new_from_data (priv->ctx, priv->width, priv->height,
+                                    COGL_GST_TEXTURE_FLAGS, format, format,
+                                    GST_ROUND_UP_4 (3 * priv->width),
+                                    GST_BUFFER_DATA (buffer), NULL);
+
+  create_paint_pipeline (sink, tex, NULL, NULL);
+}
+
+
+static CoglGstRenderer rgb24_renderer =
+{
+  "RGB 24",
+  COGL_GST_RGB24,
+  0,
+  GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB ";" GST_VIDEO_CAPS_BGR),
+  cogl_gst_rgb_init,
+  cogl_gst_dummy_deinit,
+  cogl_gst_rgb24_upload,
+};
+
+static void
+cogl_gst_rgb32_upload (CoglGstVideoSink *sink,
+                       GstBuffer *buffer)
+{
+  CoglGstVideoSinkPrivate *priv = sink->priv;
+  CoglPixelFormat format;
+  CoglTexture *tex;
+
+  if (priv->bgr)
+    format = COGL_PIXEL_FORMAT_BGRA_8888;
+  else
+    format = COGL_PIXEL_FORMAT_RGBA_8888;
+
+  tex = cogl_texture_new_from_data (priv->ctx, priv->width, priv->height,
+                                    COGL_GST_TEXTURE_FLAGS, format, format,
+                                    GST_ROUND_UP_4 (4 * priv->width),
+                                    GST_BUFFER_DATA (buffer), NULL);
+
+  create_paint_pipeline (sink, tex, NULL, NULL);
+}
+
+static CoglGstRenderer rgb32_renderer =
+{
+  "RGB 32",
+  COGL_GST_RGB32,
+  0,
+  GST_STATIC_CAPS (GST_VIDEO_CAPS_RGBA ";" GST_VIDEO_CAPS_BGRA),
+  cogl_gst_rgb_init,
+  cogl_gst_dummy_deinit,
+  cogl_gst_rgb32_upload,
+};
+
+static void
+cogl_gst_yv12_upload (CoglGstVideoSink *sink,
+                      GstBuffer *buffer)
+{
+  CoglGstVideoSinkPrivate *priv = sink->priv;
+  int y_row_stride = GST_ROUND_UP_4 (priv->width);
+  int uv_row_stride = GST_ROUND_UP_4 (priv->width / 2);
+  CoglTexture *y_tex, *u_tex, *v_tex;
+
+  CoglPixelFormat format = COGL_PIXEL_FORMAT_G_8;
+
+  y_tex = cogl_texture_new_from_data (priv->ctx, priv->width, priv->height,
+                                      COGL_GST_TEXTURE_FLAGS, format, format,
+                                      y_row_stride, GST_BUFFER_DATA (buffer),
+                                      NULL);
+
+  u_tex = cogl_texture_new_from_data (priv->ctx, priv->width / 2,
+                                      priv->height / 2, COGL_GST_TEXTURE_FLAGS,
+                                      format, format, uv_row_stride,
+                                      GST_BUFFER_DATA (buffer) +
+                                      (y_row_stride * priv->height), NULL);
+
+  v_tex = cogl_texture_new_from_data (priv->ctx, priv->width / 2,
+                                      priv->height / 2, COGL_GST_TEXTURE_FLAGS,
+                                      format, format, uv_row_stride,
+                                      GST_BUFFER_DATA (buffer) +
+                                      (y_row_stride * priv->height) +
+                                      (uv_row_stride * priv->height / 2), NULL);
+
+  create_paint_pipeline (sink, y_tex, u_tex, v_tex);
+}
+
+static void
+cogl_gst_yv12_glsl_init (CoglGstVideoSink *sink)
+{
+  create_template_pipeline (sink,
+                            _cogl_gst_shader_yv12_to_rgba_decl,
+                            _cogl_gst_shader_default_post,
+                            TRUE,
+                            3);
+}
+
+static CoglGstRenderer yv12_glsl_renderer =
+{
+  "YV12 glsl",
+  COGL_GST_YV12,
+  0,
+  GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("YV12")),
+  cogl_gst_yv12_glsl_init,
+  cogl_gst_dummy_deinit,
+  cogl_gst_yv12_upload,
+};
+
+static void
+cogl_gst_i420_glsl_init (CoglGstVideoSink *sink)
+{
+  create_template_pipeline (sink,
+                            _cogl_gst_shader_yv12_to_rgba_decl,
+                            _cogl_gst_shader_default_post,
+                            TRUE,
+                            3);
+}
+
+static CoglGstRenderer i420_glsl_renderer =
+{
+  "I420 glsl",
+  COGL_GST_I420,
+  0,
+  GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420")),
+  cogl_gst_i420_glsl_init,
+  cogl_gst_dummy_deinit,
+  cogl_gst_yv12_upload,
+};
+
+static void
+cogl_gst_ayuv_glsl_init (CoglGstVideoSink *sink)
+{
+  create_template_pipeline (sink,
+                            _cogl_gst_shader_ayuv_to_rgba_decl,
+                            _cogl_gst_shader_default_post,
+                            TRUE,
+                            1);
+}
+
+static void
+cogl_gst_ayuv_upload (CoglGstVideoSink *sink,
+                      GstBuffer *buffer)
+{
+  CoglGstVideoSinkPrivate *priv = sink->priv;
+  CoglPixelFormat format = COGL_PIXEL_FORMAT_RGBA_8888;
+  CoglTexture *tex;
+
+  tex = cogl_texture_new_from_data (priv->ctx, priv->width, priv->height,
+                                    COGL_GST_TEXTURE_FLAGS, format, format,
+                                    GST_ROUND_UP_4 (4 * priv->width),
+                                    GST_BUFFER_DATA (buffer), NULL);
+
+  create_paint_pipeline (sink, tex, NULL, NULL);
+}
+
+static CoglGstRenderer ayuv_glsl_renderer =
+{
+  "AYUV glsl",
+  COGL_GST_AYUV,
+  0,
+  GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV")),
+  cogl_gst_ayuv_glsl_init,
+  cogl_gst_dummy_deinit,
+  cogl_gst_ayuv_upload,
+};
+
+static GSList*
+cogl_gst_build_renderers_list (void)
+{
+  GSList *list = NULL;
+  int i;
+
+  CoglGstRenderer *renderers[] =
+  {
+    &rgb24_renderer,
+    &rgb32_renderer,
+    &yv12_glsl_renderer,
+    &i420_glsl_renderer,
+    &ayuv_glsl_renderer,
+    NULL
+  };
+
+  for (i = 0; i < 5; i++)
+    list = g_slist_prepend (list, renderers[i]);
+
+  return list;
+}
+
+static void
+append_cap (gpointer data,
+            gpointer user_data)
+{
+  CoglGstRenderer *renderer = (CoglGstRenderer*) data;
+  GstCaps *caps = (GstCaps*) user_data;
+  GstCaps *writable_caps;
+
+  writable_caps =
+    gst_caps_make_writable (gst_static_caps_get (&renderer->caps));
+  gst_caps_append (caps, writable_caps);
+}
+
+static GstCaps*
+cogl_gst_build_caps (GSList *renderers)
+{
+  GstCaps *caps;
+
+  caps = gst_caps_new_empty ();
+
+  g_slist_foreach (renderers, append_cap, caps);
+
+  return caps;
+}
+
+static CoglGstRenderer*
+cogl_gst_find_renderer_by_format (CoglGstVideoSink *sink,
+                                  CoglGstVideoFormat format)
+{
+  CoglGstVideoSinkPrivate *priv = sink->priv;
+  CoglGstRenderer *renderer = NULL;
+  GSList *element;
+
+  for (element = priv->renderers; element; element = g_slist_next (element))
+    {
+      CoglGstRenderer *candidate = (CoglGstRenderer*) element->data;
+      if (candidate->format == format)
+        {
+          renderer = candidate;
+          break;
+        }
+    }
+
+  return renderer;
+}
+
+static void
+cogl_gst_video_sink_base_init (void *g_class)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+  gst_element_class_add_pad_template (element_class,
+                               gst_static_pad_template_get (&sinktemplate_all));
+  gst_element_class_set_details (element_class, &cogl_gst_video_sink_details);
+
+}
+
+
+static void
+cogl_gst_video_sink_init (CoglGstVideoSink *sink,
+                          CoglGstVideoSinkClass *klass)
+{
+  CoglGstVideoSinkPrivate* priv;
+
+  sink->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (sink,
+                                                   COGL_GST_TYPE_VIDEO_SINK,
+                                                   CoglGstVideoSinkPrivate);
+
+  sink->priv->loop = g_main_loop_new (NULL, TRUE);
+  sink->priv->g_ctx = g_main_loop_get_context (sink->priv->loop);
+
+  priv->renderers = cogl_gst_build_renderers_list ();
+  priv->caps = cogl_gst_build_caps (priv->renderers);
+  priv->renderer_state = COGL_GST_RENDERER_STOPPED;
+  priv->hook = COGL_SNIPPET_HOOK_FRAGMENT;
+}
+
+static GstFlowReturn
+_cogl_gst_video_sink_render (GstBaseSink *bsink,
+                             GstBuffer *buffer)
+{
+  CoglGstVideoSink *sink = COGL_GST_VIDEO_SINK (bsink);
+  cogl_gst_source_push (sink->priv->source, buffer);
+
+  return GST_FLOW_OK;
+}
+
+static GstCaps*
+cogl_gst_video_sink_get_caps (GstBaseSink *bsink)
+{
+  CoglGstVideoSink *sink;
+  sink = COGL_GST_VIDEO_SINK (bsink);
+  return gst_caps_ref (sink->priv->caps);
+}
+
+static CoglBool
+cogl_gst_video_sink_set_caps (GstBaseSink *bsink,
+                              GstCaps *caps)
+{
+  CoglGstVideoSink *sink;
+  CoglGstVideoSinkPrivate *priv;
+  GstCaps *intersection;
+  GstStructure *structure;
+  CoglBool ret;
+  const GValue *fps;
+  const GValue *par;
+  int width, height;
+  uint32_t fourcc;
+  int red_mask, blue_mask;
+
+  sink = COGL_GST_VIDEO_SINK (bsink);
+  priv = sink->priv;
+
+  intersection = gst_caps_intersect (priv->caps, caps);
+  if (gst_caps_is_empty (intersection))
+    return FALSE;
+
+  gst_caps_unref (intersection);
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  ret = gst_structure_get_int (structure, "width", &width);
+  ret &= gst_structure_get_int (structure, "height", &height);
+  fps = gst_structure_get_value (structure, "framerate");
+  ret &= (fps != NULL);
+
+  par = gst_structure_get_value (structure, "pixel-aspect-ratio");
+
+  if (!ret)
+    return FALSE;
+
+  priv->width = width;
+  priv->height = height;
+
+  priv->fps_n = gst_value_get_fraction_numerator (fps);
+  priv->fps_d = gst_value_get_fraction_denominator (fps);
+
+  if (par)
+    {
+      priv->par_n = gst_value_get_fraction_numerator (par);
+      priv->par_d = gst_value_get_fraction_denominator (par);
+    }
+  else
+    priv->par_n = priv->par_d = 1;
+
+  ret = gst_structure_get_fourcc (structure, "format", &fourcc);
+  if (ret && (fourcc == GST_MAKE_FOURCC ('Y', 'V', '1', '2')))
+    priv->format = COGL_GST_YV12;
+  else if (ret && (fourcc == GST_MAKE_FOURCC ('I', '4', '2', '0')))
+    priv->format = COGL_GST_I420;
+  else if (ret && (fourcc == GST_MAKE_FOURCC ('A', 'Y', 'U', 'V')))
+    {
+      priv->format = COGL_GST_AYUV;
+      priv->bgr = FALSE;
+    }
+  else
+    {
+      guint32 mask;
+      gst_structure_get_int (structure, "red_mask", &red_mask);
+      gst_structure_get_int (structure, "blue_mask", &blue_mask);
+
+      mask = red_mask | blue_mask;
+
+      if (mask < 0x1000000)
+        {
+          priv->format = COGL_GST_RGB24;
+          priv->bgr = (red_mask == 0xff0000) ? FALSE : TRUE;
+        }
+      else
+        {
+          priv->format = COGL_GST_RGB32;
+          priv->bgr = (red_mask == 0xff000000) ? FALSE : TRUE;
+        }
+    }
+
+  priv->renderer = cogl_gst_find_renderer_by_format (sink, priv->format);
+  if (priv->renderer == NULL)
+    {
+      GST_ERROR_OBJECT (sink, "Could not find suitable renderer");
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+static void
+cogl_gst_video_sink_dispose (GObject *object)
+{
+  CoglGstVideoSink *self;
+  CoglGstVideoSinkPrivate *priv;
+
+  self = COGL_GST_VIDEO_SINK (object);
+  priv = self->priv;
+
+  if (priv->renderer_state == COGL_GST_RENDERER_RUNNING ||
+      priv->renderer_state == COGL_GST_RENDERER_NEED_GC)
+    {
+      priv->renderer->deinit (self);
+      priv->renderer_state = COGL_GST_RENDERER_STOPPED;
+    }
+
+  if (priv->pipeline)
+    {
+      cogl_object_unref (priv->pipeline);
+      priv->pipeline = NULL;
+    }
+
+  if (priv->caps)
+    {
+      gst_caps_unref (priv->caps);
+      priv->caps = NULL;
+    }
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+cogl_gst_video_sink_finalize (GObject *object)
+{
+  CoglGstVideoSink *self;
+  CoglGstVideoSinkPrivate *priv;
+
+  self = COGL_GST_VIDEO_SINK (object);
+  priv = self->priv;
+
+  g_slist_free (priv->renderers);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static CoglBool
+cogl_gst_video_sink_start (GstBaseSink *base_sink)
+{
+  CoglGstVideoSink *sink = COGL_GST_VIDEO_SINK (base_sink);
+  CoglGstVideoSinkPrivate *priv = sink->priv;
+
+  priv->source = cogl_gst_source_new (sink);
+  g_source_attach ((GSource*) priv->source, priv->g_ctx);
+  return TRUE;
+}
+
+static void
+cogl_gst_video_sink_set_property (GObject *object,
+                                  guint prop_id,
+                                  const GValue *value,
+                                  GParamSpec *pspec)
+{
+  CoglGstVideoSink *sink = COGL_GST_VIDEO_SINK (object);
+
+  switch (prop_id)
+    {
+    case PROP_UPDATE_PRIORITY:
+      cogl_gst_video_sink_set_priority (sink, g_value_get_int (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+cogl_gst_video_sink_get_property (GObject *object,
+                                  guint prop_id,
+                                  GValue *value,
+                                  GParamSpec *pspec)
+{
+  CoglGstVideoSink *sink = COGL_GST_VIDEO_SINK (object);
+  CoglGstVideoSinkPrivate *priv = sink->priv;
+
+  switch (prop_id)
+    {
+    case PROP_UPDATE_PRIORITY:
+      g_value_set_int (value, g_source_get_priority ((GSource*) priv->source));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static CoglBool
+cogl_gst_video_sink_stop (GstBaseSink *base_sink)
+{
+  CoglGstVideoSink *sink = COGL_GST_VIDEO_SINK (base_sink);
+  CoglGstVideoSinkPrivate *priv = sink->priv;
+
+  if (priv->source)
+    {
+      GSource *source = (GSource*) priv->source;
+      g_source_destroy (source);
+      g_source_unref (source);
+      priv->source = NULL;
+    }
+
+  priv->renderer_state = COGL_GST_RENDERER_STOPPED;
+
+  return TRUE;
+}
+
+static void
+cogl_gst_video_sink_class_init (CoglGstVideoSinkClass *klass)
+{
+  GObjectClass *go_class = G_OBJECT_CLASS (klass);
+  GstBaseSinkClass *gb_class = GST_BASE_SINK_CLASS (klass);
+  GParamSpec *pspec;
+
+  g_type_class_add_private (klass, sizeof (CoglGstVideoSinkPrivate));
+  go_class->set_property = cogl_gst_video_sink_set_property;
+  go_class->get_property = cogl_gst_video_sink_get_property;
+  go_class->dispose = cogl_gst_video_sink_dispose;
+  go_class->finalize = cogl_gst_video_sink_finalize;
+  gb_class->render = _cogl_gst_video_sink_render;
+  gb_class->preroll = _cogl_gst_video_sink_render;
+  gb_class->start = cogl_gst_video_sink_start;
+  gb_class->stop = cogl_gst_video_sink_stop;
+  gb_class->set_caps = cogl_gst_video_sink_set_caps;
+  gb_class->get_caps = cogl_gst_video_sink_get_caps;
+
+  pspec = g_param_spec_int ("update-priority",
+                            "Update Priority",
+                            "Priority of video updates in the thread",
+                            -G_MAXINT, G_MAXINT,
+                            COGL_GST_DEFAULT_PRIORITY,
+                            COGL_GST_PARAM_READWRITE);
+
+  g_object_class_install_property (go_class, PROP_UPDATE_PRIORITY, pspec);
+
+  g_signal_new ("cogl-pipeline-ready", COGL_GST_TYPE_VIDEO_SINK,
+                G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID,
+                G_TYPE_NONE, 0, G_TYPE_NONE);
+
+}
+
+static CoglBool
+plugin_init (GstPlugin *plugin)
+{
+  CoglBool ret = gst_element_register (plugin, "coglsink", GST_RANK_PRIMARY,
+                                       COGL_GST_TYPE_VIDEO_SINK);
+
+  return ret;
+}
+
+GST_PLUGIN_DEFINE_STATIC (GST_VERSION_MAJOR, GST_VERSION_MINOR, "coglsink",
+                          "Element to attach frames to cogl pipelines",
+                          plugin_init, VERSION, "LGPL", PACKAGE, "...");
diff --git a/cogl-gst/cogl-gst-video-sink.h b/cogl-gst/cogl-gst-video-sink.h
new file mode 100644
index 0000000..d3d9580
--- /dev/null
+++ b/cogl-gst/cogl-gst-video-sink.h
@@ -0,0 +1,112 @@
+/*
+ * Cogl-GStreamer.
+ *
+ * GStreamer integration library for Cogl.
+ *
+ * cogl-gst-video-sink.h - Gstreamer Video Sink that renders to a
+ *                         Cogl Pipeline.
+ *
+ * Authored by Jonathan Matthew  <jonathan at kaolin.wh9.net>,
+ *             Chris Lord        <chris at openedhand.com>
+ *             Damien Lespiau    <damien.lespiau at intel.com>
+ *             Matthew Allum     <mallum at openedhand.com>
+ *             Plamena Manolova  <plamena.n.manolova at intel.com>
+ *
+ * Copyright (C) 2007, 2008 OpenedHand
+ * Copyright (C) 2009, 2010, 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.
+ */
+
+#ifndef __COGL_GST_VIDEO_SINK_H__
+#define __COGL_GST_VIDEO_SINK_H__
+#include <glib-object.h>
+#include <gst/base/gstbasesink.h>
+#include <cogl/cogl.h>
+
+G_BEGIN_DECLS
+
+#define COGL_GST_TYPE_VIDEO_SINK cogl_gst_video_sink_get_type()
+
+#define COGL_GST_VIDEO_SINK(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  COGL_GST_TYPE_VIDEO_SINK, CoglGstVideoSink))
+
+#define COGL_GST_VIDEO_SINK_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  COGL_GST_TYPE_VIDEO_SINK, CoglGstVideoSinkClass))
+
+#define COGL_GST_IS_VIDEO_SINK(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  COGL_GST_TYPE_VIDEO_SINK))
+
+#define COGL_GST_IS_VIDEO_SINK_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  COGL_GST_TYPE_VIDEO_SINK))
+
+#define COGL_GST_VIDEO_SINK_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  COGL_GST_TYPE_VIDEO_SINK, CoglGstVideoSinkClass))
+
+#define COGL_GST_PARAM_STATIC        \
+  (G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)
+
+#define COGL_GST_PARAM_READABLE      \
+  (G_PARAM_READABLE | COGL_GST_PARAM_STATIC)
+
+#define COGL_GST_PARAM_WRITABLE      \
+  (G_PARAM_WRITABLE | COGL_GST_PARAM_STATIC)
+
+#define COGL_GST_PARAM_READWRITE     \
+  (G_PARAM_READABLE | G_PARAM_WRITABLE | COGL_GST_PARAM_STATIC)
+
+typedef struct _CoglGstVideoSink CoglGstVideoSink;
+typedef struct _CoglGstVideoSinkClass CoglGstVideoSinkClass;
+typedef struct _CoglGstVideoSinkPrivate CoglGstVideoSinkPrivate;
+
+struct _CoglGstVideoSink
+{
+  GstBaseSink parent;
+  CoglGstVideoSinkPrivate *priv;
+};
+
+struct _CoglGstVideoSinkClass
+{
+  GstBaseSinkClass parent_class;
+};
+
+GType       cogl_gst_video_sink_get_type    (void) G_GNUC_CONST;
+
+CoglPipeline*
+cogl_gst_video_sink_get_pipeline (CoglGstVideoSink *vt);
+
+void
+cogl_gst_video_sink_set_context (CoglGstVideoSink *vt,
+                                 CoglContext *ctx);
+
+GMainLoop*
+cogl_gst_video_sink_get_main_loop (CoglGstVideoSink *loop);
+
+void
+cogl_gst_set_shader_hook (CoglGstVideoSink *sink,
+                          CoglSnippetHook hook);
+
+int
+cogl_gst_video_sink_get_free_layer (CoglGstVideoSink *sink);
+
+G_END_DECLS
+
+#endif
diff --git a/cogl-gst/cogl-gst.h b/cogl-gst/cogl-gst.h
new file mode 100644
index 0000000..c9588d7
--- /dev/null
+++ b/cogl-gst/cogl-gst.h
@@ -0,0 +1,40 @@
+/*
+ * Cogl-GStreamer.
+ *
+ * GStreamer integration library for Cogl.
+ *
+ * cogl-gst.h - Top level header file
+ *
+ * Authored by Jonathan Matthew  <jonathan at kaolin.wh9.net>,
+ *             Chris Lord        <chris at openedhand.com>
+ *             Damien Lespiau    <damien.lespiau at intel.com>
+ *             Matthew Allum     <mallum at openedhand.com>
+ *             Plamena Manolova  <plamena.n.manolova at intel.com>
+ *
+ * Copyright (C) 2007, 2008 OpenedHand
+ * Copyright (C) 2009, 2010, 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.
+ */
+
+#ifndef __COGL_GST_H__
+#define __COGL_GST_H__
+
+#include <cogl-gst/cogl-gst-util.h>
+#include <cogl-gst/cogl-gst-video-sink.h>
+#include <cogl-gst/cogl-gst-video-player.h>
+
+#endif
diff --git a/cogl-gst/cogl-gst.pc.in b/cogl-gst/cogl-gst.pc.in
new file mode 100644
index 0000000..5333303
--- /dev/null
+++ b/cogl-gst/cogl-gst.pc.in
@@ -0,0 +1,13 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+apiversion=@COGL_API_VERSION@
+requires=@COGL_PKG_REQUIRES@ @COGL_GST_PKG_REQUIRES@
+
+Name: Cogl
+Description: An gstreamer integration library for Cogl
+Version: @COGL_VERSION@
+Libs: -L${libdir} -lcogl-gst
+Cflags: -I${includedir}/cogl -DCOGL_ENABLE_EXPERIMENTAL_2_0_API
+Requires: ${requires}
diff --git a/configure.ac b/configure.ac
index 418eed3..2404545 100644
--- a/configure.ac
+++ b/configure.ac
@@ -428,6 +428,30 @@ AS_IF([test "x$enable_cogl_pango" = "xyes"],
 )
 
 dnl     ============================================================
+dnl     Should cogl-gst be built?
+dnl     ============================================================
+
+AS_IF([test "x$enable_glib" != "xyes"],
+      [
+        AS_IF([test "x$enable_cogl_gst" = "xyes"],
+              AC_MSG_ERROR([--enable-cogl-gst conflicts with --disable-glib]))
+        enable_cogl_gst=no
+      ]
+)
+
+AC_ARG_ENABLE(
+  [cogl-gst],
+  [AC_HELP_STRING([--enable-cogl-gst=@<:@no/yes@:>@], [Enable gstreamer support @<:@default=no@:>@])],
+  [],
+  enable_cogl_gst=no
+)
+AS_IF([test "x$enable_cogl_gst" = "xyes"],
+      [
+  COGL_GST_PKG_REQUIRES="$COGL_GST_PKG_REQUIRES gstreamer-0.10 >= 0.10 gstreamer-fft-0.10 >= 0.10 gstreamer-interfaces-0.10 >= 0.10 gstreamer-base-0.10 >= 0.10"
+      ]
+)
+
+dnl     ============================================================
 dnl     Choose image loading backend
 dnl     ============================================================
 AC_ARG_ENABLE(
@@ -1134,6 +1158,13 @@ AS_IF([test "x$enable_cogl_pango" = "xyes"],
 )
 AM_CONDITIONAL([BUILD_COGL_PANGO], [test "x$enable_cogl_pango" = "xyes"])
 
+AC_SUBST(COGL_GST_PKG_REQUIRES)
+
+AS_IF([test "x$enable_cogl_gst" = "xyes"],
+  [PKG_CHECK_MODULES(COGL_GST_DEP, [$COGL_GST_PKG_REQUIRES])]
+)
+AM_CONDITIONAL([BUILD_COGL_GST], [test "x$enable_cogl_gst" = "xyes"])
+
 
 dnl ================================================================
 dnl Misc program dependencies.
@@ -1243,6 +1274,8 @@ AC_SUBST(COGL_DEP_CFLAGS)
 AC_SUBST(COGL_DEP_LIBS)
 AC_SUBST(COGL_PANGO_DEP_CFLAGS)
 AC_SUBST(COGL_PANGO_DEP_LIBS)
+AC_SUBST(COGL_GST_DEP_CFLAGS)
+AC_SUBST(COGL_GST_DEP_LIBS)
 AC_SUBST(COGL_EXTRA_CFLAGS)
 AC_SUBST(COGL_EXTRA_LDFLAGS)
 
@@ -1273,6 +1306,8 @@ cogl/cogl.rc
 cogl-pango/Makefile
 cogl-pango/cogl-pango2.pc
 cogl-pango/cogl-pango.rc
+cogl-gst/Makefile
+cogl-gst/cogl-gst.pc
 cogl-gles2/Makefile
 cogl-gles2/cogl-gles2-experimental.pc
 doc/Makefile
@@ -1325,6 +1360,7 @@ echo "        Build libcogl-gles2 GLES 2.0 frontend api: ${enable_cogl_gles2}"
 echo "        Image backend: ${COGL_IMAGE_BACKEND}"
 echo "        Cogl Pango: ${enable_cogl_pango}"
 echo "        Profiling: ${enable_profile}"
+echo "        Cogl Gst: ${enable_cogl_gst}"
 
 # Compiler/Debug related flags
 echo ""
diff --git a/examples/Makefile.am b/examples/Makefile.am
index e715973..2b30de1 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -48,6 +48,13 @@ cogl_crate_CFLAGS = $(AM_CFLAGS) $(COGL_PANGO_DEP_CFLAGS)
 examples_data_DATA += crate.jpg
 endif
 
+if BUILD_COGL_GST
+programs += cogl-basic-video-player
+cogl_basic_video_player_SOURCES = cogl-basic-video-player.c
+cogl_basic_video_player_LDADD = $(common_ldadd) $(COGL_GST_DEP_LIBS) $(top_builddir)/cogl-gst/libcogl-gst.la
+cogl_basic_video_player_CFLAGS = $(AM_CFLAGS) $(COGL_GST_DEP_CFLAGS) -I$(top_builddir)/cogl-gst
+endif
+
 if X11_TESTS
 programs += cogl-x11-foreign cogl-x11-tfp
 cogl_x11_foreign_SOURCES = cogl-x11-foreign.c
diff --git a/examples/cogl-basic-video-player.c b/examples/cogl-basic-video-player.c
new file mode 100644
index 0000000..0de6430
--- /dev/null
+++ b/examples/cogl-basic-video-player.c
@@ -0,0 +1,162 @@
+#include <cogl/cogl.h>
+#include <cogl-gst/cogl-gst.h>
+
+typedef struct _Data
+{
+  CoglFramebuffer *fb;
+  CoglPipeline *pln;
+  CoglGstVideoSink *sink;
+  CoglBool draw_ready;
+}Data;
+
+static CoglBool
+_bus_watch (GstBus *bus,
+            GstMessage *msg,
+            void *user_data)
+{
+  Data *data = (Data*) user_data;
+  switch (GST_MESSAGE_TYPE (msg))
+    {
+      case GST_MESSAGE_EOS:
+        {
+          g_main_loop_quit (cogl_gst_video_sink_get_main_loop (data->sink));
+          break;
+        }
+      case GST_MESSAGE_ERROR:
+        {
+          char *debug;
+          GError *error = NULL;
+
+          gst_message_parse_error (msg, &error, &debug);
+          g_free (debug);
+
+          if (error != NULL)
+            {
+              g_error ("Playback error: %s\n", error->message);
+              g_error_free (error);
+            }
+          g_main_loop_quit (cogl_gst_video_sink_get_main_loop (data->sink));
+          break;
+        }
+      default:
+        break;
+    }
+
+  return TRUE;
+}
+
+static void
+_frame_callback (CoglOnscreen *onscreen,
+                 CoglFrameEvent event,
+                 CoglFrameInfo *info,
+                 void *user_data)
+{
+  Data *data = user_data;
+
+  if (event == COGL_FRAME_EVENT_SYNC)
+    data->draw_ready = TRUE;
+}
+
+static CoglBool
+_draw (void *user_data)
+{
+  Data *data = (Data*) user_data;
+  CoglPipeline* current = cogl_gst_video_sink_get_pipeline (data->sink);
+
+/*
+ * This checks whether the system compositor is ready to render and that
+ * sink has retrieved a new frame (the cogl sink creates a new cogl pipeline
+ * (by copying the previous one) for each frame so checking whether the
+ * pipeline has changed is a way of querying whether there is a new frame to
+ * render).
+ */
+
+  if (data->draw_ready && current != data->pln && current)
+    {
+      cogl_framebuffer_clear4f (data->fb,
+                                COGL_BUFFER_BIT_COLOR|COGL_BUFFER_BIT_DEPTH, 0,
+                                0, 0, 1);
+      data->pln = current;
+
+      cogl_framebuffer_push_matrix (data->fb);
+      cogl_framebuffer_translate (data->fb, 640 / 2, 480 / 2, 0);
+      cogl_framebuffer_draw_textured_rectangle (data->fb, data->pln, -320, -240,
+                                                320, 240, 0, 0, 1, 1);
+      cogl_framebuffer_pop_matrix (data->fb);
+
+      cogl_onscreen_swap_buffers (COGL_ONSCREEN (data->fb));
+    }
+
+  return TRUE;
+}
+
+static void
+_set_up_pipeline (gpointer instance,
+                  gpointer user_data)
+{
+  Data* data = (Data*) user_data;
+  int free_layer = cogl_gst_video_sink_get_free_layer (data->sink);
+  data->pln = cogl_gst_video_sink_get_pipeline (data->sink);
+
+  while (free_layer > 0)
+    {
+      free_layer--;
+      cogl_pipeline_set_layer_filters (data->pln, free_layer,
+                                       COGL_PIPELINE_FILTER_LINEAR_MIPMAP_LINEAR,
+                                       COGL_PIPELINE_FILTER_LINEAR);
+    }
+
+  cogl_onscreen_add_frame_callback(COGL_ONSCREEN (data->fb), _frame_callback,
+                                   &data, NULL);
+  g_idle_add (_draw, data);
+}
+
+int
+main (int argc,
+      char **argv)
+{
+  Data data;
+  CoglContext *ctx;
+  CoglOnscreen *onscreen;
+  CoglMatrix view;
+  CoglGstVideoPlayer *player;
+  GMainLoop *loop;
+  float fovy, aspect, z_near, z_2d, z_far;
+
+  ctx = cogl_context_new (NULL, NULL);
+  onscreen = cogl_onscreen_new (ctx, 640, 480);
+  data.fb = COGL_FRAMEBUFFER (onscreen);
+  cogl_onscreen_show (onscreen);
+
+  cogl_framebuffer_set_viewport (data.fb, 0, 0, 640, 480);
+  fovy = 60;
+  aspect = 640 / 480;
+  z_near = 0.1;
+  z_2d = 1000;
+  z_far = 2000;
+
+  cogl_framebuffer_perspective (data.fb, fovy, aspect, z_near, z_far);
+  cogl_matrix_init_identity (&view);
+  cogl_matrix_view_2d_in_perspective (&view, fovy, aspect, z_near, z_2d,
+                                      640, 480);
+  cogl_framebuffer_set_modelview_matrix (data.fb, &view);
+
+  cogl_gst_init (&argc, &argv);
+
+  player = cogl_gst_video_player_new (ctx, TRUE,
+                                      "http://docs.gstreamer.com/media/sintel_trailer-480p.webm");
+
+  data.sink = cogl_gst_video_player_get_sink (player);
+
+  cogl_gst_video_player_add_bus_watch (player, _bus_watch, &data);
+  loop = cogl_gst_video_sink_get_main_loop (data.sink);
+
+  g_signal_connect (data.sink, "cogl-pipeline-ready",
+                    G_CALLBACK (_set_up_pipeline), &data);
+
+  data.draw_ready = TRUE;
+
+  g_main_loop_run (loop);
+  return 0;
+}
+
-- 
1.7.11.3.g3c3efa5



More information about the Cogl mailing list