Currently used by both upload and download objects separately.
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
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;
gstglmixer.c \
gstglshader.c \
gstglshadervariables.c \
+ gstglcolorconvert.c \
gstgldownload.c \
gstglupload.c \
gstglwindow.c \
gstglmixerpad.h \
gstglshadervariables.h \
gstglshader.h \
+ gstglcolorconvert.h \
gstgldownload.h \
gstglupload.h \
gstglapi.h \
#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>
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__ */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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__ */
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
const gchar *ARGB;
const gchar *vert_shader;
- void (*do_rgb) (GstGLContext * context, GstGLDownload * download);
- void (*do_yuv) (GstGLContext * context, GstGLDownload * download);
-
gboolean result;
};
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);
}
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;
}
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) {
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);
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:
{
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]);
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;
gst_gl_context_check_framebuffer_status (context);
gl->BindFramebuffer (GL_FRAMEBUFFER, 0);
}
-#endif
GMutex lock;
GstGLContext *context;
+ GstGLColorConvert *convert;
/* output data */
GstVideoInfo info;
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;
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,
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"))
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"))
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"))
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"))
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 \
"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;
};
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;
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;
}
/**
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;
}
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) {
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) !=
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);
* gst_gl_upload_init_format:
* @upload: a #GstGLUpload
* @in_info: input #GstVideoInfo
- * @out_info: output #GstVideoInfo
*
* Initializes @upload with the information required for upload.
*
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);
{
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);
/* 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;
_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;
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;
}
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;
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;
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;
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;
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",
}
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)) {
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;
}
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)
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;
-}
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;
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);