gl: add colorconvert object that converts between color spaces/formats
authorMatthew Waters <ystreet00@gmail.com>
Tue, 1 Apr 2014 02:30:51 +0000 (13:30 +1100)
committerTim-Philipp Müller <tim@centricular.com>
Sat, 9 Dec 2017 19:31:36 +0000 (19:31 +0000)
Currently used by both upload and download objects separately.

13 files changed:
ext/gl/gstglimagesink.c
ext/gl/gstgltestsrc.c
gst-libs/gst/gl/Makefile.am
gst-libs/gst/gl/gl.h
gst-libs/gst/gl/gstgl_fwd.h
gst-libs/gst/gl/gstglcolorconvert.c [new file with mode: 0644]
gst-libs/gst/gl/gstglcolorconvert.h [new file with mode: 0644]
gst-libs/gst/gl/gstgldownload.c
gst-libs/gst/gl/gstgldownload.h
gst-libs/gst/gl/gstglfilter.c
gst-libs/gst/gl/gstglmixer.c
gst-libs/gst/gl/gstglupload.c
gst-libs/gst/gl/gstglupload.h

index 144b1aa46d596ab371bd07004a26da0222061c36..258a6174fc98f330fdd4e49a011b0dfe7e8098d2 100644 (file)
@@ -178,10 +178,10 @@ static GstStaticPadTemplate gst_glimage_sink_template =
         GST_VIDEO_CAPS_MAKE_WITH_FEATURES
         (GST_CAPS_FEATURE_MEMORY_EGL_IMAGE, "RGBA") "; "
 #endif
-        GST_VIDEO_CAPS_MAKE (GST_GL_UPLOAD_FORMATS) "; "
+        GST_VIDEO_CAPS_MAKE (GST_GL_COLOR_CONVERT_FORMATS) "; "
         GST_VIDEO_CAPS_MAKE_WITH_FEATURES
         (GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META,
-            GST_GL_UPLOAD_FORMATS))
+            GST_GL_COLOR_CONVERT_FORMATS))
     );
 
 enum
index 59cefd77d572ec8dafa15b3dbd78a68142c41a41..fea9ddfc3af553bbe99e741072fb4bfca7166b82 100644 (file)
@@ -160,7 +160,7 @@ gst_gl_test_src_class_init (GstGLTestSrcClass * klass)
 
   gst_element_class_add_pad_template (element_class,
       gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
-          gst_caps_from_string (GST_GL_DOWNLOAD_VIDEO_CAPS)));
+          gst_caps_from_string (GST_GL_COLOR_CONVERT_VIDEO_CAPS)));
 
   element_class->set_context = gst_gl_test_src_set_context;
 
index 879425b65919d9583f40d33ec47d4edd25056557..bfda193d7c73bf896ed1e75e01b2b94ddd9edf40 100644 (file)
@@ -17,6 +17,7 @@ libgstgl_@GST_API_VERSION@_la_SOURCES = \
        gstglmixer.c \
         gstglshader.c \
         gstglshadervariables.c \
+        gstglcolorconvert.c \
         gstgldownload.c \
         gstglupload.c \
         gstglwindow.c \
@@ -38,6 +39,7 @@ libgstgl_@GST_API_VERSION@include_HEADERS = \
        gstglmixerpad.h \
        gstglshadervariables.h \
        gstglshader.h \
+       gstglcolorconvert.h \
        gstgldownload.h \
        gstglupload.h \
        gstglapi.h \
index 07d94781200fab276a50a1be71414cc0db4b3c42..32cf5fd69c4064093aa4c0bf1fc7b825a53031e7 100644 (file)
@@ -30,6 +30,7 @@
 #include <gst/gl/gstglutils.h>
 #include <gst/gl/gstglwindow.h>
 #include <gst/gl/gstglshader.h>
+#include <gst/gl/gstglcolorconvert.h>
 #include <gst/gl/gstglupload.h>
 #include <gst/gl/gstgldownload.h>
 #include <gst/gl/gstglmemory.h>
index 8de50c232486bab04b14b3ab6ffc7f68fc834c76..4b9a0940e234f1535e35f66fcfb9ece1e2c44461 100644 (file)
@@ -55,6 +55,10 @@ typedef struct _GstGLUpload GstGLUpload;
 typedef struct _GstGLUploadClass GstGLUploadClass;
 typedef struct _GstGLUploadPrivate GstGLUploadPrivate;
 
+typedef struct _GstGLColorConvert GstGLColorConvert;
+typedef struct _GstGLColorConvertClass GstGLColorConvertClass;
+typedef struct _GstGLColorConvertPrivate GstGLColorConvertPrivate;
+
 G_END_DECLS
 
 #endif /* __GST_GL_FWD_H__ */
diff --git a/gst-libs/gst/gl/gstglcolorconvert.c b/gst-libs/gst/gl/gstglcolorconvert.c
new file mode 100644 (file)
index 0000000..82b091e
--- /dev/null
@@ -0,0 +1,1251 @@
+/*
+ * GStreamer
+ * Copyright (C) 2012-2014 Matthew Waters <ystree00@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+
+#include "gl.h"
+#include "gstglcolorconvert.h"
+
+/**
+ * SECTION:gstglcolorconvert
+ * @short_description: an object that converts between color spaces/formats
+ * @see_also: #GstGLUpload, #GstGLDownload, #GstGLMemory
+ *
+ * #GstGLColorConvert is an object that converts between color spaces and/or
+ * formats using OpenGL Shaders.
+ *
+ * A #GstGLColorConvert can be created with gst_gl_color_convert_new().
+ *
+ * For handling stride scaling in the shader, see
+ * gst_gl_color_convert_set_texture_scaling().
+ */
+
+#define USING_OPENGL(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_OPENGL)
+#define USING_OPENGL3(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_OPENGL3)
+#define USING_GLES(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES)
+#define USING_GLES2(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES2)
+#define USING_GLES3(context) (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES3)
+
+static void _do_convert (GstGLContext * context, GstGLColorConvert * convert);
+static void _init_convert (GstGLContext * context, GstGLColorConvert * convert);
+static gboolean _init_convert_fbo (GstGLContext * context,
+    GstGLColorConvert * convert);
+static gboolean _gst_gl_color_convert_perform_unlocked (GstGLColorConvert *
+    convert, guint in_tex[GST_VIDEO_MAX_PLANES],
+    guint out_tex[GST_VIDEO_MAX_PLANES]);
+
+static gboolean _do_convert_draw (GstGLContext * context,
+    GstGLColorConvert * convert);
+
+/* *INDENT-OFF* */
+
+#define YUV_TO_RGB_COEFFICIENTS \
+      "uniform vec3 offset;\n" \
+      "uniform vec3 coeff1;\n" \
+      "uniform vec3 coeff2;\n" \
+      "uniform vec3 coeff3;\n"
+
+/* FIXME: use the colormatrix support from videoconvert */
+
+/* BT. 601 standard with the following ranges:
+ * Y = [16..235] (of 255)
+ * Cb/Cr = [16..240] (of 255)
+ */
+static const gfloat from_yuv_bt601_offset[] = {-0.0625, -0.5, -0.5};
+static const gfloat from_yuv_bt601_rcoeff[] = {1.164, 0.000, 1.596};
+static const gfloat from_yuv_bt601_gcoeff[] = {1.164,-0.391,-0.813};
+static const gfloat from_yuv_bt601_bcoeff[] = {1.164, 2.018, 0.000};
+
+/* BT. 709 standard with the following ranges:
+ * Y = [16..235] (of 255)
+ * Cb/Cr = [16..240] (of 255)
+ */
+static const gfloat from_yuv_bt709_offset[] = {-0.0625, -0.5, -0.5};
+static const gfloat from_yuv_bt709_rcoeff[] = {1.164, 0.000, 1.787};
+static const gfloat from_yuv_bt709_gcoeff[] = {1.164,-0.213,-0.531};
+static const gfloat from_yuv_bt709_bcoeff[] = {1.164,-2.112, 0.000};
+
+#define RGB_TO_YUV_COEFFICIENTS \
+      "uniform vec3 offset;\n" \
+      "uniform vec3 coeff1;\n" \
+      "uniform vec3 coeff2;\n" \
+      "uniform vec3 coeff3;\n"
+
+/* Matrix inverses of the color matrices found above */
+/* BT. 601 standard with the following ranges:
+ * Y = [16..235] (of 255)
+ * Cb/Cr = [16..240] (of 255)
+ */
+static const gfloat from_rgb_bt601_offset[] = {0.0625, 0.5, 0.5};
+static const gfloat from_rgb_bt601_ycoeff[] = {0.256816, 0.504154, 0.0979137};
+static const gfloat from_rgb_bt601_ucoeff[] = {-0.148246, -0.29102, 0.439266};
+static const gfloat from_rgb_bt601_vcoeff[] = {0.439271, -0.367833, -0.071438};
+
+/* BT. 709 standard with the following ranges:
+ * Y = [16..235] (of 255)
+ * Cb/Cr = [16..240] (of 255)
+ */
+static const gfloat from_rgb_bt709_offset[] = {0.0625, 0.5, 0.5};
+static const gfloat from_rgb_bt709_ycoeff[] = {0.213392, 0.718140,-0.072426};
+static const gfloat from_rgb_bt709_ucoeff[] = {0.117608, 0.395793,-0.513401};
+static const gfloat from_rgb_bt709_vcoeff[] = {0.420599,-0.467775, 0.047176};
+
+/** GRAY16 to RGB conversion 
+ *  data transfered as GL_LUMINANCE_ALPHA then convert back to GRAY16 
+ *  high byte weight as : 255*256/65535 
+ *  ([0~1] denormalize to [0~255],shift to high byte,normalize to [0~1])
+ *  low byte weight as : 255/65535 (similar)
+ * */
+#define COMPOSE_WEIGHT \
+    "const vec2 compose_weight = vec2(0.996109, 0.003891);\n"
+
+/* Channel reordering for XYZ <-> ZYX conversion */
+static const char *frag_REORDER =
+      "#ifdef GL_ES\n"
+      "precision mediump float;\n"
+      "#endif\n"
+      "varying vec2 v_texcoord;\n"
+      "uniform sampler2D tex;\n"
+      "uniform vec2 tex_scale0;\n"
+      "uniform vec2 tex_scale1;\n"
+      "uniform vec2 tex_scale2;\n"
+      "void main(void)\n"
+      "{\n"
+      " vec4 t = texture2D(tex, v_texcoord * tex_scale0);\n"
+      " gl_FragColor = vec4(t.%c, t.%c, t.%c, t.%c);\n"
+      "}";
+
+/** GRAY16 to RGB conversion 
+ *  data transfered as GL_LUMINANCE_ALPHA then convert back to GRAY16 
+ *  high byte weight as : 255*256/65535 
+ *  ([0~1] denormalize to [0~255],shift to high byte,normalize to [0~1])
+ *  low byte weight as : 255/65535 (similar)
+ * */
+static const char *frag_COMPOSE =
+      "#ifdef GL_ES\n"
+      "precision mediump float;\n"
+      "#endif\n"
+      "varying vec2 v_texcoord;\n"
+      "uniform sampler2D tex;\n"
+      "uniform vec2 tex_scale0;\n"
+      "uniform vec2 tex_scale1;\n"
+      "uniform vec2 tex_scale2;\n"
+      COMPOSE_WEIGHT
+      "void main(void)\n"
+      "{\n"
+      " float r, g, b, a;\n"
+      " vec4 t = texture2D(tex, v_texcoord * tex_scale0);\n"
+      " r = dot(t.%c%c, compose_weight);"
+      " g = r;\n"
+      " b = r;\n"
+      " a = 1.0;\n"
+      " gl_FragColor = vec4(%c, %c, %c, %c);\n"
+      "}";
+
+static const char *frag_AYUV_to_RGB =
+    "#ifdef GL_ES\n"
+    "precision mediump float;\n"
+    "#endif\n"
+    "varying vec2 v_texcoord;\n"
+    "uniform sampler2D tex;\n"
+    "uniform vec2 tex_scale0;\n"
+    "uniform vec2 tex_scale1;\n"
+    "uniform vec2 tex_scale2;\n"
+    YUV_TO_RGB_COEFFICIENTS
+    "void main(void) {\n"
+    "  float r,g,b,a;\n"
+    "  vec3 yuv;\n"
+    "  yuv  = texture2D(tex,v_texcoord * tex_scale0).gba;\n"
+    "  yuv += offset;\n"
+    "  r = dot(yuv, coeff1);\n"
+    "  g = dot(yuv, coeff2);\n"
+    "  b = dot(yuv, coeff3);\n"
+    "  a = 1.0;\n"
+    "  gl_FragColor=vec4(%c,%c,%c,%c);\n"
+    "}";
+
+static const gchar *frag_RGB_to_AYUV =
+    "#ifdef GL_ES\n"
+    "precision mediump float;\n"
+    "#endif\n"
+    "varying vec2 v_texcoord;\n"
+    "uniform sampler2D tex;\n"
+    RGB_TO_YUV_COEFFICIENTS
+    "void main(void) {\n"
+    "  vec4 texel;\n"
+    "  float y, u, v;\n"
+    "  texel = texture2D(tex, v_texcoord).%c%c%c%c;\n"
+    "  y = dot(texel.rgb, coeff1);\n"
+    "  u = dot(texel.rgb, coeff2);\n"
+    "  v = dot(texel.rgb, coeff3);\n"
+    "  y += offset.x;\n"
+    "  u += offset.y;\n"
+    "  v += offset.z;\n"
+    "  gl_FragColor = vec4(1.0,y,u,v);\n"
+    "}\n";
+
+/** YUV to RGB conversion */
+static const char *frag_PLANAR_YUV_to_RGB =
+    "#ifdef GL_ES\n"
+    "precision mediump float;\n"
+    "#endif\n"
+    "varying vec2 v_texcoord;\n"
+    "uniform sampler2D Ytex, Utex, Vtex;\n"
+    "uniform vec2 tex_scale0;\n"
+    "uniform vec2 tex_scale1;\n"
+    "uniform vec2 tex_scale2;\n"
+    YUV_TO_RGB_COEFFICIENTS
+    "void main(void) {\n"
+    "  float r, g, b, a;\n"
+    "  vec3 yuv;\n"
+    "  yuv.x = texture2D(Ytex,v_texcoord * tex_scale0).r;\n"
+    "  yuv.y = texture2D(Utex,v_texcoord * tex_scale1).r;\n"
+    "  yuv.z = texture2D(Vtex,v_texcoord * tex_scale2).r;\n"
+    "  yuv += offset;\n"
+    "  r = dot(yuv, coeff1);\n"
+    "  g = dot(yuv, coeff2);\n"
+    "  b = dot(yuv, coeff3);\n"
+    "  a = 1.0;\n"
+    "  gl_FragColor = vec4(%c, %c, %c, %c);\n"
+    "}\n";
+
+static const gchar *frag_RGB_to_PLANAR_YUV =
+    "#ifdef GL_ES\n"
+    "precision mediump float;\n"
+    "#endif\n"
+    "varying vec2 v_texcoord;\n"
+    "uniform sampler2D tex;\n"
+    "uniform float w, h;\n"
+    RGB_TO_YUV_COEFFICIENTS
+    "void main(void) {\n"
+    "  float y, u, v;\n"
+    "  vec4 texel = texture2D(tex, v_texcoord).%c%c%c%c;\n"
+    "  vec4 texel2 = texture2D(tex, v_texcoord * 2.0).%c%c%c%c;\n"
+    "  y = dot(texel.rgb, coeff1);\n"
+    "  u = dot(texel2.rgb, coeff2);\n"
+    "  v = dot(texel2.rgb, coeff3);\n"
+    "  y += offset.x;\n"
+    "  u += offset.y;\n"
+    "  v += offset.z;\n"
+    "  gl_FragData[0] = vec4(y, 0.0, 0.0, 1.0);\n"
+    "  gl_FragData[1] = vec4(u, 0.0, 0.0, 1.0);\n"
+    "  gl_FragData[2] = vec4(v, 0.0, 0.0, 1.0);\n"
+    "}\n";
+
+/** NV12/NV21 to RGB conversion */
+static const char *frag_NV12_NV21_to_RGB = {
+      "#ifdef GL_ES\n"
+      "precision mediump float;\n"
+      "#endif\n"
+      "varying vec2 v_texcoord;\n"
+      "uniform sampler2D Ytex,UVtex;\n"
+      "uniform vec2 tex_scale0;\n"
+      "uniform vec2 tex_scale1;\n"
+      "uniform vec2 tex_scale2;\n"
+      YUV_TO_RGB_COEFFICIENTS
+      "void main(void) {\n"
+      "  float r, g, b, a;\n"
+      "  vec3 yuv;\n"
+      "  yuv.x=texture2D(Ytex, v_texcoord * tex_scale0).r;\n"
+      "  yuv.yz=texture2D(UVtex, v_texcoord * tex_scale1).%c%c;\n"
+      "  yuv += offset;\n"
+      "  r = dot(yuv, coeff1);\n"
+      "  g = dot(yuv, coeff2);\n"
+      "  b = dot(yuv, coeff3);\n"
+      "  a = 1.0;\n"
+      "  gl_FragColor=vec4(%c, %c, %c, %c);\n"
+      "}"
+};
+
+/* YUY2:r,g,a
+   UYVY:a,b,r */
+static const gchar *frag_YUY2_UYVY_to_RGB =
+    "#ifdef GL_ES\n"
+    "precision mediump float;\n"
+    "#endif\n"
+    "varying vec2 v_texcoord;\n"
+    "uniform sampler2D Ytex, UVtex;\n"
+    "uniform vec2 tex_scale0;\n"
+    "uniform vec2 tex_scale1;\n"
+    "uniform vec2 tex_scale2;\n"
+    YUV_TO_RGB_COEFFICIENTS
+    "void main(void) {\n"
+    "  vec3 yuv;\n"
+    "  float r, g, b, a;\n"
+    "  yuv.x = texture2D(Ytex, v_texcoord * tex_scale0).%c;\n"
+    "  yuv.yz = texture2D(UVtex, v_texcoord * tex_scale1).%c%c;\n"
+    "  yuv += offset;\n"
+    "  r = dot(yuv, coeff1);\n"
+    "  g = dot(yuv, coeff2);\n"
+    "  b = dot(yuv, coeff3);\n"
+    "  a = 1.0;\n"
+    "  gl_FragColor = vec4(%c, %c, %c, %c);\n"
+    "}\n";
+
+static const gchar *frag_RGB_to_YUY2_UYVY =
+    "#ifdef GL_ES\n"
+    "precision mediump float;\n"
+    "#endif\n"
+    "varying vec2 v_texcoord;\n"
+    "uniform sampler2D tex;\n"
+    "uniform float width;\n"
+    RGB_TO_YUV_COEFFICIENTS
+    "void main(void) {\n"
+    "  vec4 texel1, texel2;\n"
+    "  float fx, fy, y1, y2, u, v;\n"
+    "  fx = v_texcoord.x;\n"
+    "  fy = v_texcoord.y;\n"
+    "  texel1 = texture2D(tex, vec2(fx*2.0,     fy)).%c%c%c%c;\n"
+    "  texel2 = texture2D(tex, vec2(fx*2.0+1.0 / width, fy)).%c%c%c%c;\n"
+    "  y1 = dot(texel1.rgb, coeff1);\n"
+    "  y2 = dot(texel2.rgb, coeff1);\n"
+    "  u = dot(texel1.rgb, coeff2);\n"
+    "  v = dot(texel1.rgb, coeff3);\n"
+    "  y1 += offset.x;\n"
+    "  y2 += offset.x;\n"
+    "  u += offset.y;\n"
+    "  v += offset.z;\n"
+    "  gl_FragColor = vec4(%s);\n"
+    "}\n";
+
+static const gchar *text_vertex_shader =
+    "attribute vec4 a_position;   \n"
+    "attribute vec2 a_texcoord;   \n"
+    "varying vec2 v_texcoord;     \n"
+    "void main()                  \n"
+    "{                            \n"
+    "   gl_Position = a_position; \n"
+    "   v_texcoord = a_texcoord;  \n"
+    "}                            \n";
+
+/* *INDENT-ON* */
+
+struct ConvertInfo
+{
+  gint in_n_textures;
+  gint out_n_textures;
+  gchar *frag_prog;
+  const gchar *shader_tex_names[GST_VIDEO_MAX_PLANES];
+  gfloat shader_scaling[GST_VIDEO_MAX_PLANES][2];
+  gfloat *cms_offset;
+  gfloat *cms_coeff1;           /* r,y */
+  gfloat *cms_coeff2;           /* g,u */
+  gfloat *cms_coeff3;           /* b,v */
+};
+
+struct _GstGLColorConvertPrivate
+{
+  int n_textures;
+  gboolean result;
+
+    gboolean (*draw) (GstGLContext * context, GstGLColorConvert * download);
+
+  struct ConvertInfo convert_info;
+
+  guint tex_id;
+  gboolean mapped;
+};
+
+GST_DEBUG_CATEGORY_STATIC (gst_gl_color_convert_debug);
+#define GST_CAT_DEFAULT gst_gl_color_convert_debug
+
+#define DEBUG_INIT \
+  GST_DEBUG_CATEGORY_INIT (gst_gl_color_convert_debug, "glconvert", 0, "convert");
+
+G_DEFINE_TYPE_WITH_CODE (GstGLColorConvert, gst_gl_color_convert, G_TYPE_OBJECT,
+    DEBUG_INIT);
+static void gst_gl_color_convert_finalize (GObject * object);
+
+#define GST_GL_COLOR_CONVERT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
+    GST_TYPE_GL_COLOR_CONVERT, GstGLColorConvertPrivate))
+
+static void
+gst_gl_color_convert_class_init (GstGLColorConvertClass * klass)
+{
+  g_type_class_add_private (klass, sizeof (GstGLColorConvertPrivate));
+
+  G_OBJECT_CLASS (klass)->finalize = gst_gl_color_convert_finalize;
+}
+
+static void
+gst_gl_color_convert_init (GstGLColorConvert * convert)
+{
+  convert->priv = GST_GL_COLOR_CONVERT_GET_PRIVATE (convert);
+
+  g_mutex_init (&convert->lock);
+}
+
+/**
+ * gst_gl_color_convert_new:
+ * @context: a #GstGLContext
+ *
+ * Returns: a new #GstGLColorConvert object
+ */
+GstGLColorConvert *
+gst_gl_color_convert_new (GstGLContext * context)
+{
+  GstGLColorConvert *convert;
+  GstGLColorConvertPrivate *priv;
+
+  convert = g_object_new (GST_TYPE_GL_COLOR_CONVERT, NULL);
+
+  convert->context = gst_object_ref (context);
+  priv = convert->priv;
+
+  priv->draw = _do_convert_draw;
+
+  return convert;
+}
+
+static void
+gst_gl_color_convert_finalize (GObject * object)
+{
+  GstGLColorConvert *convert;
+
+  convert = GST_GL_COLOR_CONVERT (object);
+
+  if (convert->fbo || convert->depth_buffer) {
+    gst_gl_context_del_fbo (convert->context, convert->fbo,
+        convert->depth_buffer);
+    convert->fbo = 0;
+    convert->depth_buffer = 0;
+  }
+  if (convert->shader) {
+    gst_object_unref (convert->shader);
+    convert->shader = NULL;
+  }
+
+  if (convert->context) {
+    gst_object_unref (convert->context);
+    convert->context = NULL;
+  }
+
+  g_mutex_clear (&convert->lock);
+
+  G_OBJECT_CLASS (gst_gl_color_convert_parent_class)->finalize (object);
+}
+
+static gboolean
+_gst_gl_color_convert_init_format_unlocked (GstGLColorConvert * convert,
+    GstVideoInfo in_info, GstVideoInfo out_info)
+{
+  g_return_val_if_fail (convert != NULL, FALSE);
+  g_return_val_if_fail (GST_VIDEO_INFO_FORMAT (&in_info) !=
+      GST_VIDEO_FORMAT_UNKNOWN, FALSE);
+  g_return_val_if_fail (GST_VIDEO_INFO_FORMAT (&in_info) !=
+      GST_VIDEO_FORMAT_ENCODED, FALSE);
+
+  if (convert->initted) {
+    return FALSE;
+  } else {
+    convert->initted = TRUE;
+  }
+
+  convert->in_info = in_info;
+  convert->out_info = out_info;
+
+  gst_gl_context_thread_add (convert->context,
+      (GstGLContextThreadFunc) _init_convert, convert);
+
+  return convert->priv->result;
+}
+
+/**
+ * gst_gl_color_convert_init_format:
+ * @convert: a #GstGLColorConvert
+ * @in_info: input #GstVideoInfo
+ * @out_info: output #GstVideoInfo
+ *
+ * Initializes @convert with the information required for conversion.
+ *
+ * Returns: whether the initialization was successful
+ */
+gboolean
+gst_gl_color_convert_init_format (GstGLColorConvert * convert,
+    GstVideoInfo in_info, GstVideoInfo out_info)
+{
+  gboolean ret;
+
+  g_mutex_lock (&convert->lock);
+  ret = _gst_gl_color_convert_init_format_unlocked (convert, in_info, out_info);
+  g_mutex_unlock (&convert->lock);
+
+  return ret;
+}
+
+/**
+ * gst_gl_color_convert_perform:
+ * @convert: a #GstGLColorConvert
+ * @in_tex: the texture ids for input formatted according to in_info
+ * @out_tex: the texture ids for output formatted according to out_info
+ *
+ * Converts the data contained in in_tex into out_tex using the formats
+ * specified by the #GstVideoInfo<!--  -->s passed to
+ * gst_gl_color_convert_init_format() 
+ *
+ * Returns: whether the conversion was successful
+ */
+gboolean
+gst_gl_color_convert_perform (GstGLColorConvert * convert,
+    guint in_tex[GST_VIDEO_MAX_PLANES], guint out_tex[GST_VIDEO_MAX_PLANES])
+{
+  gboolean ret;
+
+  g_return_val_if_fail (convert != NULL, FALSE);
+
+  g_mutex_lock (&convert->lock);
+  ret = _gst_gl_color_convert_perform_unlocked (convert, in_tex, out_tex);
+  g_mutex_unlock (&convert->lock);
+
+  return ret;
+}
+
+/**
+ * gst_gl_color_convert_set_texture_scaling:
+ * @convert: a #GstGLColorConvert
+ * @scaling: array of texture scaling coefficients stored in width, height
+ *           order per texture being converted.
+ *
+ * Scales the input textures by the given amount.  Useful for performing stride
+ * scaling in a shader on OpenGL platforms that do not support
+ * GL_PIXEL_[UN]PACK_LENGTH such as GL|ES 2.0.
+ */
+void
+gst_gl_color_convert_set_texture_scaling (GstGLColorConvert * convert,
+    gfloat scaling[GST_VIDEO_MAX_PLANES][2])
+{
+  guint i;
+
+  g_return_val_if_fail (convert != NULL, FALSE);
+
+  for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) {
+    convert->priv->convert_info.shader_scaling[i][0] = scaling[i][0];
+    convert->priv->convert_info.shader_scaling[i][1] = scaling[i][1];
+  }
+}
+
+static gboolean
+_gst_gl_color_convert_perform_unlocked (GstGLColorConvert * convert,
+    guint in_tex[GST_VIDEO_MAX_PLANES], guint out_tex[GST_VIDEO_MAX_PLANES])
+{
+  g_return_val_if_fail (convert != NULL, FALSE);
+  g_return_val_if_fail (in_tex, FALSE);
+  g_return_val_if_fail (out_tex, FALSE);
+
+  convert->in_tex[0] = in_tex[0];
+  convert->in_tex[1] = in_tex[1];
+  convert->in_tex[2] = in_tex[2];
+  convert->in_tex[3] = in_tex[3];
+  convert->out_tex[0] = out_tex[0];
+  convert->out_tex[1] = out_tex[1];
+  convert->out_tex[2] = out_tex[2];
+  convert->out_tex[3] = out_tex[3];
+
+  GST_LOG ("Converting %s from %u,%u,%u,%u into %s using %u,%u,%u,%u",
+      gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&convert->in_info)),
+      in_tex[0], in_tex[1], in_tex[2], in_tex[3],
+      gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&convert->out_info)),
+      out_tex[0], out_tex[1], out_tex[2], out_tex[3]);
+
+  gst_gl_context_thread_add (convert->context,
+      (GstGLContextThreadFunc) _do_convert, convert);
+
+  return TRUE;
+}
+
+static gboolean
+_create_shader (GstGLContext * context, const gchar * vertex_src,
+    const gchar * fragment_src, GstGLShader ** out_shader)
+{
+  GstGLShader *shader;
+  GError *error = NULL;
+
+  g_return_val_if_fail (vertex_src != NULL || fragment_src != NULL, FALSE);
+
+  shader = gst_gl_shader_new (context);
+
+  if (vertex_src)
+    gst_gl_shader_set_vertex_source (shader, vertex_src);
+  if (fragment_src)
+    gst_gl_shader_set_fragment_source (shader, fragment_src);
+
+  if (!gst_gl_shader_compile (shader, &error)) {
+    gst_gl_context_set_error (context, "%s", error->message);
+    g_error_free (error);
+    gst_gl_context_clear_shader (context);
+    gst_object_unref (shader);
+    return FALSE;
+  }
+
+  *out_shader = shader;
+  return TRUE;
+}
+
+static inline const gchar
+_index_to_shader_swizzle (int idx)
+{
+  switch (idx) {
+    case 0:
+      return 'r';
+    case 1:
+      return 'g';
+    case 2:
+      return 'b';
+    case 3:
+      return 'a';
+    default:
+      return '#';
+  }
+}
+
+/* attempts to transform expected to want using swizzling */
+static gchar *
+_RGB_pixel_order (const gchar * expected, const gchar * wanted)
+{
+  GString *ret = g_string_sized_new (4);
+  gchar *expect, *want;
+  int len;
+
+  if (g_ascii_strcasecmp (expected, wanted) == 0)
+    return g_ascii_strdown (expected, -1);
+
+  expect = g_ascii_strdown (expected, -1);
+  want = g_ascii_strdown (wanted, -1);
+
+  /* pad want with 'a's */
+  if ((len = strlen (want)) < 4) {
+    gchar *new_want = g_strndup (want, 4);
+    while (len < 4) {
+      new_want[len] = 'a';
+      len++;
+    }
+    g_free (want);
+    want = new_want;
+  }
+
+  /* pad expect with 'a's */
+  if ((len = strlen (expect)) < 4) {
+    gchar *new_expect = g_strndup (expect, 4);
+    while (len < 4) {
+      new_expect[len] = 'a';
+      len++;
+    }
+    g_free (expect);
+    expect = new_expect;
+  }
+
+  /* build the swizzle format */
+  while (want && want[0] != '\0') {
+    gchar *val;
+    gint idx;
+    gchar needle = want[0];
+
+    if (needle == 'x')
+      needle = 'a';
+
+    if (!(val = strchr (expect, needle))
+        && needle == 'a' && !(val = strchr (expect, 'x')))
+      goto fail;
+
+    idx = (gint) (val - expect);
+
+    ret = g_string_append_c (ret, _index_to_shader_swizzle (idx));
+    want = &want[1];
+  }
+
+  return g_string_free (ret, FALSE);
+
+fail:
+  g_string_free (ret, TRUE);
+  return NULL;
+}
+
+static void
+_RGB_to_RGB (GstGLContext * context, GstGLColorConvert * convert)
+{
+  struct ConvertInfo *info = &convert->priv->convert_info;
+  GstVideoFormat in_format = GST_VIDEO_INFO_FORMAT (&convert->in_info);
+  const gchar *in_format_str = gst_video_format_to_string (in_format);
+  GstVideoFormat out_format = GST_VIDEO_INFO_FORMAT (&convert->out_info);
+  const gchar *out_format_str = gst_video_format_to_string (out_format);
+  gchar *pixel_order = _RGB_pixel_order (in_format_str, out_format_str);
+
+  info->in_n_textures = 1;
+  info->out_n_textures = 1;
+  info->frag_prog = g_strdup_printf (frag_REORDER, pixel_order[0],
+      pixel_order[1], pixel_order[2], pixel_order[3]);
+  info->shader_tex_names[0] = "tex";
+  info->shader_scaling[0][0] = 1.0f;
+  info->shader_scaling[0][1] = 1.0f;
+}
+
+static void
+_YUV_to_RGB (GstGLContext * context, GstGLColorConvert * convert)
+{
+  struct ConvertInfo *info = &convert->priv->convert_info;
+  GstVideoFormat out_format = GST_VIDEO_INFO_FORMAT (&convert->out_info);
+  const gchar *out_format_str = gst_video_format_to_string (out_format);
+  gchar *pixel_order = _RGB_pixel_order ("rgba", out_format_str);
+
+  info->out_n_textures = 1;
+
+  info->shader_scaling[0][0] = 1.0f;
+  info->shader_scaling[0][1] = 1.0f;
+  info->shader_scaling[1][0] = 1.0f;
+  info->shader_scaling[1][1] = 1.0f;
+  info->shader_scaling[2][0] = 1.0f;
+  info->shader_scaling[2][1] = 1.0f;
+
+  switch (GST_VIDEO_INFO_FORMAT (&convert->in_info)) {
+    case GST_VIDEO_FORMAT_AYUV:
+      info->frag_prog = g_strdup_printf (frag_AYUV_to_RGB, pixel_order[0],
+          pixel_order[1], pixel_order[2], pixel_order[3]);
+      info->in_n_textures = 1;
+      info->shader_tex_names[0] = "tex";
+      break;
+    case GST_VIDEO_FORMAT_I420:
+    case GST_VIDEO_FORMAT_YV12:
+    case GST_VIDEO_FORMAT_Y444:
+    case GST_VIDEO_FORMAT_Y42B:
+    case GST_VIDEO_FORMAT_Y41B:
+      info->frag_prog = g_strdup_printf (frag_PLANAR_YUV_to_RGB, pixel_order[0],
+          pixel_order[1], pixel_order[2], pixel_order[3]);
+      info->in_n_textures = 3;
+      info->shader_tex_names[0] = "Ytex";
+      info->shader_tex_names[1] = "Utex";
+      info->shader_tex_names[2] = "Vtex";
+      break;
+    case GST_VIDEO_FORMAT_YUY2:
+      info->frag_prog = g_strdup_printf (frag_YUY2_UYVY_to_RGB, 'r', 'g', 'a',
+          pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3]);
+      info->in_n_textures = 2;
+      info->shader_tex_names[0] = "Ytex";
+      info->shader_tex_names[1] = "UVtex";
+      break;
+    case GST_VIDEO_FORMAT_NV12:
+      info->frag_prog = g_strdup_printf (frag_NV12_NV21_to_RGB, 'r', 'a',
+          pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3]);
+      info->in_n_textures = 2;
+      info->shader_tex_names[0] = "Ytex";
+      info->shader_tex_names[1] = "UVtex";
+      break;
+    case GST_VIDEO_FORMAT_NV21:
+      info->frag_prog = g_strdup_printf (frag_NV12_NV21_to_RGB, 'a', 'r',
+          pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3]);
+      info->in_n_textures = 2;
+      info->shader_tex_names[0] = "Ytex";
+      info->shader_tex_names[1] = "UVtex";
+      break;
+    case GST_VIDEO_FORMAT_UYVY:
+      info->frag_prog = g_strdup_printf (frag_YUY2_UYVY_to_RGB, 'a', 'r', 'b',
+          pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3]);
+      info->in_n_textures = 2;
+      info->shader_tex_names[0] = "Ytex";
+      info->shader_tex_names[1] = "UVtex";
+      break;
+    default:
+      break;
+  }
+
+  if (gst_video_colorimetry_matches (&convert->in_info.colorimetry,
+          GST_VIDEO_COLORIMETRY_BT709)) {
+    info->cms_offset = (gfloat *) from_yuv_bt709_offset;
+    info->cms_coeff1 = (gfloat *) from_yuv_bt709_rcoeff;
+    info->cms_coeff2 = (gfloat *) from_yuv_bt709_gcoeff;
+    info->cms_coeff3 = (gfloat *) from_yuv_bt709_bcoeff;
+  } else {
+    /* defaults/bt601 */
+    info->cms_offset = (gfloat *) from_yuv_bt601_offset;
+    info->cms_coeff1 = (gfloat *) from_yuv_bt601_rcoeff;
+    info->cms_coeff2 = (gfloat *) from_yuv_bt601_gcoeff;
+    info->cms_coeff3 = (gfloat *) from_yuv_bt601_bcoeff;
+  }
+
+  g_free (pixel_order);
+}
+
+static void
+_RGB_to_YUV (GstGLContext * context, GstGLColorConvert * convert)
+{
+  struct ConvertInfo *info = &convert->priv->convert_info;
+  GstVideoFormat in_format = GST_VIDEO_INFO_FORMAT (&convert->in_info);
+  const gchar *in_format_str = gst_video_format_to_string (in_format);
+  gchar *pixel_order = _RGB_pixel_order (in_format_str, "rgba");
+
+  info->frag_prog = NULL;
+  info->in_n_textures = 1;
+
+  info->shader_tex_names[0] = "tex";
+
+  info->shader_scaling[0][0] = 1.0f;
+  info->shader_scaling[0][1] = 1.0f;
+  info->shader_scaling[1][0] = 1.0f;
+  info->shader_scaling[1][1] = 1.0f;
+  info->shader_scaling[2][0] = 1.0f;
+  info->shader_scaling[2][1] = 1.0f;
+
+  switch (GST_VIDEO_INFO_FORMAT (&convert->out_info)) {
+    case GST_VIDEO_FORMAT_AYUV:
+      info->frag_prog = g_strdup_printf (frag_RGB_to_AYUV, pixel_order[0],
+          pixel_order[1], pixel_order[2], pixel_order[3]);
+      info->out_n_textures = 1;
+      break;
+    case GST_VIDEO_FORMAT_I420:
+    case GST_VIDEO_FORMAT_YV12:
+    case GST_VIDEO_FORMAT_Y444:
+    case GST_VIDEO_FORMAT_Y42B:
+    case GST_VIDEO_FORMAT_Y41B:
+      info->frag_prog = g_strdup_printf (frag_RGB_to_PLANAR_YUV,
+          pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3],
+          pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3]);
+      info->out_n_textures = 3;
+      break;
+    case GST_VIDEO_FORMAT_YUY2:
+      info->frag_prog = g_strdup_printf (frag_RGB_to_YUY2_UYVY,
+          pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3],
+          pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3],
+          "y1,u,y2,v");
+      info->out_n_textures = 1;
+      break;
+    case GST_VIDEO_FORMAT_UYVY:
+      info->frag_prog = g_strdup_printf (frag_RGB_to_YUY2_UYVY,
+          pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3],
+          pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3],
+          "u,y1,v,y2");
+      info->out_n_textures = 1;
+      break;
+    default:
+      break;
+  }
+
+  if (gst_video_colorimetry_matches (&convert->in_info.colorimetry,
+          GST_VIDEO_COLORIMETRY_BT709)) {
+    info->cms_offset = (gfloat *) from_rgb_bt709_offset;
+    info->cms_coeff1 = (gfloat *) from_rgb_bt709_ycoeff;
+    info->cms_coeff2 = (gfloat *) from_rgb_bt709_ucoeff;
+    info->cms_coeff3 = (gfloat *) from_rgb_bt709_vcoeff;
+  } else {
+    /* defaults/bt601 */
+    info->cms_offset = (gfloat *) from_rgb_bt601_offset;
+    info->cms_coeff1 = (gfloat *) from_rgb_bt601_ycoeff;
+    info->cms_coeff2 = (gfloat *) from_rgb_bt601_ucoeff;
+    info->cms_coeff3 = (gfloat *) from_rgb_bt601_vcoeff;
+  }
+
+  g_free (pixel_order);
+}
+
+static void
+_RGB_to_GRAY (GstGLContext * context, GstGLColorConvert * convert)
+{
+  struct ConvertInfo *info = &convert->priv->convert_info;
+  GstVideoFormat in_format = GST_VIDEO_INFO_FORMAT (&convert->in_info);
+  const gchar *in_format_str = gst_video_format_to_string (in_format);
+  gchar *pixel_order = _RGB_pixel_order (in_format_str, "rgba");
+
+  info->in_n_textures = 1;
+  info->out_n_textures = 1;
+  info->shader_tex_names[0] = "tex";
+  info->shader_scaling[0][0] = 1.0f;
+  info->shader_scaling[0][1] = 1.0f;
+  info->shader_scaling[1][0] = 1.0f;
+  info->shader_scaling[1][1] = 1.0f;
+  info->shader_scaling[2][0] = 1.0f;
+  info->shader_scaling[2][1] = 1.0f;
+
+  switch (GST_VIDEO_INFO_FORMAT (&convert->out_info)) {
+    case GST_VIDEO_FORMAT_GRAY8:
+      info->frag_prog = g_strdup_printf (frag_REORDER, pixel_order[0],
+          pixel_order[0], pixel_order[0], pixel_order[3]);
+      break;
+    default:
+      break;
+  }
+}
+
+static void
+_GRAY_to_RGB (GstGLContext * context, GstGLColorConvert * convert)
+{
+  struct ConvertInfo *info = &convert->priv->convert_info;
+  GstVideoFormat out_format = GST_VIDEO_INFO_FORMAT (&convert->out_info);
+  const gchar *out_format_str = gst_video_format_to_string (out_format);
+  gchar *pixel_order = _RGB_pixel_order ("rgba", out_format_str);
+
+  info->in_n_textures = 1;
+  info->out_n_textures = 1;
+  info->shader_tex_names[0] = "tex";
+  info->shader_scaling[0][0] = 1.0f;
+  info->shader_scaling[0][1] = 1.0f;
+  info->shader_scaling[1][0] = 1.0f;
+  info->shader_scaling[1][1] = 1.0f;
+  info->shader_scaling[2][0] = 1.0f;
+  info->shader_scaling[2][1] = 1.0f;
+
+  switch (GST_VIDEO_INFO_FORMAT (&convert->in_info)) {
+    case GST_VIDEO_FORMAT_GRAY8:
+      info->frag_prog = g_strdup_printf (frag_REORDER, pixel_order[0],
+          pixel_order[1], pixel_order[2], pixel_order[3]);
+      break;
+    case GST_VIDEO_FORMAT_GRAY16_LE:
+      info->frag_prog = g_strdup_printf (frag_COMPOSE, 'a', 'r',
+          pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3]);
+      break;
+    case GST_VIDEO_FORMAT_GRAY16_BE:
+      info->frag_prog = g_strdup_printf (frag_COMPOSE, 'r', 'a',
+          pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3]);
+      break;
+    default:
+      break;
+  }
+}
+
+/* Called in the gl thread */
+void
+_init_convert (GstGLContext * context, GstGLColorConvert * convert)
+{
+  GstGLFuncs *gl;
+  gboolean res;
+  struct ConvertInfo *info = &convert->priv->convert_info;
+  gint i;
+
+  gl = context->gl_vtable;
+
+  GST_INFO ("Initializing color conversion from %s to %s",
+      gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&convert->in_info)),
+      gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&convert->out_info)));
+
+  if (!gl->CreateProgramObject && !gl->CreateProgram) {
+    gst_gl_context_set_error (context,
+        "Cannot perform color conversion without OpenGL shaders");
+    goto error;
+  }
+
+  if (GST_VIDEO_INFO_IS_RGB (&convert->in_info)) {
+    if (GST_VIDEO_INFO_IS_RGB (&convert->out_info)) {
+      _RGB_to_RGB (context, convert);
+    }
+  }
+
+  if (GST_VIDEO_INFO_IS_YUV (&convert->in_info)) {
+    if (GST_VIDEO_INFO_IS_RGB (&convert->out_info)) {
+      _YUV_to_RGB (context, convert);
+    }
+  }
+
+  if (GST_VIDEO_INFO_IS_RGB (&convert->in_info)) {
+    if (GST_VIDEO_INFO_IS_YUV (&convert->out_info)) {
+      _RGB_to_YUV (context, convert);
+    }
+  }
+
+  if (GST_VIDEO_INFO_IS_RGB (&convert->in_info)) {
+    if (GST_VIDEO_INFO_IS_GRAY (&convert->out_info)) {
+      _RGB_to_GRAY (context, convert);
+    }
+  }
+
+  if (GST_VIDEO_INFO_IS_GRAY (&convert->in_info)) {
+    if (GST_VIDEO_INFO_IS_RGB (&convert->out_info)) {
+      _GRAY_to_RGB (context, convert);
+    }
+  }
+
+  if (!info->frag_prog || info->in_n_textures == 0 || info->out_n_textures == 0)
+    goto unhandled_format;
+
+  /* multiple draw targets not supported on GLES2...yet */
+  if (info->out_n_textures > 1 && (!gl->DrawBuffers || USING_GLES2 (context))) {
+    g_free (info->frag_prog);
+    GST_ERROR ("Conversion requires output to multiple draw buffers");
+    goto incompatible_api;
+  }
+
+  res =
+      _create_shader (context, text_vertex_shader, info->frag_prog,
+      &convert->shader);
+  g_free (info->frag_prog);
+  if (!res)
+    goto error;
+
+  convert->shader_attr_position_loc =
+      gst_gl_shader_get_attribute_location (convert->shader, "a_position");
+  convert->shader_attr_texture_loc =
+      gst_gl_shader_get_attribute_location (convert->shader, "a_texcoord");
+
+  gst_gl_shader_use (convert->shader);
+
+  if (info->cms_offset && info->cms_coeff1
+      && info->cms_coeff2 && info->cms_coeff3) {
+    gst_gl_shader_set_uniform_3fv (convert->shader, "offset", 1,
+        info->cms_offset);
+    gst_gl_shader_set_uniform_3fv (convert->shader, "coeff1", 1,
+        info->cms_coeff1);
+    gst_gl_shader_set_uniform_3fv (convert->shader, "coeff2", 1,
+        info->cms_coeff2);
+    gst_gl_shader_set_uniform_3fv (convert->shader, "coeff3", 1,
+        info->cms_coeff3);
+  }
+
+  for (i = info->in_n_textures - 1; i >= 0; i--) {
+    gchar *scale_name = g_strdup_printf ("tex_scale%u", i);
+
+    gst_gl_shader_set_uniform_1i (convert->shader, info->shader_tex_names[i],
+        i);
+    gst_gl_shader_set_uniform_2fv (convert->shader, scale_name, 1,
+        info->shader_scaling[i]);
+
+    g_free (scale_name);
+  }
+
+  gst_gl_shader_set_uniform_1f (convert->shader, "width",
+      GST_VIDEO_INFO_WIDTH (&convert->in_info));
+
+  gst_gl_context_clear_shader (context);
+
+  if (!_init_convert_fbo (context, convert)) {
+    goto error;
+  }
+
+  gl->BindTexture (GL_TEXTURE_2D, 0);
+
+  convert->priv->result = TRUE;
+  return;
+
+unhandled_format:
+  gst_gl_context_set_error (context, "Don't know how to convert from %s to %s",
+      gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&convert->in_info)),
+      gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&convert->out_info)));
+
+error:
+  convert->priv->result = FALSE;
+  return;
+
+incompatible_api:
+  {
+    gst_gl_context_set_error (context, "Converting from %s to %s requires "
+        "functionality that the current OpenGL setup does not support",
+        gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&convert->in_info)),
+        gst_video_format_to_string (GST_VIDEO_INFO_FORMAT
+            (&convert->out_info)));
+    convert->priv->result = FALSE;
+    return;
+  }
+}
+
+
+/* called by _init_convert (in the gl thread) */
+gboolean
+_init_convert_fbo (GstGLContext * context, GstGLColorConvert * convert)
+{
+  GstGLFuncs *gl;
+  guint out_width, out_height;
+  GLuint fake_texture = 0;      /* a FBO must hava texture to init */
+
+  gl = context->gl_vtable;
+
+  out_width = GST_VIDEO_INFO_WIDTH (&convert->out_info);
+  out_height = GST_VIDEO_INFO_HEIGHT (&convert->out_info);
+
+  if (!gl->GenFramebuffers) {
+    /* turn off the pipeline because Frame buffer object is a not present */
+    gst_gl_context_set_error (context,
+        "Context, EXT_framebuffer_object supported: no");
+    return FALSE;
+  }
+
+  GST_INFO ("Context, EXT_framebuffer_object supported: yes");
+
+  /* setup FBO */
+  gl->GenFramebuffers (1, &convert->fbo);
+  gl->BindFramebuffer (GL_FRAMEBUFFER, convert->fbo);
+
+  /* setup the render buffer for depth */
+  gl->GenRenderbuffers (1, &convert->depth_buffer);
+  gl->BindRenderbuffer (GL_RENDERBUFFER, convert->depth_buffer);
+  if (USING_OPENGL (context)) {
+    gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT,
+        out_width, out_height);
+    gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH24_STENCIL8,
+        out_width, out_height);
+  }
+  if (USING_GLES2 (context)) {
+    gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
+        out_width, out_height);
+  }
+
+  /* a fake texture is attached to the convert FBO (cannot init without it) */
+  gl->GenTextures (1, &fake_texture);
+  gl->BindTexture (GL_TEXTURE_2D, fake_texture);
+  gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, out_width, out_height,
+      0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+  gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+  gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+  gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+  gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+  /* attach the texture to the FBO to renderer to */
+  gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+      GL_TEXTURE_2D, fake_texture, 0);
+
+  /* attach the depth render buffer to the FBO */
+  gl->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+      GL_RENDERBUFFER, convert->depth_buffer);
+
+  if (USING_OPENGL (context)) {
+    gl->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+        GL_RENDERBUFFER, convert->depth_buffer);
+  }
+
+  if (!gst_gl_context_check_framebuffer_status (context)) {
+    gst_gl_context_set_error (context, "GL framebuffer status incomplete");
+    return FALSE;
+  }
+
+  /* unbind the FBO */
+  gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
+
+  gl->DeleteTextures (1, &fake_texture);
+
+  return TRUE;
+}
+
+/* Called by the idle function in the gl thread */
+void
+_do_convert (GstGLContext * context, GstGLColorConvert * convert)
+{
+  guint in_width, in_height, out_width, out_height;
+
+  out_width = GST_VIDEO_INFO_WIDTH (&convert->out_info);
+  out_height = GST_VIDEO_INFO_HEIGHT (&convert->out_info);
+  in_width = GST_VIDEO_INFO_WIDTH (&convert->in_info);
+  in_height = GST_VIDEO_INFO_HEIGHT (&convert->in_info);
+
+  GST_TRACE ("converting to textures:%u,%u,%u,%u dimensions:%ux%u, "
+      "from textures:%u,%u,%u,%u dimensions:%ux%u", convert->out_tex[0],
+      convert->out_tex[1], convert->out_tex[2], convert->out_tex[3],
+      out_width, out_height, convert->in_tex[0], convert->in_tex[1],
+      convert->in_tex[2], convert->in_tex[3], in_width, in_height);
+
+  if (!convert->priv->draw (context, convert))
+    goto error;
+
+  convert->priv->result = TRUE;
+  return;
+
+error:
+  {
+    convert->priv->result = FALSE;
+    return;
+  }
+}
+
+static gboolean
+_do_convert_draw (GstGLContext * context, GstGLColorConvert * convert)
+{
+  GstGLFuncs *gl;
+  struct ConvertInfo *c_info = &convert->priv->convert_info;
+  guint out_width, out_height;
+  gint i;
+
+  const GLfloat vVertices[] = { 1.0f, -1.0f, 0.0f,
+    1.0f, 0.0f,
+    -1.0f, -1.0f, 0.0f,
+    0.0f, 0.0f,
+    -1.0f, 1.0f, 0.0f,
+    0.0f, 1.0f,
+    1.0f, 1.0f, 0.0f,
+    1.0f, 1.0f
+  };
+
+  GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
+
+  GLenum multipleRT[] = {
+    GL_COLOR_ATTACHMENT0,
+    GL_COLOR_ATTACHMENT1,
+    GL_COLOR_ATTACHMENT2
+  };
+
+  gl = context->gl_vtable;
+
+  out_width = GST_VIDEO_INFO_WIDTH (&convert->out_info);
+  out_height = GST_VIDEO_INFO_HEIGHT (&convert->out_info);
+
+  gl->BindFramebuffer (GL_FRAMEBUFFER, convert->fbo);
+
+  /* attach the texture to the FBO to renderer to */
+  for (i = 0; i < c_info->out_n_textures; i++) {
+    /* needed? */
+    gl->BindTexture (GL_TEXTURE_2D, convert->out_tex[i]);
+
+    gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
+        GL_TEXTURE_2D, convert->out_tex[i], 0);
+  }
+
+  if (gl->DrawBuffers)
+    gl->DrawBuffers (c_info->out_n_textures, multipleRT);
+  else if (gl->DrawBuffer)
+    gl->DrawBuffer (GL_COLOR_ATTACHMENT0);
+
+  gl->Viewport (0, 0, out_width, out_height);
+
+  gl->ClearColor (0.0, 0.0, 0.0, 0.0);
+  gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+  gst_gl_shader_use (convert->shader);
+
+  gl->VertexAttribPointer (convert->shader_attr_position_loc, 3,
+      GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), vVertices);
+  gl->VertexAttribPointer (convert->shader_attr_texture_loc, 2,
+      GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), &vVertices[3]);
+
+  gl->EnableVertexAttribArray (convert->shader_attr_position_loc);
+  gl->EnableVertexAttribArray (convert->shader_attr_texture_loc);
+
+  for (i = c_info->in_n_textures - 1; i >= 0; i--) {
+    gl->ActiveTexture (GL_TEXTURE0 + i);
+    gl->BindTexture (GL_TEXTURE_2D, convert->in_tex[i]);
+
+    gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+  }
+
+  gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
+
+  gl->DisableVertexAttribArray (convert->shader_attr_position_loc);
+  gl->DisableVertexAttribArray (convert->shader_attr_texture_loc);
+
+  if (gl->DrawBuffer)
+    gl->DrawBuffer (GL_NONE);
+
+  /* we are done with the shader */
+  gst_gl_context_clear_shader (context);
+
+  gst_gl_context_check_framebuffer_status (context);
+
+  gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
+
+  return TRUE;
+}
diff --git a/gst-libs/gst/gl/gstglcolorconvert.h b/gst-libs/gst/gl/gstglcolorconvert.h
new file mode 100644 (file)
index 0000000..4832268
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * GStreamer
+ * Copyright (C) 2012 Matthew Waters <ystree00@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_GL_COLOR_CONVERT_H__
+#define __GST_GL_COLOR_CONVERT_H__
+
+#include <gst/video/video.h>
+#include <gst/gstmemory.h>
+
+#include <gst/gl/gstgl_fwd.h>
+
+G_BEGIN_DECLS
+
+GType gst_gl_color_convert_get_type (void);
+#define GST_TYPE_GL_COLOR_CONVERT (gst_gl_color_convert_get_type())
+#define GST_GL_COLOR_CONVERT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_COLOR_CONVERT,GstGLColorConvert))
+#define GST_GL_COLOR_CONVERT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GL_DISPLAY,GstGLColorConvertClass))
+#define GST_IS_GL_COLOR_CONVERT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_COLOR_CONVERT))
+#define GST_IS_GL_COLOR_CONVERT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GL_COLOR_CONVERT))
+#define GST_GL_COLOR_CONVERT_CAST(obj) ((GstGLColorConvert*)(obj))
+
+/**
+ * GstGLColorConvert
+ *
+ * Opaque #GstGLColorConvert object
+ */
+struct _GstGLColorConvert
+{
+  /* <private> */
+  GObject          parent;
+
+  GMutex           lock;
+
+  GstGLContext    *context;
+
+  /* input data */
+  GstVideoInfo     in_info;
+  GstVideoInfo     out_info;
+
+  gboolean         initted;
+
+  guint            in_tex[GST_VIDEO_MAX_PLANES];
+  guint            out_tex[GST_VIDEO_MAX_PLANES];
+
+  /* used for the conversion */
+  GLuint           fbo;
+  GLuint           depth_buffer;
+  GstGLShader     *shader;
+  GLint            shader_attr_position_loc;
+  GLint            shader_attr_texture_loc;
+
+  /* <private> */
+  GstGLColorConvertPrivate *priv;
+
+  gpointer _reserved[GST_PADDING];
+};
+
+/**
+ * GstGLColorConvertClass:
+ *
+ * The #GstGLColorConvertClass struct only contains private data
+ */
+struct _GstGLColorConvertClass
+{
+  GObjectClass object_class;
+};
+
+/**
+ * GST_GL_COLOR_CONVERT_FORMATS:
+ *
+ * The currently supported formats that can be converted
+ */
+#define GST_GL_COLOR_CONVERT_FORMATS "{ RGB, RGBx, RGBA, BGR, BGRx, BGRA, xRGB, " \
+                               "xBGR, ARGB, ABGR, Y444, I420, YV12, Y42B, " \
+                               "Y41B, NV12, NV21, YUY2, UYVY, AYUV, " \
+                               "GRAY8, GRAY16_LE, GRAY16_BE }"
+
+/**
+ * GST_GL_COLOR_CONVERT_VIDEO_CAPS:
+ *
+ * The currently supported #GstCaps that can be converted
+ */
+#define GST_GL_COLOR_CONVERT_VIDEO_CAPS GST_VIDEO_CAPS_MAKE (GST_GL_COLOR_CONVERT_FORMATS)
+
+GstGLColorConvert * gst_gl_color_convert_new (GstGLContext * context);
+
+gboolean gst_gl_color_convert_init_format    (GstGLColorConvert * convert,
+                                              GstVideoInfo in_info,
+                                              GstVideoInfo out_info);
+
+void     gst_gl_color_convert_set_texture_scaling (GstGLColorConvert * convert,
+                                                   gfloat scaling[GST_VIDEO_MAX_PLANES][2]);
+
+gboolean gst_gl_color_convert_perform        (GstGLColorConvert * convert,
+                                              guint in_tex[GST_VIDEO_MAX_PLANES],
+                                              guint out_tex[GST_VIDEO_MAX_PLANES]);
+
+G_END_DECLS
+
+#endif /* __GST_GL_COLOR_CONVERT_H__ */
index 425747df5e7ef4301c03f991ff50e484a456a789..a20bc41a2225318b33993ef421dbfea1bbaae160 100644 (file)
 
 static void _do_download (GstGLContext * context, GstGLDownload * download);
 static void _init_download (GstGLContext * context, GstGLDownload * download);
-static gboolean _init_download_shader (GstGLContext * context,
-    GstGLDownload * download);
 static gboolean _gst_gl_download_perform_with_data_unlocked (GstGLDownload *
     download, GLuint texture_id, gpointer data[GST_VIDEO_MAX_PLANES]);
 
-#if GST_GL_HAVE_OPENGL
-static void _do_download_draw_rgb_opengl (GstGLContext * context,
-    GstGLDownload * download);
-static void _do_download_draw_yuv_opengl (GstGLContext * context,
-    GstGLDownload * download);
-#endif
-#if GST_GL_HAVE_GLES2
-static void _do_download_draw_rgb_gles2 (GstGLContext * context,
-    GstGLDownload * download);
-static void _do_download_draw_yuv_gles2 (GstGLContext * context,
-    GstGLDownload * download);
-#endif
-
-/* *INDENT-OFF* */
-
-/* FIXME: use the colormatrix support from videoconvert */
-
-#define RGB_TO_YUV_COEFFICIENTS \
-      "uniform vec3 offset;\n" \
-      "uniform vec3 ycoeff;\n" \
-      "uniform vec3 ucoeff;\n" \
-      "uniform vec3 vcoeff;\n"
-
-/* Matrix inverses of the color matrices found in gstglupload */
-/* BT. 601 standard with the following ranges:
- * Y = [16..235] (of 255)
- * Cb/Cr = [16..240] (of 255)
- */
-static const gfloat bt601_offset[] = {0.0625, 0.5, 0.5};
-static const gfloat bt601_ycoeff[] = {0.256816, 0.504154, 0.0979137};
-static const gfloat bt601_ucoeff[] = {-0.148246, -0.29102, 0.439266};
-static const gfloat bt601_vcoeff[] = {0.439271, -0.367833, -0.071438};
-
-/* BT. 709 standard with the following ranges:
- * Y = [16..235] (of 255)
- * Cb/Cr = [16..240] (of 255)
- */
-static const gfloat bt709_offset[] = {0.0625, 0.5, 0.5};
-static const gfloat bt709_ycoeff[] = {0.213392, 0.718140,-0.072426};
-static const gfloat bt709_ucoeff[] = {0.117608, 0.395793,-0.513401};
-static const gfloat bt709_vcoeff[] = {0.420599,-0.467775, 0.047176};
-
-#if GST_GL_HAVE_OPENGL
-/* YUY2:y2,u,y1,v
-   UYVY:v,y1,u,y2 */
-static const gchar *text_shader_YUY2_UYVY_opengl =
-    "uniform sampler2D tex;\n"
-    "uniform float width;\n"
-    RGB_TO_YUV_COEFFICIENTS
-    "void main(void) {\n"
-    "  vec3 rgb1, rgb2;\n"
-    "  float fx,fy,y1,y2,u,v;\n"
-    "  fx = gl_TexCoord[0].x;\n"
-    "  fy = gl_TexCoord[0].y;\n"
-    "  rgb1=texture2D(tex,vec2(fx*2.0,fy)).rgb;\n"
-    "  rgb2=texture2D(tex,vec2(fx*2.0+1.0/width,fy)).rgb;\n"
-    "  y1=dot(rgb1, ycoeff);\n"
-    "  y2=dot(rgb2, ycoeff);\n"
-    "  u=dot(rgb1, ucoeff);\n"
-    "  v=dot(rgb1, vcoeff);\n"
-    "  y1+=offset.x;\n"
-    "  y2+=offset.x;\n"
-    "  u+=offset.y;\n"
-    "  v+=offset.z;\n"
-    "  gl_FragColor=vec4(%s);\n"
-    "}\n";
-
-static const gchar *text_shader_I420_YV12_opengl =
-    "uniform sampler2D tex;\n"
-    "uniform float w, h;\n"
-    RGB_TO_YUV_COEFFICIENTS
-    "void main(void) {\n"
-    "  vec3 rgb1, rgb2;\n"
-    "  float y,u,v;\n"
-    "  vec2 nxy=gl_TexCoord[0].xy;\n"
-    "  vec2 nxy2=nxy*2.0;\n"
-    "  rgb1=texture2D(tex,nxy).rgb;\n"
-    "  rgb2=texture2D(tex,nxy2).rgb;\n"
-    "  y=dot(rgb1, ycoeff);\n"
-    "  u=dot(rgb2, ucoeff);\n"
-    "  v=dot(rgb2, vcoeff);\n"
-    "  y+=offset.x;\n"
-    "  u+=offset.y;\n"
-    "  v+=offset.z;\n"
-    "  gl_FragData[0] = vec4(y, 0.0, 0.0, 1.0);\n"
-    "  gl_FragData[1] = vec4(u, 0.0, 0.0, 1.0);\n"
-    "  gl_FragData[2] = vec4(v, 0.0, 0.0, 1.0);\n"
-    "}\n";
-
-static const gchar *text_shader_AYUV_opengl =
-    "uniform sampler2D tex;\n"
-    RGB_TO_YUV_COEFFICIENTS
-    "void main(void) {\n"
-    "  vec3 rgb;\n"
-    "  float y,u,v;\n"
-    "  vec2 nxy=gl_TexCoord[0].xy;\n"
-    "  rgb=texture2D(tex,nxy).rgb;\n"
-    "  y=dot(rgb, ycoeff);\n"
-    "  u=dot(rgb, ucoeff);\n"
-    "  v=dot(rgb, vcoeff);\n"
-    "  y+=offset.x;\n"
-    "  u+=offset.y;\n"
-    "  v+=offset.z;\n"
-    "  gl_FragColor=vec4(y,u,v,1.0);\n"
-    "}\n";
-
-#define text_vertex_shader_opengl NULL
-#endif /* GST_GL_HAVE_OPENGL */
-
-#if GST_GL_HAVE_GLES2
-static const gchar *text_shader_YUY2_UYVY_gles2 =
-    "precision mediump float;\n"
-    "varying vec2 v_texCoord;\n"
-    "uniform sampler2D tex;\n"
-    RGB_TO_YUV_COEFFICIENTS
-    "void main(void) {\n"
-    "  vec3 rgb1, rgb2;\n"
-    "  float fx,fy,y1,y2,u,v;\n"
-    "  fx = v_texCoord.x;\n"
-    "  fy = v_texCoord.y;\n"
-    "  rgb1=texture2D(tex,vec2(fx*2.0,fy)).rgb;\n"
-    "  rgb2=texture2D(tex,vec2(fx*2.0+1.0,fy)).rgb;\n"
-    "  y1=dot(rgb1, ycoeff);\n"
-    "  y2=dot(rgb2, ycoeff);\n"
-    "  u=dot(rgb1, ucoeff);\n"
-    "  v=dot(rgb1, vcoeff);\n"
-    "  y1+=offset.x;\n"
-    "  y2+=offset.x;\n"
-    "  u+=offset.y;\n"
-    "  v+=offset.z;\n"
-    "  gl_FragColor=vec4(%s);\n"
-    "}\n";
-
-/* no OpenGL ES 2.0 support because for now it's not possible
- * to attach multiple textures to a frame buffer object
- */
-#define text_shader_I420_YV12_gles2 NULL
-
-static const gchar *text_shader_AYUV_gles2 =
-    "precision mediump float;\n"
-    "varying vec2 v_texCoord;\n"
-    "uniform sampler2D tex;\n"
-    RGB_TO_YUV_COEFFICIENTS
-    "void main(void) {\n"
-    "  vec3 rgb;\n"
-    "  float y,u,v;\n"
-    "  vec2 nxy=v_texCoord.xy;\n"
-    "  rgb=texture2D(tex,nxy).rgb;\n"
-    "  y=dot(rgb, ycoeff);\n"
-    "  u=dot(rgb, ucoeff);\n"
-    "  v=dot(rgb, vcoeff);\n"
-    "  y+=offset.x;\n"
-    "  u+=offset.y;\n"
-    "  v+=offset.z;\n"
-    "  gl_FragColor=vec4(1.0,y,u,v);\n"
-    "}\n";
-
-static const gchar *text_shader_ARGB_gles2 =
-    "precision mediump float;\n"
-    "varying vec2 v_texCoord;\n"
-    "uniform sampler2D tex;\n"
-    "void main(void) {\n"
-    "  vec4 rgba;\n"
-    "  vec2 nxy = v_texCoord.xy;\n"
-    "  rgba.rgb=texture2D(tex,nxy).rgb;\n"
-    "  rgba.a = 1.0;\n"
-    "  gl_FragColor=vec4(rgba.%c,rgba.%c,rgba.%c,rgba.%c);\n"
-    "}\n";
-
-static const gchar *text_vertex_shader_gles2 =
-    "attribute vec4 a_position;   \n"
-    "attribute vec2 a_texCoord;   \n"
-    "varying vec2 v_texCoord;     \n"
-    "void main()                  \n"
-    "{                            \n"
-    "   gl_Position = a_position; \n"
-    "   v_texCoord = a_texCoord;  \n"
-    "}                            \n";
-
-static const gchar *text_shader_RGB_gles2 =
-    "precision mediump float;                            \n"
-    "varying vec2 v_texCoord;                            \n"
-    "uniform sampler2D tex;                              \n"
-    "void main()                                         \n"
-    "{                                                   \n"
-    "  gl_FragColor = texture2D(tex, v_texCoord );       \n"
-    "}                                                   \n";
-#endif /* GST_GL_HAVE_GLES2 */
-
 /* *INDENT-ON* */
 
 struct _GstGLDownloadPrivate
@@ -249,9 +58,6 @@ struct _GstGLDownloadPrivate
   const gchar *ARGB;
   const gchar *vert_shader;
 
-  void (*do_rgb) (GstGLContext * context, GstGLDownload * download);
-  void (*do_yuv) (GstGLContext * context, GstGLDownload * download);
-
   gboolean result;
 };
 
@@ -282,18 +88,8 @@ gst_gl_download_init (GstGLDownload * download)
 
   download->priv = GST_GL_DOWNLOAD_GET_PRIVATE (download);
 
-  download->context = NULL;
-
   g_mutex_init (&download->lock);
 
-  download->fbo = 0;
-  download->depth_buffer = 0;
-  download->in_texture = 0;
-  download->shader = NULL;
-
-  download->shader_attr_position_loc = 0;
-  download->shader_attr_texture_loc = 0;
-
   gst_video_info_init (&download->info);
 }
 
@@ -307,35 +103,11 @@ GstGLDownload *
 gst_gl_download_new (GstGLContext * context)
 {
   GstGLDownload *download;
-  GstGLDownloadPrivate *priv;
 
   download = g_object_new (GST_TYPE_GL_DOWNLOAD, NULL);
 
   download->context = gst_object_ref (context);
-  priv = download->priv;
-
-#if GST_GL_HAVE_OPENGL
-  if (USING_OPENGL (context)) {
-    priv->YUY2_UYVY = text_shader_YUY2_UYVY_opengl;
-    priv->I420_YV12 = text_shader_I420_YV12_opengl;
-    priv->AYUV = text_shader_AYUV_opengl;
-    priv->ARGB = NULL;
-    priv->vert_shader = text_vertex_shader_opengl;
-    priv->do_rgb = _do_download_draw_rgb_opengl;
-    priv->do_yuv = _do_download_draw_yuv_opengl;
-  }
-#endif
-#if GST_GL_HAVE_GLES2
-  if (USING_GLES2 (context)) {
-    priv->YUY2_UYVY = text_shader_YUY2_UYVY_gles2;
-    priv->I420_YV12 = text_shader_I420_YV12_gles2;
-    priv->AYUV = text_shader_AYUV_gles2;
-    priv->ARGB = text_shader_ARGB_gles2;
-    priv->vert_shader = text_vertex_shader_gles2;
-    priv->do_rgb = _do_download_draw_rgb_gles2;
-    priv->do_yuv = _do_download_draw_yuv_gles2;
-  }
-#endif
+  download->convert = gst_gl_color_convert_new (context);
 
   return download;
 }
@@ -359,15 +131,9 @@ gst_gl_download_finalize (GObject * object)
     gst_gl_context_del_texture (download->context, &download->in_texture);
     download->in_texture = 0;
   }
-  if (download->fbo || download->depth_buffer) {
-    gst_gl_context_del_fbo (download->context, download->fbo,
-        download->depth_buffer);
-    download->fbo = 0;
-    download->depth_buffer = 0;
-  }
-  if (download->shader) {
-    gst_object_unref (download->shader);
-    download->shader = NULL;
+  if (download->convert) {
+    gst_object_unref (download->convert);
+    download->convert = NULL;
   }
 
   if (download->context) {
@@ -527,9 +293,10 @@ _gst_gl_download_perform_with_data_unlocked (GstGLDownload * download,
 static void
 _init_download (GstGLContext * context, GstGLDownload * download)
 {
-  GstGLFuncs *gl;
+  const GstGLFuncs *gl;
   GstVideoFormat v_format;
   guint out_width, out_height;
+  GstVideoInfo in_info;
 
   gl = context->gl_vtable;
   v_format = GST_VIDEO_INFO_FORMAT (&download->info);
@@ -539,733 +306,92 @@ _init_download (GstGLContext * context, GstGLDownload * download)
   GST_TRACE ("initializing texture download for format %s",
       gst_video_format_to_string (v_format));
 
-  if (USING_OPENGL (context)) {
-    switch (v_format) {
-      case GST_VIDEO_FORMAT_RGBx:
-      case GST_VIDEO_FORMAT_BGRx:
-      case GST_VIDEO_FORMAT_xRGB:
-      case GST_VIDEO_FORMAT_xBGR:
-      case GST_VIDEO_FORMAT_RGBA:
-      case GST_VIDEO_FORMAT_BGRA:
-      case GST_VIDEO_FORMAT_ARGB:
-      case GST_VIDEO_FORMAT_ABGR:
-      case GST_VIDEO_FORMAT_RGB:
-      case GST_VIDEO_FORMAT_BGR:
-        goto no_convert;
-        break;
-      default:
-        break;
-    }
-  }
-
-  switch (v_format) {
-    case GST_VIDEO_FORMAT_RGBx:
-    case GST_VIDEO_FORMAT_BGRx:
-    case GST_VIDEO_FORMAT_xRGB:
-    case GST_VIDEO_FORMAT_xBGR:
-    case GST_VIDEO_FORMAT_RGBA:
-    case GST_VIDEO_FORMAT_BGRA:
-    case GST_VIDEO_FORMAT_ARGB:
-    case GST_VIDEO_FORMAT_ABGR:
-    case GST_VIDEO_FORMAT_RGB:
-    case GST_VIDEO_FORMAT_BGR:
-    case GST_VIDEO_FORMAT_YUY2:
-    case GST_VIDEO_FORMAT_UYVY:
-    case GST_VIDEO_FORMAT_I420:
-    case GST_VIDEO_FORMAT_YV12:
-    case GST_VIDEO_FORMAT_AYUV:
-      /* color space conversion is needed */
-    {
-
-      if (!gl->GenFramebuffers) {
-        /* Frame buffer object is a requirement 
-         * when using GLSL colorspace conversion
-         */
-        gst_gl_context_set_error (context,
-            "Context, EXT_framebuffer_object supported: no");
-        goto error;
-      }
-      GST_INFO ("Context, EXT_framebuffer_object supported: yes");
-
-      /* setup FBO */
-      gl->GenFramebuffers (1, &download->fbo);
-      gl->BindFramebuffer (GL_FRAMEBUFFER, download->fbo);
-
-      /* setup the render buffer for depth */
-      gl->GenRenderbuffers (1, &download->depth_buffer);
-      gl->BindRenderbuffer (GL_RENDERBUFFER, download->depth_buffer);
-#if GST_GL_HAVE_OPENGL
-      if (USING_OPENGL (context)) {
-        gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT,
-            out_width, out_height);
-        gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH24_STENCIL8,
-            out_width, out_height);
-      }
-#endif
-#if GST_GL_HAVE_GLES2
-      if (USING_GLES2 (context)) {
-        gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
-            out_width, out_height);
-      }
-#endif
+  gst_video_info_set_format (&in_info, GST_VIDEO_FORMAT_RGBA, out_width,
+      out_height);
 
-      /* setup a first texture to render to */
-      gl->GenTextures (1, &download->out_texture[0]);
-      gl->BindTexture (GL_TEXTURE_2D, download->out_texture[0]);
-      gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8,
-          out_width, out_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-      gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-      gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-      gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-      gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
-      /* attach the first texture to the FBO to renderer to */
-      gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-          GL_TEXTURE_2D, download->out_texture[0], 0);
-
-      if (v_format == GST_VIDEO_FORMAT_I420 ||
-          v_format == GST_VIDEO_FORMAT_YV12) {
-        /* setup a second texture to render to */
-        gl->GenTextures (1, &download->out_texture[1]);
-        gl->BindTexture (GL_TEXTURE_2D, download->out_texture[1]);
-        gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8,
-            out_width, out_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-        gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-        gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-        gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
-        /* attach the second texture to the FBO to renderer to */
-        gl->FramebufferTexture2D (GL_FRAMEBUFFER,
-            GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, download->out_texture[1], 0);
-
-        /* setup a third texture to render to */
-        gl->GenTextures (1, &download->out_texture[2]);
-        gl->BindTexture (GL_TEXTURE_2D, download->out_texture[2]);
-        gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8,
-            out_width, out_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-        gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-        gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-        gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-        gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
-        /* attach the third texture to the FBO to renderer to */
-        gl->FramebufferTexture2D (GL_FRAMEBUFFER,
-            GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, download->out_texture[2], 0);
-      }
-
-      /* attach the depth render buffer to the FBO */
-      gl->FramebufferRenderbuffer (GL_FRAMEBUFFER,
-          GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, download->depth_buffer);
-      if (USING_OPENGL (context)) {
-        gl->FramebufferRenderbuffer (GL_FRAMEBUFFER,
-            GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, download->depth_buffer);
-      }
-
-      if (!gst_gl_context_check_framebuffer_status (context)) {
-        gst_gl_context_set_error (context, "GL framebuffer status incomplete");
-        goto error;
-      }
-
-      /* unbind the FBO */
-      gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
-    }
-      break;
-    default:
-      break;
-      gst_gl_context_set_error (context, "Unsupported download video format %d",
-          v_format);
-      g_assert_not_reached ();
-  }
-
-no_convert:
-  download->priv->result = _init_download_shader (context, download);
-  return;
-
-error:
-  {
-    download->priv->result = FALSE;
+  download->priv->result =
+      gst_gl_color_convert_init_format (download->convert, in_info,
+      download->info);
+  if (!download->priv->result)
     return;
-  }
-}
-
-static gboolean
-_create_shader (GstGLContext * context, const gchar * vertex_src,
-    const gchar * fragment_src, GstGLShader ** out_shader)
-{
-  GstGLShader *shader;
-  GError *error = NULL;
-
-  g_return_val_if_fail (vertex_src != NULL || fragment_src != NULL, FALSE);
-
-  shader = gst_gl_shader_new (context);
-
-  if (vertex_src)
-    gst_gl_shader_set_vertex_source (shader, vertex_src);
-  if (fragment_src)
-    gst_gl_shader_set_fragment_source (shader, fragment_src);
-
-  if (!gst_gl_shader_compile (shader, &error)) {
-    gst_gl_context_set_error (context, "%s", error->message);
-    g_error_free (error);
-    gst_gl_context_clear_shader (context);
-    gst_object_unref (shader);
-    return FALSE;
-  }
-
-  *out_shader = shader;
-  return TRUE;
-}
-
-static gboolean
-_init_download_shader (GstGLContext * context, GstGLDownload * download)
-{
-  GstGLFuncs *gl;
-  GstVideoFormat v_format;
 
-  gl = download->context->gl_vtable;
-  v_format = GST_VIDEO_INFO_FORMAT (&download->info);
-
-  if (GST_VIDEO_FORMAT_INFO_IS_RGB (download->info.finfo)
-      && !USING_GLES2 (context)) {
-    switch (v_format) {
-      case GST_VIDEO_FORMAT_RGBx:
-      case GST_VIDEO_FORMAT_BGRx:
-      case GST_VIDEO_FORMAT_xRGB:
-      case GST_VIDEO_FORMAT_xBGR:
-      case GST_VIDEO_FORMAT_RGBA:
-      case GST_VIDEO_FORMAT_BGRA:
-      case GST_VIDEO_FORMAT_ARGB:
-      case GST_VIDEO_FORMAT_ABGR:
-      case GST_VIDEO_FORMAT_RGB:
-      case GST_VIDEO_FORMAT_BGR:
-        return TRUE;
-        break;
-      default:
-        break;
+  if (USING_GLES2 (context) && !USING_GLES3 (context)) {
+    /* GL_RGBA is the only officially supported texture format in GLES2 */
+    if (v_format == GST_VIDEO_FORMAT_RGB || v_format == GST_VIDEO_FORMAT_BGR) {
+      download->priv->result = FALSE;
+      return;
     }
   }
 
-  /* color space conversion is needed */
-
-  /* check if fragment shader is available, then load them
-   * GLSL is a requirement for download
-   */
-  if (!gl->CreateProgramObject && !gl->CreateProgram) {
-    /* colorspace conversion is not possible */
-    gst_gl_context_set_error (context,
-        "Context, ARB_fragment_shader supported: no");
-    return FALSE;;
-  }
-
-  switch (v_format) {
-    case GST_VIDEO_FORMAT_YUY2:
-    {
-      gchar text_shader_download_YUY2[2048];
-
-      sprintf (text_shader_download_YUY2,
-          download->priv->YUY2_UYVY, "y2,u,y1,v");
-
-      if (_create_shader (context, download->priv->vert_shader,
-              text_shader_download_YUY2, &download->shader)) {
-        if (USING_GLES2 (context)) {
-          download->shader_attr_position_loc =
-              gst_gl_shader_get_attribute_location (download->shader,
-              "a_position");
-          download->shader_attr_texture_loc =
-              gst_gl_shader_get_attribute_location (download->shader,
-              "a_texCoord");
-        }
-      }
-    }
-      break;
-    case GST_VIDEO_FORMAT_UYVY:
-    {
-      gchar text_shader_download_UYVY[2048];
-
-      sprintf (text_shader_download_UYVY,
-          download->priv->YUY2_UYVY, "v,y1,u,y2");
-
-      if (_create_shader (context, download->priv->vert_shader,
-              text_shader_download_UYVY, &download->shader)) {
-        if (USING_GLES2 (context)) {
-          download->shader_attr_position_loc =
-              gst_gl_shader_get_attribute_location (download->shader,
-              "a_position");
-          download->shader_attr_texture_loc =
-              gst_gl_shader_get_attribute_location (download->shader,
-              "a_texCoord");
-        }
-      }
-    }
-      break;
-    case GST_VIDEO_FORMAT_I420:
-    case GST_VIDEO_FORMAT_YV12:
-    {
-      _create_shader (context, download->priv->vert_shader,
-          download->priv->I420_YV12, &download->shader);
-      break;
-    }
-    case GST_VIDEO_FORMAT_AYUV:
-    {
-      if (_create_shader (context, download->priv->vert_shader,
-              download->priv->AYUV, &download->shader)) {
-        if (USING_GLES2 (context)) {
-          download->shader_attr_position_loc =
-              gst_gl_shader_get_attribute_location (download->shader,
-              "a_position");
-          download->shader_attr_texture_loc =
-              gst_gl_shader_get_attribute_location (download->shader,
-              "a_texCoord");
-        }
-      }
-      break;
-    }
-    case GST_VIDEO_FORMAT_RGBx:
-    case GST_VIDEO_FORMAT_BGRx:
-    case GST_VIDEO_FORMAT_xRGB:
-    case GST_VIDEO_FORMAT_xBGR:
-    case GST_VIDEO_FORMAT_RGBA:
-    case GST_VIDEO_FORMAT_BGRA:
-    case GST_VIDEO_FORMAT_ARGB:
-    case GST_VIDEO_FORMAT_ABGR:
-    case GST_VIDEO_FORMAT_RGB:
-    case GST_VIDEO_FORMAT_BGR:
-#if GST_GL_HAVE_GLES2
-    {
-      gchar text_shader_ARGB[2048];
-
-      switch (v_format) {
-        case GST_VIDEO_FORMAT_BGR:
-        case GST_VIDEO_FORMAT_BGRx:
-        case GST_VIDEO_FORMAT_BGRA:
-          sprintf (text_shader_ARGB, download->priv->ARGB, 'b', 'g', 'r', 'a');
-          break;
-        case GST_VIDEO_FORMAT_xRGB:
-        case GST_VIDEO_FORMAT_ARGB:
-          sprintf (text_shader_ARGB, download->priv->ARGB, 'a', 'r', 'g', 'b');
-          break;
-        case GST_VIDEO_FORMAT_xBGR:
-        case GST_VIDEO_FORMAT_ABGR:
-          sprintf (text_shader_ARGB, download->priv->ARGB, 'a', 'b', 'g', 'r');
-          break;
-        default:
-          memcpy (text_shader_ARGB, text_shader_RGB_gles2,
-              strlen (text_shader_RGB_gles2) + 1);
-          break;
-      }
-
-      if (_create_shader (context, download->priv->vert_shader,
-              text_shader_ARGB, &download->shader)) {
-        download->shader_attr_position_loc =
-            gst_gl_shader_get_attribute_location (download->shader,
-            "a_position");
-        download->shader_attr_texture_loc =
-            gst_gl_shader_get_attribute_location (download->shader,
-            "a_texCoord");
-      }
-      break;
-    }
-#else
-      g_assert_not_reached ();
-      return FALSE;
-      break;
-#endif
-    default:
-      gst_gl_context_set_error (context,
-          "Unsupported download video format %d", v_format);
-      g_assert_not_reached ();
-      return FALSE;
-      break;
-  }
-
-  return TRUE;
-}
-
-/* Called in the gl thread */
-static void
-_do_download (GstGLContext * context, GstGLDownload * download)
-{
-  GstVideoFormat v_format;
-  guint out_width, out_height;
-
-  v_format = GST_VIDEO_INFO_FORMAT (&download->info);
-  out_width = GST_VIDEO_INFO_WIDTH (&download->info);
-  out_height = GST_VIDEO_INFO_HEIGHT (&download->info);
-
-  GST_TRACE ("downloading texture:%u format:%d, dimensions:%ux%u",
-      download->in_texture, v_format, out_width, out_height);
-
-  switch (v_format) {
-    case GST_VIDEO_FORMAT_RGBx:
-    case GST_VIDEO_FORMAT_BGRx:
-    case GST_VIDEO_FORMAT_xRGB:
-    case GST_VIDEO_FORMAT_xBGR:
-    case GST_VIDEO_FORMAT_RGBA:
-    case GST_VIDEO_FORMAT_BGRA:
-    case GST_VIDEO_FORMAT_ARGB:
-    case GST_VIDEO_FORMAT_ABGR:
-    case GST_VIDEO_FORMAT_RGB:
-    case GST_VIDEO_FORMAT_BGR:
-      /* color space conversion is not needed */
-      download->priv->do_rgb (context, download);
-      break;
-    case GST_VIDEO_FORMAT_YUY2:
-    case GST_VIDEO_FORMAT_UYVY:
-    case GST_VIDEO_FORMAT_I420:
-    case GST_VIDEO_FORMAT_YV12:
-    case GST_VIDEO_FORMAT_AYUV:
-      /* color space conversion is needed */
-      download->priv->do_yuv (context, download);
-      break;
-    default:
-      gst_gl_context_set_error (context, "Unsupported download video format %d",
-          v_format);
-      g_assert_not_reached ();
-      break;
+  gl->GenTextures (1, &download->out_texture[0]);
+  gl->BindTexture (GL_TEXTURE_2D, download->out_texture[0]);
+  gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8,
+      out_width, out_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+  gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+  gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+  gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+  gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+  if (v_format == GST_VIDEO_FORMAT_I420 || v_format == GST_VIDEO_FORMAT_YV12) {
+    /* setup a second texture to render to */
+    gl->GenTextures (1, &download->out_texture[1]);
+    gl->BindTexture (GL_TEXTURE_2D, download->out_texture[1]);
+    gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8,
+        out_width, out_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+    gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+    /* setup a third texture to render to */
+    gl->GenTextures (1, &download->out_texture[2]);
+    gl->BindTexture (GL_TEXTURE_2D, download->out_texture[2]);
+    gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8,
+        out_width, out_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+    gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
   }
 
   download->priv->result = TRUE;
 }
 
-#if GST_GL_HAVE_OPENGL
 static void
-_do_download_draw_rgb_opengl (GstGLContext * context, GstGLDownload * download)
-{
-  GstGLFuncs *gl;
-  GstVideoFormat v_format;
-
-  gl = download->context->gl_vtable;
-
-  gst_gl_context_clear_shader (context);
-
-  gl->Enable (GL_TEXTURE_2D);
-  gl->BindTexture (GL_TEXTURE_2D, download->in_texture);
-
-  v_format = GST_VIDEO_INFO_FORMAT (&download->info);
-
-  switch (v_format) {
-    case GST_VIDEO_FORMAT_RGBA:
-    case GST_VIDEO_FORMAT_RGBx:
-      gl->GetTexImage (GL_TEXTURE_2D, 0, GL_RGBA,
-          GL_UNSIGNED_BYTE, download->data[0]);
-      break;
-    case GST_VIDEO_FORMAT_xRGB:
-    case GST_VIDEO_FORMAT_ARGB:
-#if G_BYTE_ORDER == G_LITTLE_ENDIAN
-      gl->GetTexImage (GL_TEXTURE_2D, 0, GL_BGRA,
-          GL_UNSIGNED_INT_8_8_8_8, download->data[0]);
-#else
-      gl->GetTexImage (GL_TEXTURE_2D, 0, GL_BGRA,
-          GL_UNSIGNED_INT_8_8_8_8_REV, download->data[0]);
-#endif /* G_BYTE_ORDER */
-      break;
-    case GST_VIDEO_FORMAT_BGRx:
-    case GST_VIDEO_FORMAT_BGRA:
-      gl->GetTexImage (GL_TEXTURE_2D, 0, GL_BGRA,
-          GL_UNSIGNED_BYTE, download->data[0]);
-      break;
-    case GST_VIDEO_FORMAT_xBGR:
-    case GST_VIDEO_FORMAT_ABGR:
-#if G_BYTE_ORDER == G_LITTLE_ENDIAN
-      gl->GetTexImage (GL_TEXTURE_2D, 0, GL_RGBA,
-          GL_UNSIGNED_INT_8_8_8_8, download->data[0]);
-#else
-      glGetTexImage (GL_TEXTURE_2D, 0, GL_RGBA,
-          GL_UNSIGNED_INT_8_8_8_8_REV, download->data[0]);
-#endif /* G_BYTE_ORDER */
-      break;
-    case GST_VIDEO_FORMAT_RGB:
-      gl->GetTexImage (GL_TEXTURE_2D, 0, GL_RGB,
-          GL_UNSIGNED_BYTE, download->data[0]);
-      break;
-    case GST_VIDEO_FORMAT_BGR:
-      gl->GetTexImage (GL_TEXTURE_2D, 0, GL_BGR,
-          GL_UNSIGNED_BYTE, download->data[0]);
-      break;
-    default:
-      gst_gl_context_set_error (context,
-          "Download video format inconsistency %d", v_format);
-      g_assert_not_reached ();
-      break;
-  }
-
-  gl->Disable (GL_TEXTURE_2D);
-}
-#endif
-
-
-#if GST_GL_HAVE_GLES2
-static void
-_do_download_draw_rgb_gles2 (GstGLContext * context, GstGLDownload * download)
+_do_download (GstGLContext * context, GstGLDownload * download)
 {
   GstGLFuncs *gl;
   GstVideoFormat v_format;
   guint out_width, out_height;
+  guint in_tex[] = { download->in_texture, 0, 0, 0 };
 
-  GLint viewport_dim[4];
-
-  const GLfloat vVertices[] = { 1.0f, -1.0f, 0.0f,
-    1.0f, 0.0f,
-    -1.0f, -1.0f, 0.0f,
-    0.0f, 0.0f,
-    -1.0f, 1.0f, 0.0f,
-    0.0f, 1.0f,
-    1.0f, 1.0f, 0.0f,
-    1.0f, 1.0f
-  };
-
-  GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
-
-  gl = download->context->gl_vtable;
+  gl = context->gl_vtable;
 
   out_width = GST_VIDEO_INFO_WIDTH (&download->info);
   out_height = GST_VIDEO_INFO_HEIGHT (&download->info);
-
-  gst_gl_context_check_framebuffer_status (context);
-  gl->BindFramebuffer (GL_FRAMEBUFFER, download->fbo);
-
-  gl->GetIntegerv (GL_VIEWPORT, viewport_dim);
-
-  gl->Viewport (0, 0, out_width, out_height);
-
-  gl->ClearColor (0.0, 0.0, 0.0, 0.0);
-  gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
-  gst_gl_shader_use (download->shader);
-
-  gl->VertexAttribPointer (download->shader_attr_position_loc, 3,
-      GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), vVertices);
-  gl->VertexAttribPointer (download->shader_attr_texture_loc, 2,
-      GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), &vVertices[3]);
-
-  gl->EnableVertexAttribArray (download->shader_attr_position_loc);
-  gl->EnableVertexAttribArray (download->shader_attr_texture_loc);
-
-  gl->ActiveTexture (GL_TEXTURE0);
-  gst_gl_shader_set_uniform_1i (download->shader, "tex", 0);
-  gl->BindTexture (GL_TEXTURE_2D, download->in_texture);
-
-  gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
-
-  gst_gl_context_clear_shader (context);
-
-  gl->Viewport (viewport_dim[0], viewport_dim[1], viewport_dim[2],
-      viewport_dim[3]);
-
   v_format = GST_VIDEO_INFO_FORMAT (&download->info);
 
-  switch (v_format) {
-    case GST_VIDEO_FORMAT_RGBA:
-    case GST_VIDEO_FORMAT_RGBx:
-    case GST_VIDEO_FORMAT_xRGB:
-    case GST_VIDEO_FORMAT_ARGB:
-    case GST_VIDEO_FORMAT_BGRx:
-    case GST_VIDEO_FORMAT_BGRA:
-    case GST_VIDEO_FORMAT_xBGR:
-    case GST_VIDEO_FORMAT_ABGR:
-      gl->ReadPixels (0, 0, out_width, out_height, GL_RGBA, GL_UNSIGNED_BYTE,
-          download->data[0]);
-      break;
-    case GST_VIDEO_FORMAT_RGB:
-    case GST_VIDEO_FORMAT_BGR:
-      gl->ReadPixels (0, 0, out_width, out_height, GL_RGB, GL_UNSIGNED_BYTE,
-          download->data[0]);
-      break;
-    default:
-      gst_gl_context_set_error (context,
-          "Download video format inconsistency %d", v_format);
-      g_assert_not_reached ();
-      break;
-  }
-
-  gst_gl_context_check_framebuffer_status (context);
-  gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
-}
-#endif
-
-#if GST_GL_HAVE_OPENGL
-static void
-_do_download_draw_yuv_opengl (GstGLContext * context, GstGLDownload * download)
-{
-  GstGLFuncs *gl;
-  GstVideoFormat v_format;
-  guint out_width = GST_VIDEO_INFO_WIDTH (&download->info);
-  guint out_height = GST_VIDEO_INFO_HEIGHT (&download->info);
-  const gfloat *cms_offset;
-  const gfloat *cms_ycoeff;
-  const gfloat *cms_ucoeff;
-  const gfloat *cms_vcoeff;
-
-  GLenum multipleRT[] = {
-    GL_COLOR_ATTACHMENT0,
-    GL_COLOR_ATTACHMENT1,
-    GL_COLOR_ATTACHMENT2
-  };
-
-  gfloat verts[8] = { 1.0f, -1.0f,
-    -1.0f, -1.0f,
-    -1.0f, 1.0f,
-    1.0f, 1.0f
-  };
-  gfloat texcoords[8] = { 1.0, 0.0,
-    0.0, 0.0,
-    0.0, 1.0,
-    1.0, 1.0
-  };
-
-  gl = context->gl_vtable;
-
-  v_format = GST_VIDEO_INFO_FORMAT (&download->info);
-
-  GST_TRACE ("doing YUV download of texture:%u (%ux%u) using fbo:%u",
-      download->in_texture, out_width, out_height, download->fbo);
-
-  gl->BindFramebuffer (GL_FRAMEBUFFER, download->fbo);
-
-  gl->PushAttrib (GL_VIEWPORT_BIT);
+  GST_TRACE ("doing YUV download of texture:%u (%ux%u)",
+      download->in_texture, out_width, out_height);
 
-  gl->MatrixMode (GL_PROJECTION);
-  gl->PushMatrix ();
-  gl->LoadIdentity ();
-  gluOrtho2D (0.0, out_width, 0.0, out_height);
-
-  gl->MatrixMode (GL_MODELVIEW);
-  gl->PushMatrix ();
-  gl->LoadIdentity ();
-
-  gl->Viewport (0, 0, out_width, out_height);
-
-  switch (v_format) {
-    case GST_VIDEO_FORMAT_YUY2:
-    case GST_VIDEO_FORMAT_UYVY:
-    case GST_VIDEO_FORMAT_AYUV:
-    {
-      gl->DrawBuffer (GL_COLOR_ATTACHMENT0);
-
-      gl->ClearColor (0.0, 0.0, 0.0, 0.0);
-      gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
-      gst_gl_shader_use (download->shader);
-
-      gl->MatrixMode (GL_PROJECTION);
-      gl->LoadIdentity ();
-
-      gl->ActiveTexture (GL_TEXTURE0);
-      gst_gl_shader_set_uniform_1i (download->shader, "tex", 0);
-      gst_gl_shader_set_uniform_1f (download->shader, "width", out_width);
-      gl->BindTexture (GL_TEXTURE_2D, download->in_texture);
-    }
-      break;
-
-    case GST_VIDEO_FORMAT_I420:
-    case GST_VIDEO_FORMAT_YV12:
-    {
-      gl->DrawBuffers (3, multipleRT);
-
-      gl->ClearColor (0.0, 0.0, 0.0, 0.0);
-      gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
-      gst_gl_shader_use (download->shader);
-
-      gl->MatrixMode (GL_PROJECTION);
-      gl->LoadIdentity ();
-
-      gl->ActiveTexture (GL_TEXTURE0);
-      gst_gl_shader_set_uniform_1i (download->shader, "tex", 0);
-      gst_gl_shader_set_uniform_1f (download->shader, "w", (gfloat) out_width);
-      gst_gl_shader_set_uniform_1f (download->shader, "h", (gfloat) out_height);
-      gl->BindTexture (GL_TEXTURE_2D, download->in_texture);
-    }
-      break;
-
-    default:
-      break;
-      gst_gl_context_set_error (context,
-          "Download video format inconsistensy %d", v_format);
-  }
-
-  if (gst_video_colorimetry_matches (&download->info.colorimetry,
-          GST_VIDEO_COLORIMETRY_BT709)) {
-    cms_offset = bt709_offset;
-    cms_ycoeff = bt709_ycoeff;
-    cms_ucoeff = bt709_ucoeff;
-    cms_vcoeff = bt709_vcoeff;
-  } else if (gst_video_colorimetry_matches (&download->info.colorimetry,
-          GST_VIDEO_COLORIMETRY_BT601)) {
-    cms_offset = bt601_offset;
-    cms_ycoeff = bt601_ycoeff;
-    cms_ucoeff = bt601_ucoeff;
-    cms_vcoeff = bt601_vcoeff;
-  } else {
-    /* defaults */
-    cms_offset = bt601_offset;
-    cms_ycoeff = bt601_ycoeff;
-    cms_ucoeff = bt601_ucoeff;
-    cms_vcoeff = bt601_vcoeff;
-  }
-
-  gst_gl_shader_set_uniform_3fv (download->shader, "offset", 1,
-      (gfloat *) cms_offset);
-  gst_gl_shader_set_uniform_3fv (download->shader, "ycoeff", 1,
-      (gfloat *) cms_ycoeff);
-  gst_gl_shader_set_uniform_3fv (download->shader, "ucoeff", 1,
-      (gfloat *) cms_ucoeff);
-  gst_gl_shader_set_uniform_3fv (download->shader, "vcoeff", 1,
-      (gfloat *) cms_vcoeff);
-
-  gl->ClientActiveTexture (GL_TEXTURE0);
-
-  gl->EnableClientState (GL_VERTEX_ARRAY);
-  gl->EnableClientState (GL_TEXTURE_COORD_ARRAY);
-
-  gl->VertexPointer (2, GL_FLOAT, 0, &verts);
-  gl->TexCoordPointer (2, GL_FLOAT, 0, &texcoords);
-
-  gl->DrawArrays (GL_QUADS, 0, 4);
-
-  gl->DisableClientState (GL_VERTEX_ARRAY);
-  gl->DisableClientState (GL_TEXTURE_COORD_ARRAY);
-
-  gl->DrawBuffer (GL_NONE);
-
-  /* don't check if GLSL is available
-   * because download yuv is not available
-   * without GLSL (whereas rgb is)
-   */
-  gl->UseProgramObject (0);
-
-  gl->Disable (GL_TEXTURE_2D);
-  gl->MatrixMode (GL_PROJECTION);
-  gl->PopMatrix ();
-  gl->MatrixMode (GL_MODELVIEW);
-  gl->PopMatrix ();
-  gl->PopAttrib ();
-
-  gst_gl_context_check_framebuffer_status (context);
+  download->priv->result =
+      gst_gl_color_convert_perform (download->convert, in_tex,
+      download->out_texture);
+  if (!download->priv->result)
+    return;
 
-  gl->BindFramebuffer (GL_FRAMEBUFFER, download->fbo);
+  gl->BindFramebuffer (GL_FRAMEBUFFER, download->convert->fbo);
   gl->ReadBuffer (GL_COLOR_ATTACHMENT0);
 
   switch (v_format) {
     case GST_VIDEO_FORMAT_AYUV:
-#if G_BYTE_ORDER == G_LITTLE_ENDIAN
-      gl->ReadPixels (0, 0, out_width, out_height, GL_BGRA,
-          GL_UNSIGNED_INT_8_8_8_8, download->data[0]);
-#else
-      gl->ReadPixels (0, 0, out_width, out_height, GL_BGRA,
-          GL_UNSIGNED_INT_8_8_8_8_REV, download->data[0]);
-#endif
+      gl->ReadPixels (0, 0, out_width, out_height, GL_RGBA,
+          GL_UNSIGNED_BYTE, download->data[0]);
       break;
     case GST_VIDEO_FORMAT_YUY2:
     case GST_VIDEO_FORMAT_UYVY:
-#if G_BYTE_ORDER == G_LITTLE_ENDIAN
-      gl->ReadPixels (0, 0, GST_ROUND_UP_2 (out_width) / 2, out_height, GL_BGRA,
-          GL_UNSIGNED_INT_8_8_8_8_REV, download->data[0]);
-#else
-      gl->ReadPixels (0, 0, GST_ROUND_UP_2 (out_width) / 2, out_height, GL_BGRA,
-          GL_UNSIGNED_INT_8_8_8_8, download->data[0]);
-#endif
+      gl->ReadPixels (0, 0, GST_ROUND_UP_2 (out_width) / 2, out_height, GL_RGBA,
+          GL_UNSIGNED_BYTE, download->data[0]);
       break;
     case GST_VIDEO_FORMAT_I420:
     {
@@ -1273,13 +399,11 @@ _do_download_draw_yuv_opengl (GstGLContext * context, GstGLDownload * download)
           GL_UNSIGNED_BYTE, download->data[0]);
 
       gl->ReadBuffer (GL_COLOR_ATTACHMENT1);
-
       gl->ReadPixels (0, 0, GST_ROUND_UP_2 (out_width) / 2,
           GST_ROUND_UP_2 (out_height) / 2, GL_LUMINANCE, GL_UNSIGNED_BYTE,
           download->data[1]);
 
       gl->ReadBuffer (GL_COLOR_ATTACHMENT2);
-
       gl->ReadPixels (0, 0, GST_ROUND_UP_2 (out_width) / 2,
           GST_ROUND_UP_2 (out_height) / 2, GL_LUMINANCE, GL_UNSIGNED_BYTE,
           download->data[2]);
@@ -1291,208 +415,31 @@ _do_download_draw_yuv_opengl (GstGLContext * context, GstGLDownload * download)
           GL_UNSIGNED_BYTE, download->data[0]);
 
       gl->ReadBuffer (GL_COLOR_ATTACHMENT1);
-
       gl->ReadPixels (0, 0, GST_ROUND_UP_2 (out_width) / 2,
           GST_ROUND_UP_2 (out_height) / 2, GL_LUMINANCE, GL_UNSIGNED_BYTE,
           download->data[2]);
 
       gl->ReadBuffer (GL_COLOR_ATTACHMENT2);
-
       gl->ReadPixels (0, 0, GST_ROUND_UP_2 (out_width) / 2,
           GST_ROUND_UP_2 (out_height) / 2, GL_LUMINANCE, GL_UNSIGNED_BYTE,
           download->data[1]);
     }
       break;
-    default:
-      break;
-      gst_gl_context_set_error (context,
-          "Download video format inconsistensy %d", v_format);
-      g_assert_not_reached ();
-  }
-  gl->ReadBuffer (GL_NONE);
-
-  gst_gl_context_check_framebuffer_status (context);
-
-  gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
-}
-#endif
-
-#if GST_GL_HAVE_GLES2
-static void
-_do_download_draw_yuv_gles2 (GstGLContext * context, GstGLDownload * download)
-{
-  GstGLFuncs *gl;
-  GstVideoFormat v_format;
-  guint out_width, out_height;
-  const gfloat *cms_offset;
-  const gfloat *cms_ycoeff;
-  const gfloat *cms_ucoeff;
-  const gfloat *cms_vcoeff;
-
-  GLint viewport_dim[4];
-
-  const GLfloat vVertices[] = { 1.0f, -1.0f, 0.0f,
-    1.0f, 0.0f,
-    -1.0f, -1.0f, 0.0f,
-    0.0f, .0f,
-    -1.0f, 1.0f, 0.0f,
-    0.0f, 1.0f,
-    1.0f, 1.0f, 0.0f,
-    1.0f, 1.0f
-  };
-
-  GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
-
-  gl = context->gl_vtable;
-
-  out_width = GST_VIDEO_INFO_WIDTH (&download->info);
-  out_height = GST_VIDEO_INFO_HEIGHT (&download->info);
-  v_format = GST_VIDEO_INFO_FORMAT (&download->info);
-
-  GST_TRACE ("doing YUV download of texture:%u (%ux%u) using fbo:%u",
-      download->in_texture, out_width, out_height, download->fbo);
-
-  gst_gl_context_check_framebuffer_status (context);
-  gl->BindFramebuffer (GL_FRAMEBUFFER, download->fbo);
-
-  gl->GetIntegerv (GL_VIEWPORT, viewport_dim);
-
-  gl->Viewport (0, 0, out_width, out_height);
-
-  switch (v_format) {
-    case GST_VIDEO_FORMAT_YUY2:
-    case GST_VIDEO_FORMAT_UYVY:
-    case GST_VIDEO_FORMAT_AYUV:
-    {
-      gl->ClearColor (0.0, 0.0, 0.0, 0.0);
-      gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
-      gst_gl_shader_use (download->shader);
-
-      gl->VertexAttribPointer (download->shader_attr_position_loc, 3,
-          GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), vVertices);
-      gl->VertexAttribPointer (download->shader_attr_texture_loc, 2,
-          GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), &vVertices[3]);
-
-      gl->EnableVertexAttribArray (download->shader_attr_position_loc);
-      gl->EnableVertexAttribArray (download->shader_attr_texture_loc);
-
-      gl->ActiveTexture (GL_TEXTURE0);
-      gst_gl_shader_set_uniform_1i (download->shader, "tex", 0);
-      gl->BindTexture (GL_TEXTURE_2D, download->in_texture);
-    }
-      break;
-
-    case GST_VIDEO_FORMAT_I420:
-    case GST_VIDEO_FORMAT_YV12:
-    {
-      gl->ClearColor (0.0, 0.0, 0.0, 0.0);
-      gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
-      gst_gl_shader_use (download->shader);
-
-      gl->ActiveTexture (GL_TEXTURE0);
-      gst_gl_shader_set_uniform_1i (download->shader, "tex", 0);
-      gst_gl_shader_set_uniform_1f (download->shader, "w", (gfloat) out_width);
-      gst_gl_shader_set_uniform_1f (download->shader, "h", (gfloat) out_height);
-      gl->BindTexture (GL_TEXTURE_2D, download->in_texture);
-    }
-      break;
-
-    default:
-      break;
-      gst_gl_context_set_error (context,
-          "Download video format inconsistensy %d", v_format);
-
-  }
-
-  if (gst_video_colorimetry_matches (&download->info.colorimetry,
-          GST_VIDEO_COLORIMETRY_BT709)) {
-    cms_offset = bt709_offset;
-    cms_ycoeff = bt709_ycoeff;
-    cms_ucoeff = bt709_ucoeff;
-    cms_vcoeff = bt709_vcoeff;
-  } else if (gst_video_colorimetry_matches (&download->info.colorimetry,
-          GST_VIDEO_COLORIMETRY_BT601)) {
-    cms_offset = bt601_offset;
-    cms_ycoeff = bt601_ycoeff;
-    cms_ucoeff = bt601_ucoeff;
-    cms_vcoeff = bt601_vcoeff;
-  } else {
-    /* defaults */
-    cms_offset = bt601_offset;
-    cms_ycoeff = bt601_ycoeff;
-    cms_ucoeff = bt601_ucoeff;
-    cms_vcoeff = bt601_vcoeff;
-  }
-
-  gst_gl_shader_set_uniform_3fv (download->shader, "offset", 1,
-      (gfloat *) cms_offset);
-  gst_gl_shader_set_uniform_3fv (download->shader, "ycoeff", 1,
-      (gfloat *) cms_ycoeff);
-  gst_gl_shader_set_uniform_3fv (download->shader, "ucoeff", 1,
-      (gfloat *) cms_ucoeff);
-  gst_gl_shader_set_uniform_3fv (download->shader, "vcoeff", 1,
-      (gfloat *) cms_vcoeff);
-
-  gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
-
-  /* don't check if GLSL is available
-   * because download yuv is not available
-   * without GLSL (whereas rgb is)
-   */
-  gst_gl_context_clear_shader (context);
-
-  gl->Viewport (viewport_dim[0], viewport_dim[1], viewport_dim[2],
-      viewport_dim[3]);
-
-  switch (v_format) {
-    case GST_VIDEO_FORMAT_AYUV:
-#if G_BYTE_ORDER == G_LITTLE_ENDIAN
-      gl->ReadPixels (0, 0, out_width, out_height, GL_BGRA,
-          GL_UNSIGNED_INT_8_8_8_8, download->data[0]);
-#else
-      gl->ReadPixels (0, 0, out_width, out_height, GL_BGRA,
-          GL_UNSIGNED_INT_8_8_8_8_REV, download->data[0]);
-#endif
-      break;
-    case GST_VIDEO_FORMAT_YUY2:
-    case GST_VIDEO_FORMAT_UYVY:
-#if G_BYTE_ORDER == G_LITTLE_ENDIAN
-      gl->ReadPixels (0, 0, GST_ROUND_UP_2 (out_width) / 2, out_height, GL_BGRA,
-          GL_UNSIGNED_INT_8_8_8_8_REV, download->data[0]);
-#else
-      gl->ReadPixels (0, 0, GST_ROUND_UP_2 (out_width) / 2, out_height, GL_BGRA,
-          GL_UNSIGNED_INT_8_8_8_8, download->data[0]);
-#endif
-      break;
-    case GST_VIDEO_FORMAT_I420:
-    {
-      gl->ReadPixels (0, 0, out_width, out_height, GL_LUMINANCE,
-          GL_UNSIGNED_BYTE, download->data[0]);
-
-      gl->ReadPixels (0, 0, GST_ROUND_UP_2 (out_width) / 2,
-          GST_ROUND_UP_2 (out_height) / 2, GL_LUMINANCE, GL_UNSIGNED_BYTE,
-          download->data[1]);
-
-      gl->ReadPixels (0, 0, GST_ROUND_UP_2 (out_width) / 2,
-          GST_ROUND_UP_2 (out_height) / 2, GL_LUMINANCE, GL_UNSIGNED_BYTE,
-          download->data[2]);
-    }
+    case GST_VIDEO_FORMAT_RGBA:
+    case GST_VIDEO_FORMAT_RGBx:
+    case GST_VIDEO_FORMAT_xRGB:
+    case GST_VIDEO_FORMAT_ARGB:
+    case GST_VIDEO_FORMAT_BGRx:
+    case GST_VIDEO_FORMAT_BGRA:
+    case GST_VIDEO_FORMAT_xBGR:
+    case GST_VIDEO_FORMAT_ABGR:
+      gl->ReadPixels (0, 0, out_width, out_height, GL_RGBA, GL_UNSIGNED_BYTE,
+          download->data[0]);
       break;
-    case GST_VIDEO_FORMAT_YV12:
-    {
-      gl->ReadPixels (0, 0, out_width, out_height, GL_LUMINANCE,
-          GL_UNSIGNED_BYTE, download->data[0]);
-
-      gl->ReadPixels (0, 0, GST_ROUND_UP_2 (out_width) / 2,
-          GST_ROUND_UP_2 (out_height) / 2, GL_LUMINANCE, GL_UNSIGNED_BYTE,
-          download->data[2]);
-
-      gl->ReadPixels (0, 0, GST_ROUND_UP_2 (out_width) / 2,
-          GST_ROUND_UP_2 (out_height) / 2, GL_LUMINANCE, GL_UNSIGNED_BYTE,
-          download->data[1]);
-    }
+    case GST_VIDEO_FORMAT_RGB:
+    case GST_VIDEO_FORMAT_BGR:
+      gl->ReadPixels (0, 0, out_width, out_height, GL_RGB, GL_UNSIGNED_BYTE,
+          download->data[0]);
       break;
     default:
       break;
@@ -1504,4 +451,3 @@ _do_download_draw_yuv_gles2 (GstGLContext * context, GstGLDownload * download)
   gst_gl_context_check_framebuffer_status (context);
   gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
 }
-#endif
index 5b6558c898ee9b1d96dfbb56c3325a3fce18c8bb..930bbafd13635f8f28e7c33f852557fa3004f42a 100644 (file)
@@ -49,6 +49,7 @@ struct _GstGLDownload
   GMutex           lock;
 
   GstGLContext     *context;
+  GstGLColorConvert *convert;
 
   /* output data */
   GstVideoInfo     info;
@@ -57,13 +58,8 @@ struct _GstGLDownload
   gboolean         initted;
 
   /* used for the conversion */
-  GLuint           fbo;
-  GLuint           depth_buffer;
   GLuint           in_texture;
   GLuint           out_texture[GST_VIDEO_MAX_PLANES];
-  GstGLShader     *shader;
-  GLint            shader_attr_position_loc;
-  GLint            shader_attr_texture_loc;
 
   GstGLDownloadPrivate *priv;
 
@@ -81,21 +77,6 @@ struct _GstGLDownloadClass
   GObjectClass object_class;
 };
 
-/**
- * GST_GL_DOWNLOAD_FORMATS:
- *
- * The currently supported formats that can be downloaded
- */
-# define GST_GL_DOWNLOAD_FORMATS "{ RGB, RGBx, RGBA, BGR, BGRx, BGRA, xRGB, " \
-                                 "xBGR, ARGB, ABGR, I420, YV12, YUY2, UYVY, AYUV }"
-
-/**
- * GST_GL_DOWNLOAD_VIDEO_CAPS:
- *
- * The currently supported #GstCaps that can be downloaded
- */
-#define GST_GL_DOWNLOAD_VIDEO_CAPS GST_VIDEO_CAPS_MAKE (GST_GL_DOWNLOAD_FORMATS)
-
 GstGLDownload * gst_gl_download_new          (GstGLContext * context);
 
 gboolean gst_gl_download_init_format                (GstGLDownload * download, GstVideoFormat v_format,
index 92bbf455f3ab5755d07434eec8f6284a99ac5043..bd4a9883d59f0ae55fe0fc7a75ccc6798fb625a8 100644 (file)
@@ -43,7 +43,7 @@ static GstStaticPadTemplate gst_gl_filter_src_pad_template =
         GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_EGL_IMAGE,
             "RGBA") "; "
 #endif
-        GST_VIDEO_CAPS_MAKE (GST_GL_DOWNLOAD_FORMATS) "; "
+        GST_VIDEO_CAPS_MAKE (GST_GL_COLOR_CONVERT_FORMATS) "; "
         GST_VIDEO_CAPS_MAKE_WITH_FEATURES
         (GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META,
             "RGBA"))
@@ -58,7 +58,7 @@ static GstStaticPadTemplate gst_gl_filter_sink_pad_template =
         GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_EGL_IMAGE,
             "RGBA") "; "
 #endif
-        GST_VIDEO_CAPS_MAKE (GST_GL_UPLOAD_FORMATS) "; "
+        GST_VIDEO_CAPS_MAKE (GST_GL_COLOR_CONVERT_FORMATS) "; "
         GST_VIDEO_CAPS_MAKE_WITH_FEATURES
         (GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META,
             "RGBA"))
index bab80161019c9da75d733fe98d4739c574509251..782a2bea3f8ac5254c8d8d0acce56135768d3084 100644 (file)
@@ -533,7 +533,7 @@ enum
 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_SRC,
     GST_PAD_ALWAYS,
-    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (GST_GL_DOWNLOAD_FORMATS) "; "
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (GST_GL_COLOR_CONVERT_FORMATS) "; "
         GST_VIDEO_CAPS_MAKE_WITH_FEATURES
         (GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META,
             "RGBA"))
@@ -542,7 +542,7 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink_%d",
     GST_PAD_SINK,
     GST_PAD_REQUEST,
-    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (GST_GL_UPLOAD_FORMATS) "; "
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (GST_GL_COLOR_CONVERT_FORMATS) "; "
         GST_VIDEO_CAPS_MAKE_WITH_FEATURES
         (GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META,
             "RGBA"))
index 667322cbc45a9e4e520ab6a7214b5a35abafb8ed..882928eb81c294fc3cdfca541831362103992dea 100644 (file)
@@ -47,13 +47,11 @@ static void _do_upload (GstGLContext * context, GstGLUpload * upload);
 static gboolean _do_upload_fill (GstGLContext * context, GstGLUpload * upload);
 static gboolean _do_upload_make (GstGLContext * context, GstGLUpload * upload);
 static void _init_upload (GstGLContext * context, GstGLUpload * upload);
-static gboolean _init_upload_fbo (GstGLContext * context, GstGLUpload * upload);
+//static gboolean _init_upload_fbo (GstGLContext * context, GstGLUpload * upload);
 static gboolean _gst_gl_upload_perform_with_data_unlocked (GstGLUpload * upload,
     GLuint texture_id, gpointer data[GST_VIDEO_MAX_PLANES]);
 static void _do_upload_with_meta (GstGLContext * context, GstGLUpload * upload);
 
-static gboolean _do_upload_draw (GstGLContext * context, GstGLUpload * upload);
-
 /* *INDENT-OFF* */
 
 #define YUV_TO_RGB_COEFFICIENTS \
@@ -63,206 +61,10 @@ static gboolean _do_upload_draw (GstGLContext * context, GstGLUpload * upload);
       "uniform vec3 bcoeff;\n"
 
 /* FIXME: use the colormatrix support from videoconvert */
-
-/* BT. 601 standard with the following ranges:
- * Y = [16..235] (of 255)
- * Cb/Cr = [16..240] (of 255)
- */
-static const gfloat bt601_offset[] = {-0.0625, -0.5, -0.5};
-static const gfloat bt601_rcoeff[] = {1.164, 0.000, 1.596};
-static const gfloat bt601_gcoeff[] = {1.164,-0.391,-0.813};
-static const gfloat bt601_bcoeff[] = {1.164, 2.018, 0.000};
-
-/* BT. 709 standard with the following ranges:
- * Y = [16..235] (of 255)
- * Cb/Cr = [16..240] (of 255)
- */
-static const gfloat bt709_offset[] = {-0.0625, -0.5, -0.5};
-static const gfloat bt709_rcoeff[] = {1.164, 0.000, 1.787};
-static const gfloat bt709_gcoeff[] = {1.164,-0.213,-0.531};
-static const gfloat bt709_bcoeff[] = {1.164,-2.112, 0.000};
-
-/** GRAY16 to RGB conversion 
- *  data transfered as GL_LUMINANCE_ALPHA then convert back to GRAY16 
- *  high byte weight as : 255*256/65535 
- *  ([0~1] denormalize to [0~255],shift to high byte,normalize to [0~1])
- *  low byte weight as : 255/65535 (similar)
- * */
-#define COMPOSE_WEIGHT \
-    "const vec2 compose_weight = vec2(0.996109, 0.003891);\n"
-
-/* Channel reordering for XYZ <-> ZYX conversion */
-static const char *frag_REORDER = {
-      "#ifdef GL_ES\n"
-      "precision mediump float;\n"
-      "#endif\n"
-      "varying vec2 v_texcoord;\n"
-      "uniform sampler2D tex;\n"
-      "uniform vec2 tex_scale0;\n"
-      "uniform vec2 tex_scale1;\n"
-      "uniform vec2 tex_scale2;\n"
-      "void main(void)\n"
-      "{\n"
-      " vec4 t = texture2D(tex, v_texcoord * tex_scale0);\n"
-      " gl_FragColor = vec4(t.%c, t.%c, t.%c, 1.0);\n"
-      "}"
-};
-
-/** GRAY16 to RGB conversion 
- *  data transfered as GL_LUMINANCE_ALPHA then convert back to GRAY16 
- *  high byte weight as : 255*256/65535 
- *  ([0~1] denormalize to [0~255],shift to high byte,normalize to [0~1])
- *  low byte weight as : 255/65535 (similar)
- * */
-static const char *frag_COMPOSE = {
-      "#ifdef GL_ES\n"
-      "precision mediump float;\n"
-      "#endif\n"
-      "varying vec2 v_texcoord;\n"
-      "uniform sampler2D tex;\n"
-      "uniform vec2 tex_scale0;\n"
-      "uniform vec2 tex_scale1;\n"
-      "uniform vec2 tex_scale2;\n"
-      COMPOSE_WEIGHT
-      "void main(void)\n"
-      "{\n"
-      " vec4 t = texture2D(tex, v_texcoord * tex_scale0);\n"
-      " float value = dot(t.%c%c, compose_weight);"
-      " gl_FragColor = vec4(value, value, value, 1.0);\n"
-      "}"
-
-};
-static const char *frag_AYUV = {
-      "#ifdef GL_ES\n"
-      "precision mediump float;\n"
-      "#endif\n"
-      "varying vec2 v_texcoord;\n"
-      "uniform sampler2D tex;\n"
-      "uniform vec2 tex_scale0;\n"
-      "uniform vec2 tex_scale1;\n"
-      "uniform vec2 tex_scale2;\n"
-      YUV_TO_RGB_COEFFICIENTS
-      "void main(void) {\n"
-      "  float r,g,b;\n"
-      "  vec3 yuv;\n"
-      "  yuv  = texture2D(tex,v_texcoord * tex_scale0).gba;\n"
-      "  yuv += offset;\n"
-      "  r = dot(yuv, rcoeff);\n"
-      "  g = dot(yuv, gcoeff);\n"
-      "  b = dot(yuv, bcoeff);\n"
-      "  gl_FragColor=vec4(r,g,b,1.0);\n"
-      "}"
-};
-
-/** YUV to RGB conversion */
-static const char *frag_PLANAR_YUV = {
-      "#ifdef GL_ES\n"
-      "precision mediump float;\n"
-      "#endif\n"
-      "varying vec2 v_texcoord;\n"
-      "uniform sampler2D Ytex,Utex,Vtex;\n"
-      "uniform vec2 tex_scale0;\n"
-      "uniform vec2 tex_scale1;\n"
-      "uniform vec2 tex_scale2;\n"
-      YUV_TO_RGB_COEFFICIENTS
-      "void main(void) {\n"
-      "  float r,g,b;\n"
-      "  vec3 yuv;\n"
-      "  yuv.x=texture2D(Ytex,v_texcoord * tex_scale0).r;\n"
-      "  yuv.y=texture2D(Utex,v_texcoord * tex_scale1).r;\n"
-      "  yuv.z=texture2D(Vtex,v_texcoord * tex_scale2).r;\n"
-      "  yuv += offset;\n"
-      "  r = dot(yuv, rcoeff);\n"
-      "  g = dot(yuv, gcoeff);\n"
-      "  b = dot(yuv, bcoeff);\n"
-      "  gl_FragColor=vec4(r,g,b,1.0);\n"
-      "}"
-};
-
-/** NV12/NV21 to RGB conversion */
-static const char *frag_NV12_NV21 = {
-      "#ifdef GL_ES\n"
-      "precision mediump float;\n"
-      "#endif\n"
-      "varying vec2 v_texcoord;\n"
-      "uniform sampler2D Ytex,UVtex;\n"
-      "uniform vec2 tex_scale0;\n"
-      "uniform vec2 tex_scale1;\n"
-      "uniform vec2 tex_scale2;\n"
-      YUV_TO_RGB_COEFFICIENTS
-      "void main(void) {\n"
-      "  float r,g,b;\n"
-      "  vec3 yuv;\n"
-      "  yuv.x=texture2D(Ytex, v_texcoord * tex_scale0).r;\n"
-      "  yuv.yz=texture2D(UVtex, v_texcoord * tex_scale1).%c%c;\n"
-      "  yuv += offset;\n"
-      "  r = dot(yuv, rcoeff);\n"
-      "  g = dot(yuv, gcoeff);\n"
-      "  b = dot(yuv, bcoeff);\n"
-      "  gl_FragColor=vec4(r,g,b,1.0);\n"
-      "}"
-};
-
-/* Direct fragments copy with stride-scaling */
-static const char *frag_COPY = {
-      "#ifdef GL_ES\n"
-      "precision mediump float;\n"
-      "#endif\n"
-      "varying vec2 v_texcoord;\n"
-      "uniform sampler2D tex;\n"
-      "uniform vec2 tex_scale0;\n"
-      "uniform vec2 tex_scale1;\n"
-      "uniform vec2 tex_scale2;\n"
-      "void main(void)\n"
-      "{\n"
-      " vec4 t = texture2D(tex, v_texcoord * tex_scale0);\n"
-      " gl_FragColor = vec4(t.rgb, 1.0);\n"
-      "}"
-};
-
-/* YUY2:r,g,a
-   UYVY:a,b,r */
-static const gchar *frag_YUY2_UYVY =
-    "#ifdef GL_ES\n"
-    "precision mediump float;\n"
-    "#endif\n"
-    "varying vec2 v_texcoord;\n"
-    "uniform sampler2D Ytex, UVtex;\n"
-    "uniform vec2 tex_scale0;\n"
-    "uniform vec2 tex_scale1;\n"
-    "uniform vec2 tex_scale2;\n"
-    YUV_TO_RGB_COEFFICIENTS
-    "void main(void) {\n"
-    "  vec3 yuv;\n"
-    "  float fx, fy, y, u, v, r, g, b;\n"
-    "  fx = v_texcoord.x;\n"
-    "  fy = v_texcoord.y;\n"
-    "  yuv.x = texture2D(Ytex,v_texcoord * tex_scale0).%c;\n"
-    "  yuv.yz = texture2D(UVtex,v_texcoord * tex_scale1).%c%c;\n"
-    "  yuv+=offset;\n"
-    "  r = dot(yuv, rcoeff);\n"
-    "  g = dot(yuv, gcoeff);\n"
-    "  b = dot(yuv, bcoeff);\n"
-    "  gl_FragColor = vec4(r, g, b, 1.0);\n"
-    "}\n";
-
-static const gchar *text_vertex_shader =
-    "attribute vec4 a_position;   \n"
-    "attribute vec2 a_texcoord;   \n"
-    "varying vec2 v_texcoord;     \n"
-    "void main()                  \n"
-    "{                            \n"
-    "   gl_Position = a_position; \n"
-    "   v_texcoord = a_texcoord;  \n"
-    "}                            \n";
-
-/* *INDENT-ON* */
-
 struct TexData
 {
-  guint internal_format, format, type, width, height;
+  guint format, type, width, height;
   gfloat tex_scaling[2];
-  const gchar *shader_name;
   guint unpack_length;
 };
 
@@ -271,17 +73,6 @@ struct _GstGLUploadPrivate
   int n_textures;
   gboolean result;
 
-  const gchar *YUY2_UYVY;
-  const gchar *PLANAR_YUV;
-  const gchar *AYUV;
-  const gchar *NV12_NV21;
-  const gchar *REORDER;
-  const gchar *COPY;
-  const gchar *COMPOSE;
-  const gchar *vert_shader;
-
-    gboolean (*draw) (GstGLContext * context, GstGLUpload * download);
-
   struct TexData texture_info[GST_VIDEO_MAX_PLANES];
 
   GstBuffer *buffer;
@@ -319,14 +110,6 @@ gst_gl_upload_init (GstGLUpload * upload)
   upload->context = NULL;
 
   g_mutex_init (&upload->lock);
-
-  upload->fbo = 0;
-  upload->depth_buffer = 0;
-  upload->out_texture = 0;
-  upload->shader = NULL;
-
-  upload->shader_attr_position_loc = 0;
-  upload->shader_attr_texture_loc = 0;
 }
 
 /**
@@ -339,22 +122,11 @@ GstGLUpload *
 gst_gl_upload_new (GstGLContext * context)
 {
   GstGLUpload *upload;
-  GstGLUploadPrivate *priv;
 
   upload = g_object_new (GST_TYPE_GL_UPLOAD, NULL);
 
   upload->context = gst_object_ref (context);
-  priv = upload->priv;
-
-  priv->YUY2_UYVY = frag_YUY2_UYVY;
-  priv->PLANAR_YUV = frag_PLANAR_YUV;
-  priv->AYUV = frag_AYUV;
-  priv->REORDER = frag_REORDER;
-  priv->COMPOSE = frag_COMPOSE;
-  priv->COPY = frag_COPY;
-  priv->NV12_NV21 = frag_NV12_NV21;
-  priv->vert_shader = text_vertex_shader;
-  priv->draw = _do_upload_draw;
+  upload->convert = gst_gl_color_convert_new (context);
 
   return upload;
 }
@@ -363,32 +135,11 @@ static void
 gst_gl_upload_finalize (GObject * object)
 {
   GstGLUpload *upload;
-  guint i;
 
   upload = GST_GL_UPLOAD (object);
 
-  for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) {
-    if (upload->in_texture[i]) {
-      gst_gl_context_del_texture (upload->context, &upload->in_texture[i]);
-      upload->in_texture[i] = 0;
-    }
-  }
-  if (upload->out_texture) {
-    gst_gl_context_del_texture (upload->context, &upload->out_texture);
-    upload->out_texture = 0;
-  }
-  if (upload->priv->tex_id) {
-    gst_gl_context_del_texture (upload->context, &upload->priv->tex_id);
-    upload->priv->tex_id = 0;
-  }
-  if (upload->fbo || upload->depth_buffer) {
-    gst_gl_context_del_fbo (upload->context, upload->fbo, upload->depth_buffer);
-    upload->fbo = 0;
-    upload->depth_buffer = 0;
-  }
-  if (upload->shader) {
-    gst_object_unref (upload->shader);
-    upload->shader = NULL;
+  if (upload->convert) {
+    gst_object_unref (upload->convert);
   }
 
   if (upload->context) {
@@ -403,7 +154,7 @@ gst_gl_upload_finalize (GObject * object)
 
 static gboolean
 _gst_gl_upload_init_format_unlocked (GstGLUpload * upload,
-    GstVideoInfo * in_info, GstVideoInfo * out_info)
+    GstVideoInfo *in_info)
 {
   g_return_val_if_fail (upload != NULL, FALSE);
   g_return_val_if_fail (GST_VIDEO_INFO_FORMAT (in_info) !=
@@ -413,12 +164,9 @@ _gst_gl_upload_init_format_unlocked (GstGLUpload * upload,
 
   if (upload->initted) {
     return FALSE;
-  } else {
-    upload->initted = TRUE;
   }
 
   upload->in_info = *in_info;
-  upload->out_info = *out_info;
 
   gst_gl_context_thread_add (upload->context,
       (GstGLContextThreadFunc) _init_upload, upload);
@@ -431,7 +179,6 @@ _gst_gl_upload_init_format_unlocked (GstGLUpload * upload,
  * gst_gl_upload_init_format:
  * @upload: a #GstGLUpload
  * @in_info: input #GstVideoInfo
- * @out_info: output #GstVideoInfo
  *
  * Initializes @upload with the information required for upload.
  *
@@ -445,7 +192,7 @@ gst_gl_upload_init_format (GstGLUpload * upload, GstVideoInfo * in_info,
 
   g_mutex_lock (&upload->lock);
 
-  ret = _gst_gl_upload_init_format_unlocked (upload, in_info, out_info);
+  ret = _gst_gl_upload_init_format_unlocked (upload, in_info);
 
   g_mutex_unlock (&upload->lock);
 
@@ -469,6 +216,7 @@ gst_gl_upload_perform_with_buffer (GstGLUpload * upload, GstBuffer * buffer,
 {
   GstMemory *mem;
   GstVideoGLTextureUploadMeta *gl_tex_upload_meta;
+  guint texture_ids[] = { 0, 0, 0, 0 };
 
   g_return_val_if_fail (upload != NULL, FALSE);
   g_return_val_if_fail (buffer != NULL, FALSE);
@@ -502,7 +250,6 @@ gst_gl_upload_perform_with_buffer (GstGLUpload * upload, GstBuffer * buffer,
   /* GstVideoGLTextureUploadMeta */
   gl_tex_upload_meta = gst_buffer_get_video_gl_texture_upload_meta (buffer);
   if (gl_tex_upload_meta) {
-    guint texture_ids[] = { 0, 0, 0, 0 };
     GST_LOG_OBJECT (upload, "Attempting upload with "
         "GstVideoGLTextureUploadMeta");
     texture_ids[0] = upload->priv->tex_id;
@@ -606,7 +353,7 @@ static gboolean
 _do_upload_for_meta (GstGLUpload * upload, GstVideoGLTextureUploadMeta * meta)
 {
   GstVideoMeta *v_meta;
-  GstVideoInfo in_info, out_info;
+  GstVideoInfo in_info;
   GstVideoFrame frame;
   GstMemory *mem;
   gboolean ret;
@@ -628,9 +375,8 @@ _do_upload_for_meta (GstGLUpload * upload, GstVideoGLTextureUploadMeta * meta)
     height = v_meta->height;
 
     gst_video_info_set_format (&in_info, v_format, width, height);
-    gst_video_info_set_format (&out_info, GST_VIDEO_FORMAT_RGBA, width, height);
 
-    if (!_gst_gl_upload_init_format_unlocked (upload, &in_info, &out_info))
+    if (!_gst_gl_upload_init_format_unlocked (upload, &in_info))
       return FALSE;
   }
 
@@ -845,42 +591,13 @@ _gst_gl_upload_perform_with_data_unlocked (GstGLUpload * upload,
   return TRUE;
 }
 
-static gboolean
-_create_shader (GstGLContext * context, const gchar * vertex_src,
-    const gchar * fragment_src, GstGLShader ** out_shader)
-{
-  GstGLShader *shader;
-  GError *error = NULL;
-
-  g_return_val_if_fail (vertex_src != NULL || fragment_src != NULL, FALSE);
-
-  shader = gst_gl_shader_new (context);
-
-  if (vertex_src)
-    gst_gl_shader_set_vertex_source (shader, vertex_src);
-  if (fragment_src)
-    gst_gl_shader_set_fragment_source (shader, fragment_src);
-
-  if (!gst_gl_shader_compile (shader, &error)) {
-    gst_gl_context_set_error (context, "%s", error->message);
-    g_error_free (error);
-    gst_gl_context_clear_shader (context);
-    gst_object_unref (shader);
-    return FALSE;
-  }
-
-  *out_shader = shader;
-  return TRUE;
-}
-
 /* Called in the gl thread */
 void
 _init_upload (GstGLContext * context, GstGLUpload * upload)
 {
   GstGLFuncs *gl;
   GstVideoFormat v_format;
-  gchar *frag_prog = NULL;
-  gboolean free_frag_prog, res;
+  GstVideoInfo out_info;
 
   gl = context->gl_vtable;
 
@@ -895,102 +612,47 @@ _init_upload (GstGLContext * context, GstGLUpload * upload)
     goto error;
   }
 
-  if (!_init_upload_fbo (context, upload)) {
+  gst_video_info_set_format (&out_info, GST_VIDEO_FORMAT_RGBA, GST_VIDEO_INFO_WIDTH (&upload->in_info), GST_VIDEO_INFO_HEIGHT (&upload->in_info));
+
+  if (!gst_gl_color_convert_init_format (upload->convert, upload->in_info, out_info))
     goto error;
-  }
 
   switch (v_format) {
-    case GST_VIDEO_FORMAT_AYUV:
-      frag_prog = (gchar *) upload->priv->AYUV;
-      free_frag_prog = FALSE;
-      upload->priv->n_textures = 1;
-      break;
-    case GST_VIDEO_FORMAT_Y444:
-    case GST_VIDEO_FORMAT_I420:
-    case GST_VIDEO_FORMAT_YV12:
-    case GST_VIDEO_FORMAT_Y42B:
-    case GST_VIDEO_FORMAT_Y41B:
-      frag_prog = (gchar *) upload->priv->PLANAR_YUV;
-      free_frag_prog = FALSE;
-      upload->priv->n_textures = 3;
-      break;
-    case GST_VIDEO_FORMAT_NV12:
-      frag_prog = g_strdup_printf (upload->priv->NV12_NV21, 'r', 'a');
-      free_frag_prog = TRUE;
-      upload->priv->n_textures = 2;
-      break;
-    case GST_VIDEO_FORMAT_NV21:
-      frag_prog = g_strdup_printf (upload->priv->NV12_NV21, 'a', 'r');
-      free_frag_prog = TRUE;
-      upload->priv->n_textures = 2;
-      break;
+    case GST_VIDEO_FORMAT_RGB:
     case GST_VIDEO_FORMAT_BGR:
+    case GST_VIDEO_FORMAT_RGB16:
+    case GST_VIDEO_FORMAT_RGBx:
+    case GST_VIDEO_FORMAT_RGBA:
     case GST_VIDEO_FORMAT_BGRx:
     case GST_VIDEO_FORMAT_BGRA:
-      frag_prog = g_strdup_printf (upload->priv->REORDER, 'b', 'g', 'r');
-      free_frag_prog = TRUE;
-      upload->priv->n_textures = 1;
-      break;
     case GST_VIDEO_FORMAT_xRGB:
     case GST_VIDEO_FORMAT_ARGB:
-      frag_prog = g_strdup_printf (upload->priv->REORDER, 'g', 'b', 'a');
-      free_frag_prog = TRUE;
-      upload->priv->n_textures = 1;
-      break;
     case GST_VIDEO_FORMAT_xBGR:
     case GST_VIDEO_FORMAT_ABGR:
-      frag_prog = g_strdup_printf (upload->priv->REORDER, 'a', 'b', 'g');
-      free_frag_prog = TRUE;
-      upload->priv->n_textures = 1;
-      break;
+    case GST_VIDEO_FORMAT_GRAY8:
     case GST_VIDEO_FORMAT_GRAY16_BE:
-      frag_prog = g_strdup_printf (upload->priv->COMPOSE, 'r', 'a');
-      free_frag_prog = TRUE;
-      upload->priv->n_textures = 1;
-      break;
     case GST_VIDEO_FORMAT_GRAY16_LE:
-      frag_prog = g_strdup_printf (upload->priv->COMPOSE, 'a', 'r');
-      free_frag_prog = TRUE;
-      upload->priv->n_textures = 1;
-      break;
-    case GST_VIDEO_FORMAT_GRAY8:
-    case GST_VIDEO_FORMAT_RGB:
-    case GST_VIDEO_FORMAT_RGBx:
-    case GST_VIDEO_FORMAT_RGBA:
-    case GST_VIDEO_FORMAT_RGB16:
-      frag_prog = (gchar *) upload->priv->COPY;
-      free_frag_prog = FALSE;
+    case GST_VIDEO_FORMAT_AYUV:
       upload->priv->n_textures = 1;
       break;
     case GST_VIDEO_FORMAT_YUY2:
-      frag_prog = g_strdup_printf (upload->priv->YUY2_UYVY, 'r', 'g', 'a');
-      free_frag_prog = TRUE;
-      upload->priv->n_textures = 2;
-      break;
     case GST_VIDEO_FORMAT_UYVY:
-      frag_prog = g_strdup_printf (upload->priv->YUY2_UYVY, 'a', 'r', 'b');
-      free_frag_prog = TRUE;
+    case GST_VIDEO_FORMAT_NV12:
+    case GST_VIDEO_FORMAT_NV21:
       upload->priv->n_textures = 2;
       break;
+    case GST_VIDEO_FORMAT_Y444:
+    case GST_VIDEO_FORMAT_I420:
+    case GST_VIDEO_FORMAT_YV12:
+    case GST_VIDEO_FORMAT_Y42B:
+    case GST_VIDEO_FORMAT_Y41B:
+      upload->priv->n_textures = 3;
+      break;
     default:
       g_assert_not_reached ();
       break;
   }
 
-  res =
-      _create_shader (context, upload->priv->vert_shader, frag_prog,
-      &upload->shader);
-  if (free_frag_prog)
-    g_free (frag_prog);
-  frag_prog = NULL;
-  if (!res)
-    goto error;
-
-  upload->shader_attr_position_loc =
-      gst_gl_shader_get_attribute_location (upload->shader, "a_position");
-  upload->shader_attr_texture_loc =
-      gst_gl_shader_get_attribute_location (upload->shader, "a_texcoord");
-
   if (!_do_upload_make (context, upload))
     goto error;
 
@@ -1001,104 +663,24 @@ error:
   upload->priv->result = FALSE;
 }
 
-
-/* called by _init_upload (in the gl thread) */
-gboolean
-_init_upload_fbo (GstGLContext * context, GstGLUpload * upload)
-{
-  GstGLFuncs *gl;
-  guint out_width, out_height;
-  GLuint fake_texture = 0;      /* a FBO must hava texture to init */
-
-  gl = context->gl_vtable;
-
-  out_width = GST_VIDEO_INFO_WIDTH (&upload->out_info);
-  out_height = GST_VIDEO_INFO_HEIGHT (&upload->out_info);
-
-  if (!gl->GenFramebuffers) {
-    /* turn off the pipeline because Frame buffer object is a not present */
-    gst_gl_context_set_error (context,
-        "Context, EXT_framebuffer_object supported: no");
-    return FALSE;
-  }
-
-  GST_INFO ("Context, EXT_framebuffer_object supported: yes");
-
-  /* setup FBO */
-  gl->GenFramebuffers (1, &upload->fbo);
-  gl->BindFramebuffer (GL_FRAMEBUFFER, upload->fbo);
-
-  /* setup the render buffer for depth */
-  gl->GenRenderbuffers (1, &upload->depth_buffer);
-  gl->BindRenderbuffer (GL_RENDERBUFFER, upload->depth_buffer);
-  if (USING_OPENGL (context)) {
-    gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT,
-        out_width, out_height);
-    gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH24_STENCIL8,
-        out_width, out_height);
-  }
-  if (USING_GLES2 (context)) {
-    gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
-        out_width, out_height);
-  }
-
-  /* a fake texture is attached to the upload FBO (cannot init without it) */
-  gl->GenTextures (1, &fake_texture);
-  gl->BindTexture (GL_TEXTURE_2D, fake_texture);
-  gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, out_width, out_height,
-      0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-  gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-  gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-  gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-  gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
-  /* attach the texture to the FBO to renderer to */
-  gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-      GL_TEXTURE_2D, fake_texture, 0);
-
-  /* attach the depth render buffer to the FBO */
-  gl->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
-      GL_RENDERBUFFER, upload->depth_buffer);
-
-  if (USING_OPENGL (context)) {
-    gl->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
-        GL_RENDERBUFFER, upload->depth_buffer);
-  }
-
-  if (!gst_gl_context_check_framebuffer_status (context)) {
-    gst_gl_context_set_error (context, "GL framebuffer status incomplete");
-    return FALSE;
-  }
-
-  /* unbind the FBO */
-  gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
-
-  gl->DeleteTextures (1, &fake_texture);
-
-  return TRUE;
-}
-
 /* Called by the idle function in the gl thread */
 void
 _do_upload (GstGLContext * context, GstGLUpload * upload)
 {
-  guint in_width, in_height, out_width, out_height;
+  guint in_width, in_height;
+  guint out_texture[] = {upload->out_texture, 0, 0, 0};
 
-  out_width = GST_VIDEO_INFO_WIDTH (&upload->out_info);
-  out_height = GST_VIDEO_INFO_HEIGHT (&upload->out_info);
   in_width = GST_VIDEO_INFO_WIDTH (&upload->in_info);
   in_height = GST_VIDEO_INFO_HEIGHT (&upload->in_info);
 
-  GST_TRACE ("uploading to texture:%u dimensions:%ux%u, "
-      "from textures:%u,%u,%u dimensions:%ux%u", upload->out_texture,
-      out_width, out_height, upload->in_texture[0], upload->in_texture[1],
+  GST_TRACE ("uploading to texture:%u with textures:%u,%u,%u dimensions:%ux%u", 
+      upload->out_texture, upload->in_texture[0], upload->in_texture[1],
       upload->in_texture[2], in_width, in_height);
 
   if (!_do_upload_fill (context, upload))
     goto error;
 
-  if (!upload->priv->draw (context, upload))
-    goto error;
+  gst_gl_color_convert_perform (upload->convert, upload->in_texture, out_texture);
 
   upload->priv->result = TRUE;
   return;
@@ -1135,6 +717,7 @@ _do_upload_make (GstGLContext * context, GstGLUpload * upload)
   GstVideoFormat v_format;
   guint in_height;
   struct TexData *tex = upload->priv->texture_info;
+  gfloat tex_scaling[GST_VIDEO_MAX_PLANES][2];
   guint i;
 
   gl = context->gl_vtable;
@@ -1152,97 +735,69 @@ _do_upload_make (GstGLContext * context, GstGLUpload * upload)
     case GST_VIDEO_FORMAT_ARGB:
     case GST_VIDEO_FORMAT_ABGR:
     case GST_VIDEO_FORMAT_AYUV:
-      tex[0].internal_format = GL_RGBA;
       tex[0].format = GL_RGBA;
       tex[0].type = GL_UNSIGNED_BYTE;
       tex[0].height = in_height;
-      tex[0].shader_name = "tex";
       break;
     case GST_VIDEO_FORMAT_RGB:
     case GST_VIDEO_FORMAT_BGR:
-      tex[0].internal_format = GL_RGB;
       tex[0].format = GL_RGB;
       tex[0].type = GL_UNSIGNED_BYTE;
       tex[0].height = in_height;
-      tex[0].shader_name = "tex";
       break;
     case GST_VIDEO_FORMAT_GRAY8:
-      tex[0].internal_format = GL_LUMINANCE;
       tex[0].format = GL_LUMINANCE;
       tex[0].type = GL_UNSIGNED_BYTE;
       tex[0].height = in_height;
-      tex[0].shader_name = "tex";
       break;
     case GST_VIDEO_FORMAT_GRAY16_BE:
     case GST_VIDEO_FORMAT_GRAY16_LE:
-      tex[0].internal_format = GL_LUMINANCE_ALPHA;
       tex[0].format = GL_LUMINANCE_ALPHA;
       tex[0].type = GL_UNSIGNED_BYTE;
       tex[0].height = in_height;
-      tex[0].shader_name = "tex";
       break;
     case GST_VIDEO_FORMAT_YUY2:
     case GST_VIDEO_FORMAT_UYVY:
-      tex[0].internal_format = GL_LUMINANCE_ALPHA;
       tex[0].format = GL_LUMINANCE_ALPHA;
       tex[0].type = GL_UNSIGNED_BYTE;
       tex[0].height = in_height;
-      tex[0].shader_name = "Ytex";
-      tex[1].internal_format = GL_RGBA8;
       tex[1].format = GL_RGBA;
       tex[1].type = GL_UNSIGNED_BYTE;
       tex[1].height = in_height;
-      tex[1].shader_name = "UVtex";
       break;
     case GST_VIDEO_FORMAT_NV12:
     case GST_VIDEO_FORMAT_NV21:
-      tex[0].internal_format = GL_LUMINANCE;
       tex[0].format = GL_LUMINANCE;
       tex[0].type = GL_UNSIGNED_BYTE;
       tex[0].height = in_height;
-      tex[0].shader_name = "Ytex";
-      tex[1].internal_format = GL_LUMINANCE_ALPHA;
       tex[1].format = GL_LUMINANCE_ALPHA;
       tex[1].type = GL_UNSIGNED_BYTE;
       tex[1].height = GST_ROUND_UP_2 (in_height) / 2;
-      tex[1].shader_name = "UVtex";
       break;
     case GST_VIDEO_FORMAT_Y444:
     case GST_VIDEO_FORMAT_Y42B:
     case GST_VIDEO_FORMAT_Y41B:
-      tex[0].internal_format = GL_LUMINANCE;
       tex[0].format = GL_LUMINANCE;
       tex[0].type = GL_UNSIGNED_BYTE;
       tex[0].height = in_height;
-      tex[0].shader_name = "Ytex";
-      tex[1].internal_format = GL_LUMINANCE;
       tex[1].format = GL_LUMINANCE;
       tex[1].type = GL_UNSIGNED_BYTE;
       tex[1].height = in_height;
-      tex[1].shader_name = "Utex";
-      tex[2].internal_format = GL_LUMINANCE;
       tex[2].format = GL_LUMINANCE;
       tex[2].type = GL_UNSIGNED_BYTE;
       tex[2].height = in_height;
-      tex[2].shader_name = "Vtex";
       break;
     case GST_VIDEO_FORMAT_I420:
     case GST_VIDEO_FORMAT_YV12:
-      tex[0].internal_format = GL_LUMINANCE;
       tex[0].format = GL_LUMINANCE;
       tex[0].type = GL_UNSIGNED_BYTE;
       tex[0].height = in_height;
-      tex[0].shader_name = "Ytex";
-      tex[1].internal_format = GL_LUMINANCE;
       tex[1].format = GL_LUMINANCE;
       tex[1].type = GL_UNSIGNED_BYTE;
       tex[1].height = GST_ROUND_UP_2 (in_height) / 2;
-      tex[1].shader_name = "Utex";
-      tex[2].internal_format = GL_LUMINANCE;
       tex[2].format = GL_LUMINANCE;
       tex[2].type = GL_UNSIGNED_BYTE;
       tex[2].height = GST_ROUND_UP_2 (in_height) / 2;
-      tex[2].shader_name = "Vtex";
       break;
     default:
       gst_gl_context_set_error (context, "Unsupported upload video format %d",
@@ -1272,8 +827,8 @@ _do_upload_make (GstGLContext * context, GstGLUpload * upload)
     }
 
     tex[i].width = plane_width;
-    tex[i].tex_scaling[0] = 1.0f;
-    tex[i].tex_scaling[1] = 1.0f;
+    tex_scaling[i][0] = 1.0f;
+    tex_scaling[i][1] = 1.0f;
 
 #if GST_GL_HAVE_OPENGL || GST_GL_HAVE_GLES3
     if (USING_OPENGL (context) || USING_GLES3 (context)) {
@@ -1322,7 +877,7 @@ _do_upload_make (GstGLContext * context, GstGLUpload * upload)
                 j, i, plane_stride, pstride, j, plane_stride, round_up_j);
 
             tex[i].unpack_length = j;
-            tex[i].tex_scaling[0] =
+            tex_scaling[i][0] =
                 (gfloat) (plane_width * pstride) / (gfloat) plane_stride;
             break;
           }
@@ -1342,14 +897,15 @@ _do_upload_make (GstGLContext * context, GstGLUpload * upload)
     gl->GenTextures (1, &upload->in_texture[i]);
     gl->BindTexture (GL_TEXTURE_2D, upload->in_texture[i]);
 
-    gl->TexImage2D (GL_TEXTURE_2D, 0, tex[i].internal_format,
+    gl->TexImage2D (GL_TEXTURE_2D, 0, tex[i].format,
         tex[i].width, tex[i].height, 0, tex[i].format, tex[i].type, NULL);
   }
 
+  gst_gl_color_convert_set_texture_scaling (upload->convert, tex_scaling);
+
   return TRUE;
 }
 
-
 /* called by gst_gl_context_thread_do_upload (in the gl thread) */
 gboolean
 _do_upload_fill (GstGLContext * context, GstGLUpload * upload)
@@ -1413,123 +969,3 @@ _do_upload_fill (GstGLContext * context, GstGLUpload * upload)
 
   return TRUE;
 }
-
-static gboolean
-_do_upload_draw (GstGLContext * context, GstGLUpload * upload)
-{
-  GstGLFuncs *gl;
-  struct TexData *tex = upload->priv->texture_info;
-  guint out_width, out_height;
-  const gfloat *cms_offset;
-  const gfloat *cms_rcoeff;
-  const gfloat *cms_gcoeff;
-  const gfloat *cms_bcoeff;
-  gint i;
-
-  GLint viewport_dim[4];
-
-  const GLfloat vVertices[] = { 1.0f, -1.0f, 0.0f,
-    1.0f, 0.0f,
-    -1.0f, -1.0f, 0.0f,
-    0.0f, 0.0f,
-    -1.0f, 1.0f, 0.0f,
-    0.0f, 1.0f,
-    1.0f, 1.0f, 0.0f,
-    1.0f, 1.0f
-  };
-
-  GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
-
-  gl = context->gl_vtable;
-
-  out_width = GST_VIDEO_INFO_WIDTH (&upload->out_info);
-  out_height = GST_VIDEO_INFO_HEIGHT (&upload->out_info);
-
-  if (gst_video_colorimetry_matches (&upload->in_info.colorimetry,
-          GST_VIDEO_COLORIMETRY_BT709)) {
-    cms_offset = bt709_offset;
-    cms_rcoeff = bt709_rcoeff;
-    cms_gcoeff = bt709_gcoeff;
-    cms_bcoeff = bt709_bcoeff;
-  } else if (gst_video_colorimetry_matches (&upload->in_info.colorimetry,
-          GST_VIDEO_COLORIMETRY_BT601)) {
-    cms_offset = bt601_offset;
-    cms_rcoeff = bt601_rcoeff;
-    cms_gcoeff = bt601_gcoeff;
-    cms_bcoeff = bt601_bcoeff;
-  } else {
-    /* defaults */
-    cms_offset = bt601_offset;
-    cms_rcoeff = bt601_rcoeff;
-    cms_gcoeff = bt601_gcoeff;
-    cms_bcoeff = bt601_bcoeff;
-  }
-
-  gl->BindFramebuffer (GL_FRAMEBUFFER, upload->fbo);
-
-  /* setup a texture to render to */
-  gl->BindTexture (GL_TEXTURE_2D, upload->out_texture);
-
-  /* attach the texture to the FBO to renderer to */
-  gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-      GL_TEXTURE_2D, upload->out_texture, 0);
-
-  gst_gl_context_clear_shader (context);
-
-  gl->GetIntegerv (GL_VIEWPORT, viewport_dim);
-
-  gl->Viewport (0, 0, out_width, out_height);
-
-  gl->ClearColor (0.0, 0.0, 0.0, 0.0);
-  gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
-  gst_gl_shader_use (upload->shader);
-
-  gl->VertexAttribPointer (upload->shader_attr_position_loc, 3,
-      GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), vVertices);
-  gl->VertexAttribPointer (upload->shader_attr_texture_loc, 2,
-      GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), &vVertices[3]);
-
-  gl->EnableVertexAttribArray (upload->shader_attr_position_loc);
-  gl->EnableVertexAttribArray (upload->shader_attr_texture_loc);
-
-  gst_gl_shader_set_uniform_3fv (upload->shader, "offset", 1,
-      (gfloat *) cms_offset);
-  gst_gl_shader_set_uniform_3fv (upload->shader, "rcoeff", 1,
-      (gfloat *) cms_rcoeff);
-  gst_gl_shader_set_uniform_3fv (upload->shader, "gcoeff", 1,
-      (gfloat *) cms_gcoeff);
-  gst_gl_shader_set_uniform_3fv (upload->shader, "bcoeff", 1,
-      (gfloat *) cms_bcoeff);
-
-  for (i = upload->priv->n_textures - 1; i >= 0; i--) {
-    gchar *scale_name = g_strdup_printf ("tex_scale%u", i);
-
-    gl->ActiveTexture (GL_TEXTURE0 + i);
-    gst_gl_shader_set_uniform_1i (upload->shader, tex[i].shader_name, i);
-    gst_gl_shader_set_uniform_2fv (upload->shader, scale_name, 1,
-        &tex[i].tex_scaling[0]);
-
-    g_free (scale_name);
-
-    gl->BindTexture (GL_TEXTURE_2D, upload->in_texture[i]);
-    gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-    gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-    gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-    gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-  }
-
-  gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
-
-  /* we are done with the shader */
-  gst_gl_context_clear_shader (context);
-
-  gl->Viewport (viewport_dim[0], viewport_dim[1], viewport_dim[2],
-      viewport_dim[3]);
-
-  gst_gl_context_check_framebuffer_status (context);
-
-  gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
-
-  return TRUE;
-}
index b60d89287d7e6669003101063a168d6c5836cb2f..6e313ef64d6ba2970f5035ce043c814e24a73355 100644 (file)
@@ -49,22 +49,16 @@ struct _GstGLUpload
   GMutex           lock;
 
   GstGLContext    *context;
+  GstGLColorConvert *convert;
 
   /* input data */
   GstVideoInfo     in_info;
-  GstVideoInfo     out_info;
 
   gpointer         data[GST_VIDEO_MAX_PLANES];
   gboolean         initted;
 
-  /* used for the conversion */
-  GLuint           fbo;
-  GLuint           depth_buffer;
-  GLuint           out_texture;
   GLuint           in_texture[GST_VIDEO_MAX_PLANES];
-  GstGLShader     *shader;
-  GLint            shader_attr_position_loc;
-  GLint            shader_attr_texture_loc;
+  GLuint           out_texture;
 
   /* <private> */
   GstGLUploadPrivate *priv;
@@ -82,23 +76,6 @@ struct _GstGLUploadClass
   GObjectClass object_class;
 };
 
-/**
- * GST_GL_UPLOAD_FORMATS:
- *
- * The currently supported formats that can be uploaded
- */
-#define GST_GL_UPLOAD_FORMATS "{ RGB, RGBx, RGBA, BGR, BGRx, BGRA, xRGB, " \
-                               "xBGR, ARGB, ABGR, Y444, I420, YV12, Y42B, " \
-                               "Y41B, NV12, NV21, YUY2, UYVY, AYUV, " \
-                               "GRAY8, GRAY16_LE, GRAY16_BE }"
-
-/**
- * GST_GL_UPLOAD_VIDEO_CAPS:
- *
- * The currently supported #GstCaps that can be uploaded
- */
-#define GST_GL_UPLOAD_VIDEO_CAPS GST_VIDEO_CAPS_MAKE (GST_GL_UPLOAD_FORMATS)
-
 GstGLUpload * gst_gl_upload_new            (GstGLContext * context);
 
 gboolean gst_gl_upload_init_format         (GstGLUpload * upload, GstVideoInfo * in_info, GstVideoInfo * out_info);