3 * Copyright (C) 2012-2014 Matthew Waters <ystree00@gmail.com>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
28 #include "gstglcolorconvert.h"
31 #include "gstglfuncs.h"
32 #include "gstglsl_private.h"
35 * SECTION:gstglcolorconvert
36 * @title: GstGLColorConvert
37 * @short_description: convert between video color spaces and formats
38 * @see_also: #GstGLUpload, #GstGLMemory, #GstGLBaseMemory
40 * #GstGLColorConvert is an object that converts between color spaces and/or
41 * formats using OpenGL Shaders.
43 * A #GstGLColorConvert can be created with gst_gl_color_convert_new(), the
44 * configuration negotiated with gst_gl_color_convert_transform_caps() and the
45 * conversion performed with gst_gl_color_convert_perform().
47 * The glcolorconvertelement provides a GStreamer element that uses
48 * #GstGLColorConvert to convert between video formats and color spaces.
51 #define USING_OPENGL(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL, 1, 0))
52 #define USING_OPENGL3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL3, 3, 1))
53 #define USING_GLES(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES, 1, 0))
54 #define USING_GLES2(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 2, 0))
55 #define USING_GLES3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 3, 0))
57 static void _do_convert (GstGLContext * context, GstGLColorConvert * convert);
58 static gboolean _init_convert (GstGLColorConvert * convert);
59 static gboolean _init_convert_fbo (GstGLColorConvert * convert);
60 static GstBuffer *_gst_gl_color_convert_perform_unlocked (GstGLColorConvert *
61 convert, GstBuffer * inbuf);
63 static gboolean _do_convert_draw (GstGLContext * context,
64 GstGLColorConvert * convert);
70 GstGLColorConvert *convert;
74 #define YUV_TO_RGB_COEFFICIENTS \
75 "uniform vec3 offset;\n" \
76 "uniform vec3 coeff1;\n" \
77 "uniform vec3 coeff2;\n" \
78 "uniform vec3 coeff3;\n"
80 /* FIXME: use the colormatrix support from videoconvert */
82 /* BT. 601 standard with the following ranges:
83 * Y = [16..235] (of 255)
84 * Cb/Cr = [16..240] (of 255)
86 static const gfloat from_yuv_bt601_offset[] = {-0.0625f, -0.5f, -0.5f};
87 static const gfloat from_yuv_bt601_rcoeff[] = {1.164f, 0.000f, 1.596f};
88 static const gfloat from_yuv_bt601_gcoeff[] = {1.164f,-0.391f,-0.813f};
89 static const gfloat from_yuv_bt601_bcoeff[] = {1.164f, 2.018f, 0.000f};
91 /* BT. 709 standard with the following ranges:
92 * Y = [16..235] (of 255)
93 * Cb/Cr = [16..240] (of 255)
95 static const gfloat from_yuv_bt709_offset[] = {-0.0625f, -0.5f, -0.5f};
96 static const gfloat from_yuv_bt709_rcoeff[] = {1.164f, 0.000f, 1.787f};
97 static const gfloat from_yuv_bt709_gcoeff[] = {1.164f,-0.213f,-0.531f};
98 static const gfloat from_yuv_bt709_bcoeff[] = {1.164f,2.112f, 0.000f};
100 #define RGB_TO_YUV_COEFFICIENTS \
101 "uniform vec3 offset;\n" \
102 "uniform vec3 coeff1;\n" \
103 "uniform vec3 coeff2;\n" \
104 "uniform vec3 coeff3;\n"
106 /* Matrix inverses of the color matrices found above */
107 /* BT. 601 standard with the following ranges:
108 * Y = [16..235] (of 255)
109 * Cb/Cr = [16..240] (of 255)
111 static const gfloat from_rgb_bt601_offset[] = {0.0625f, 0.5f, 0.5f};
112 static const gfloat from_rgb_bt601_ycoeff[] = {0.256816f, 0.504154f, 0.0979137f};
113 static const gfloat from_rgb_bt601_ucoeff[] = {-0.148246f, -0.29102f, 0.439266f};
114 static const gfloat from_rgb_bt601_vcoeff[] = {0.439271f, -0.367833f, -0.071438f};
116 /* BT. 709 standard with the following ranges:
117 * Y = [16..235] (of 255)
118 * Cb/Cr = [16..240] (of 255)
120 static const gfloat from_rgb_bt709_offset[] = {0.0625f, 0.5f, 0.5f};
121 static const gfloat from_rgb_bt709_ycoeff[] = {0.182604f, 0.614526f, 0.061976f};
122 static const gfloat from_rgb_bt709_ucoeff[] = {-0.100640f, -0.338688f, 0.439327f};
123 static const gfloat from_rgb_bt709_vcoeff[] = {0.440654f, -0.400285f, -0.040370f};
125 /* GRAY16 to RGB conversion
126 * data transferred as GL_LUMINANCE_ALPHA then convert back to GRAY16
127 * high byte weight as : 255*256/65535
128 * ([0~1] denormalize to [0~255],shift to high byte,normalize to [0~1])
129 * low byte weight as : 255/65535 (similar)
131 #define COMPOSE_WEIGHT \
132 "const vec2 compose_weight = vec2(0.996109, 0.003891);\n"
134 #define DEFAULT_UNIFORMS \
135 "uniform vec2 tex_scale0;\n" \
136 "uniform vec2 tex_scale1;\n" \
137 "uniform vec2 tex_scale2;\n" \
138 "uniform vec2 tex_scale3;\n" \
139 "uniform float width;\n" \
140 "uniform float height;\n" \
141 "uniform float poffset_x;\n" \
142 "uniform float poffset_y;\n"
144 #define MAX_FUNCTIONS 4
146 #define glsl_OES_extension_string "#extension GL_OES_EGL_image_external : require \n"
150 const gchar *extensions;
151 const gchar *uniforms;
152 const gchar *functions[MAX_FUNCTIONS];
154 GstGLTextureTarget target;
157 #define glsl_func_yuv_to_rgb \
158 "vec3 yuv_to_rgb (vec3 val, vec3 offset, vec3 ycoeff, vec3 ucoeff, vec3 vcoeff) {\n" \
160 " val += offset;\n" \
161 " rgb.r = dot(val, ycoeff);\n" \
162 " rgb.g = dot(val, ucoeff);\n" \
163 " rgb.b = dot(val, vcoeff);\n" \
167 #define glsl_func_rgb_to_yuv \
168 "vec3 rgb_to_yuv (vec3 val, vec3 offset, vec3 rcoeff, vec3 gcoeff, vec3 bcoeff) {\n" \
170 " yuv.r = dot(val.rgb, rcoeff);\n" \
171 " yuv.g = dot(val.rgb, gcoeff);\n" \
172 " yuv.b = dot(val.rgb, bcoeff);\n" \
173 " yuv += offset;\n" \
177 /* Channel reordering for XYZ <-> ZYX conversion */
178 static const gchar templ_REORDER_BODY[] =
179 "vec4 t = texture2D(tex, texcoord * tex_scale0);\n"
180 "%s\n" /* clobber alpha channel? */
181 "gl_FragColor = vec4(t.%c, t.%c, t.%c, t.%c);\n";
183 static const struct shader_templ templ_REORDER =
185 DEFAULT_UNIFORMS "uniform sampler2D tex;\n",
187 GST_GL_TEXTURE_TARGET_2D
190 /* GRAY16 to RGB conversion
191 * data transferred as GL_LUMINANCE_ALPHA then convert back to GRAY16
192 * high byte weight as : 255*256/65535
193 * ([0~1] denormalize to [0~255],shift to high byte,normalize to [0~1])
194 * low byte weight as : 255/65535 (similar)
196 static const gchar templ_COMPOSE_BODY[] =
198 "vec4 t = texture2D(tex, texcoord * tex_scale0);\n"
199 "rgba.rgb = vec3 (dot(t.%c%c, compose_weight));"
201 "gl_FragColor = vec4(rgba.%c, rgba.%c, rgba.%c, rgba.%c);\n";
203 static const struct shader_templ templ_COMPOSE =
205 DEFAULT_UNIFORMS COMPOSE_WEIGHT "uniform sampler2D tex;\n",
207 GST_GL_TEXTURE_TARGET_2D
210 /* Shaders for AYUV and varieties */
211 static const gchar templ_AYUV_to_RGB_BODY[] =
212 "vec4 texel, rgba;\n"
213 "texel = texture2D(tex, texcoord * tex_scale0);\n"
214 "rgba.rgb = yuv_to_rgb (texel.%s, offset, coeff1, coeff2, coeff3);\n"
215 "rgba.a = texel.%c;\n"
216 "gl_FragColor=vec4(rgba.%c,rgba.%c,rgba.%c,rgba.%c);\n";
218 static const struct shader_templ templ_AYUV_to_RGB =
220 DEFAULT_UNIFORMS YUV_TO_RGB_COEFFICIENTS "uniform sampler2D tex;\n",
221 { glsl_func_yuv_to_rgb, NULL, },
222 GST_GL_TEXTURE_TARGET_2D
225 static const gchar templ_RGB_to_AYUV_BODY[] =
226 "vec4 texel, ayuv;\n"
227 "texel = texture2D(tex, texcoord).%c%c%c%c;\n"
228 "ayuv.%s = rgb_to_yuv (texel.rgb, offset, coeff1, coeff2, coeff3);\n"
230 "gl_FragColor = ayuv;\n";
232 static const struct shader_templ templ_RGB_to_AYUV =
234 DEFAULT_UNIFORMS RGB_TO_YUV_COEFFICIENTS "uniform sampler2D tex;\n",
235 { glsl_func_rgb_to_yuv, NULL, },
236 GST_GL_TEXTURE_TARGET_2D
239 /* YUV to RGB conversion */
240 static const gchar templ_PLANAR_YUV_to_RGB_BODY[] =
241 "vec4 texel, rgba;\n"
242 /* FIXME: should get the sampling right... */
243 "texel.x = texture2D(Ytex, texcoord * tex_scale0).r;\n"
244 "texel.y = texture2D(Utex, texcoord * tex_scale1).r;\n"
245 "texel.z = texture2D(Vtex, texcoord * tex_scale2).r;\n"
246 "rgba.rgb = yuv_to_rgb (texel.xyz, offset, coeff1, coeff2, coeff3);\n"
248 "gl_FragColor=vec4(rgba.%c,rgba.%c,rgba.%c,rgba.%c);\n";
250 static const struct shader_templ templ_PLANAR_YUV_to_RGB =
252 DEFAULT_UNIFORMS YUV_TO_RGB_COEFFICIENTS "uniform sampler2D Ytex, Utex, Vtex;\n",
253 { glsl_func_yuv_to_rgb, NULL, },
254 GST_GL_TEXTURE_TARGET_2D
257 static const gchar templ_A420_to_RGB_BODY[] =
258 "vec4 texel, rgba;\n"
259 /* FIXME: should get the sampling right... */
260 /* first 3 textures (planes) contain YUV */
261 "texel.x = texture2D(Ytex, texcoord * tex_scale0).r;\n"
262 "texel.y = texture2D(Utex, texcoord * tex_scale1).r;\n"
263 "texel.z = texture2D(Vtex, texcoord * tex_scale2).r;\n"
264 /* last texture contains the alpha buffer */
265 "texel.w = texture2D(Atex, texcoord * tex_scale3).r;\n"
266 "rgba.rgb = yuv_to_rgb (texel.xyz, offset, coeff1, coeff2, coeff3);\n"
267 "rgba.a = texel.w;\n" /* copy alpha as is */
268 "gl_FragColor=vec4(rgba.%c,rgba.%c,rgba.%c,rgba.%c);\n";
270 static const struct shader_templ templ_A420_to_RGB =
272 /* 4th uniform is the alpha buffer */
273 DEFAULT_UNIFORMS YUV_TO_RGB_COEFFICIENTS "uniform sampler2D Ytex, Utex, Vtex, Atex;\n",
274 { glsl_func_yuv_to_rgb, NULL, },
275 GST_GL_TEXTURE_TARGET_2D
278 static const gchar templ_RGB_to_PLANAR_YUV_BODY[] =
281 "texel = texture2D(tex, texcoord).%c%c%c%c;\n"
282 /* FIXME: this is not quite correct yet */
283 "vec4 uv_texel = vec4(0.0);\n"
284 /* One u and v sample can be generated by a nxm sized block given by */
285 /* @chroma_sampling. The result is the average of all the values in the */
286 /* block computed with a rolling average. */
287 "vec2 unnormalization;\n"
288 "if (texcoord.x == v_texcoord.x) {\n"
289 " unnormalization = vec2(width, height);\n"
291 " unnormalization = vec2 (1.0);\n"
293 /* scale for chroma size */
294 "vec2 chroma_pos = texcoord * chroma_sampling * unnormalization;\n"
295 /* offset chroma to the center of the first texel in the block */
296 "chroma_pos -= clamp(chroma_sampling * 0.5 - 0.5, vec2(0.0), chroma_sampling);\n"
297 "if (chroma_pos.x < width && chroma_pos.y < height) {\n"
298 " for (int i = 0; i < int(chroma_sampling.x); i++) {\n"
299 " vec2 delta = vec2 (float(i), 0.0);\n"
300 " for (int j = 0; j < int(chroma_sampling.y); j++) {\n"
301 " int n = (i+1)*(j+1);\n"
302 " delta.y = float(j);\n"
303 " vec4 s = texture2D(tex, (chroma_pos + delta) / unnormalization).%c%c%c%c;\n"
304 /* rolling average */
305 " uv_texel = (float(n-1) * uv_texel + s) / float(n);\n"
309 "yuv.x = rgb_to_yuv (texel.rgb, offset, coeff1, coeff2, coeff3).x;\n"
310 "yuv.yz = rgb_to_yuv (uv_texel.rgb, offset, coeff1, coeff2, coeff3).yz;\n"
311 "gl_FragData[0] = vec4(yuv.x, 0.0, 0.0, 1.0);\n"
312 "gl_FragData[1] = vec4(yuv.y, 0.0, 0.0, 1.0);\n"
313 "gl_FragData[2] = vec4(yuv.z, 0.0, 0.0, 1.0);\n"
316 static const struct shader_templ templ_RGB_to_PLANAR_YUV =
318 DEFAULT_UNIFORMS RGB_TO_YUV_COEFFICIENTS "uniform sampler2D tex;\n"
319 "uniform vec2 chroma_sampling;\n",
320 { glsl_func_rgb_to_yuv, NULL, },
321 GST_GL_TEXTURE_TARGET_2D
324 /* semi-planar to RGB conversion */
325 static const gchar templ_SEMI_PLANAR_to_RGB_BODY[] =
328 /* FIXME: should get the sampling right... */
329 "yuv.x=texture2D(Ytex, texcoord * tex_scale0).r;\n"
330 "yuv.yz=texture2D(UVtex, texcoord * tex_scale1).%c%c;\n"
331 "rgba.rgb = yuv_to_rgb (yuv, offset, coeff1, coeff2, coeff3);\n"
333 "gl_FragColor=vec4(rgba.%c,rgba.%c,rgba.%c,rgba.%c);\n";
335 static const struct shader_templ templ_SEMI_PLANAR_to_RGB =
337 DEFAULT_UNIFORMS YUV_TO_RGB_COEFFICIENTS "uniform sampler2D Ytex, UVtex;\n",
338 { glsl_func_yuv_to_rgb, NULL, },
339 GST_GL_TEXTURE_TARGET_2D
342 static const gchar templ_AV12_to_RGB_BODY[] =
345 /* FIXME: should get the sampling right... */
346 "ayuv.x=texture2D(Ytex, texcoord * tex_scale0).r;\n"
347 "ayuv.yz=texture2D(UVtex, texcoord * tex_scale1).rg;\n"
348 "ayuv.a=texture2D(Atex, texcoord * tex_scale2).r;\n"
349 "rgba.rgb = yuv_to_rgb (ayuv.xyz, offset, coeff1, coeff2, coeff3);\n"
350 "rgba.a = ayuv.a;\n" /* copy alpha as is */
351 "gl_FragColor=vec4(rgba.%c,rgba.%c,rgba.%c,rgba.%c);\n";
353 static const struct shader_templ templ_AV12_to_RGB =
355 DEFAULT_UNIFORMS YUV_TO_RGB_COEFFICIENTS "uniform sampler2D Ytex, UVtex, Atex;\n",
356 { glsl_func_yuv_to_rgb, NULL, },
357 GST_GL_TEXTURE_TARGET_2D
360 /* RGB to NV12/NV21/NV16/NV61 conversion */
363 static const gchar templ_RGB_to_SEMI_PLANAR_YUV_BODY[] =
364 "vec4 texel, uv_texel;\n"
366 "texel = texture2D(tex, texcoord).%c%c%c%c;\n"
367 "uv_texel = texture2D(tex, texcoord * tex_scale0 * chroma_sampling).%c%c%c%c;\n"
368 "yuv.x = rgb_to_yuv (texel.rgb, offset, coeff1, coeff2, coeff3).x;\n"
369 "yuv.yz = rgb_to_yuv (uv_texel.rgb, offset, coeff1, coeff2, coeff3).yz;\n"
370 "gl_FragData[0] = vec4(yuv.x, 0.0, 0.0, 1.0);\n"
371 "gl_FragData[1] = vec4(yuv.%c, yuv.%c, 0.0, 1.0);\n";
373 static const struct shader_templ templ_RGB_to_SEMI_PLANAR_YUV =
375 DEFAULT_UNIFORMS RGB_TO_YUV_COEFFICIENTS "uniform sampler2D tex;\n"
376 "uniform vec2 chroma_sampling;\n",
377 { glsl_func_rgb_to_yuv, NULL, },
378 GST_GL_TEXTURE_TARGET_2D
381 static const gchar templ_RGB_to_AV12_BODY[] =
382 "vec4 texel, uv_texel;\n"
384 "texel = texture2D(tex, texcoord).%c%c%c%c;\n"
385 "uv_texel = texture2D(tex, texcoord * tex_scale0 * chroma_sampling).%c%c%c%c;\n"
386 "ayuv.x = rgb_to_yuv (texel.rgb, offset, coeff1, coeff2, coeff3).x;\n"
387 "ayuv.yz = rgb_to_yuv (uv_texel.rgb, offset, coeff1, coeff2, coeff3).yz;\n"
388 /* copy alpha as is */
389 "ayuv.a = texel.a;\n"
390 "gl_FragData[0] = vec4(ayuv.x, 0.0, 0.0, 1.0);\n"
391 "gl_FragData[1] = vec4(ayuv.y, ayuv.z, 0.0, 1.0);\n"
392 "gl_FragData[2] = vec4(ayuv.a, 0.0, 0.0, 1.0);\n";
394 static const struct shader_templ templ_RGB_to_AV12 =
396 DEFAULT_UNIFORMS RGB_TO_YUV_COEFFICIENTS "uniform sampler2D tex;\n"
397 "uniform vec2 chroma_sampling;\n",
398 { glsl_func_rgb_to_yuv, NULL, },
399 GST_GL_TEXTURE_TARGET_2D
405 static const gchar templ_YUY2_UYVY_to_RGB_BODY[] =
406 "vec4 rgba, uv_texel;\n"
408 /* FIXME: should get the sampling right... */
409 "float dx1 = -poffset_x;\n"
411 "yuv.x = texture2D(Ytex, texcoord * tex_scale0).%c;\n"
412 /* v_texcoord are normalized, texcoord may not be e.g. rectangle textures */
413 "float inorder = mod (v_texcoord.x * width, 2.0);\n"
414 "if (inorder < 1.0) {\n"
418 "uv_texel.rg = texture2D(Ytex, texcoord * tex_scale0 + vec2(dx1, 0.0)).r%c;\n"
419 "uv_texel.ba = texture2D(Ytex, texcoord * tex_scale0 + vec2(dx2, 0.0)).r%c;\n"
420 "yuv.yz = uv_texel.%c%c;\n"
421 "rgba.rgb = yuv_to_rgb (yuv, offset, coeff1, coeff2, coeff3);\n"
423 "gl_FragColor = vec4(rgba.%c,rgba.%c,rgba.%c,rgba.%c);\n";
425 static const struct shader_templ templ_YUY2_UYVY_to_RGB =
427 DEFAULT_UNIFORMS YUV_TO_RGB_COEFFICIENTS "uniform sampler2D Ytex;\n",
428 { glsl_func_yuv_to_rgb, NULL, },
429 GST_GL_TEXTURE_TARGET_2D
432 static const gchar templ_RGB_to_YUY2_UYVY_BODY[] =
433 "vec4 texel1, texel2;\n"
434 "vec3 yuv, yuv1, yuv2;\n"
435 "float fx, dx, fy;\n"
436 /* v_texcoord are normalized, texcoord may not be e.g. rectangle textures */
437 "float inorder = mod (v_texcoord.x * width, 2.0);\n"
440 "if (inorder > 1.0) {\n"
444 "texel1 = texture2D(tex, vec2(fx, fy)).%c%c%c%c;\n"
445 "texel2 = texture2D(tex, vec2(fx + dx, fy)).%c%c%c%c;\n"
446 "yuv1 = rgb_to_yuv (texel1.rgb, offset, coeff1, coeff2, coeff3);\n"
447 "yuv2 = rgb_to_yuv (texel2.rgb, offset, coeff1, coeff2, coeff3);\n"
449 "yuv.yz = (yuv1.yz + yuv2.yz) * 0.5;\n"
450 "if (inorder < 1.0) {\n"
451 " gl_FragColor = vec4(yuv.%c, yuv.%c, 0.0, 0.0);\n"
453 " gl_FragColor = vec4(yuv.%c, yuv.%c, 0.0, 0.0);\n"
456 static const struct shader_templ templ_RGB_to_YUY2_UYVY =
458 DEFAULT_UNIFORMS RGB_TO_YUV_COEFFICIENTS "uniform sampler2D tex;\n",
459 { glsl_func_rgb_to_yuv, NULL, },
460 GST_GL_TEXTURE_TARGET_2D
463 /* PLANAR RGB to PACKED RGB conversion */
464 static const gchar templ_PLANAR_RGB_to_PACKED_RGB_BODY[] =
466 "rgba.r = texture2D(Rtex, texcoord * tex_scale0).r;\n"
467 "rgba.g = texture2D(Gtex, texcoord * tex_scale1).r;\n"
468 "rgba.b = texture2D(Btex, texcoord * tex_scale2).r;\n"
469 "%s\n" /* alpha channel */
470 "gl_FragColor=vec4(rgba.%c,rgba.%c,rgba.%c,rgba.%c);\n";
472 static const struct shader_templ templ_PLANAR_RGB_to_PACKED_RGB =
474 DEFAULT_UNIFORMS "uniform sampler2D Rtex, Gtex, Btex, Atex;\n",
476 GST_GL_TEXTURE_TARGET_2D
479 /* PACKED RGB to PLANAR RGB conversion */
480 static const gchar templ_PACKED_RGB_to_PLANAR_RGB_BODY[] =
482 "rgba = texture2D(tex, texcoord).%c%c%c%c;\n"
483 "gl_FragData[0] = vec4(rgba.r, 0, 0, 1.0);\n"
484 "gl_FragData[1] = vec4(rgba.g, 0, 0, 1.0);\n"
485 "gl_FragData[2] = vec4(rgba.b, 0, 0, 1.0);\n"
488 static const struct shader_templ templ_PACKED_RGB_to_PLANAR_RGB =
490 DEFAULT_UNIFORMS "uniform sampler2D tex;\n",
492 GST_GL_TEXTURE_TARGET_2D
495 /* PLANAR RGB to PLANAR RGB conversion */
496 static const gchar templ_PLANAR_RGB_to_PLANAR_RGB_BODY[] =
498 "rgba.r = texture2D(Rtex, texcoord * tex_scale0).r;\n"
499 "rgba.g = texture2D(Gtex, texcoord * tex_scale1).r;\n"
500 "rgba.b = texture2D(Btex, texcoord * tex_scale2).r;\n"
501 "%s\n" /* alpha channel */
502 "gl_FragData[0] = vec4(rgba.%c, 0, 0, 1.0);\n"
503 "gl_FragData[1] = vec4(rgba.%c, 0, 0, 1.0);\n"
504 "gl_FragData[2] = vec4(rgba.%c, 0, 0, 1.0);\n"
507 static const struct shader_templ templ_PLANAR_RGB_to_PLANAR_RGB =
509 DEFAULT_UNIFORMS "uniform sampler2D Rtex, Gtex, Btex, Atex;\n",
511 GST_GL_TEXTURE_TARGET_2D
514 static const gchar text_vertex_shader[] =
515 "attribute vec4 a_position; \n"
516 "attribute vec2 a_texcoord; \n"
517 "varying vec2 v_texcoord; \n"
520 " gl_Position = a_position; \n"
521 " v_texcoord = a_texcoord; \n"
524 static const GLfloat vertices[] = {
525 1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
526 -1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
527 -1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
528 1.0f, 1.0f, 0.0f, 1.0f, 1.0f
531 static const GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
539 const struct shader_templ *templ;
542 const gchar *shader_tex_names[GST_VIDEO_MAX_PLANES];
544 gfloat *cms_coeff1; /* r,y */
545 gfloat *cms_coeff2; /* g,u */
546 gfloat *cms_coeff3; /* b,v */
547 gfloat chroma_sampling[2];
550 struct _GstGLColorConvertPrivate
554 struct ConvertInfo convert_info;
556 GstGLTextureTarget from_texture_target;
557 GstGLTextureTarget to_texture_target;
559 GstGLMemory *in_tex[GST_VIDEO_MAX_PLANES];
560 GstGLMemory *out_tex[GST_VIDEO_MAX_PLANES];
562 GstGLFormat in_tex_formats[GST_VIDEO_MAX_PLANES];
565 GLuint vertex_buffer;
567 GLuint attr_position;
574 gboolean pool_started;
577 GST_DEBUG_CATEGORY_STATIC (gst_gl_color_convert_debug);
578 #define GST_CAT_DEFAULT gst_gl_color_convert_debug
581 GST_DEBUG_CATEGORY_INIT (gst_gl_color_convert_debug, "glconvert", 0, "convert");
583 G_DEFINE_TYPE_WITH_CODE (GstGLColorConvert, gst_gl_color_convert,
584 GST_TYPE_OBJECT, G_ADD_PRIVATE (GstGLColorConvert) DEBUG_INIT);
586 static void gst_gl_color_convert_finalize (GObject * object);
587 static void gst_gl_color_convert_reset (GstGLColorConvert * convert);
589 #define GST_GL_COLOR_CONVERT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
590 GST_TYPE_GL_COLOR_CONVERT, GstGLColorConvertPrivate))
593 gst_gl_color_convert_class_init (GstGLColorConvertClass * klass)
595 G_OBJECT_CLASS (klass)->finalize = gst_gl_color_convert_finalize;
599 gst_gl_color_convert_init (GstGLColorConvert * convert)
601 convert->priv = gst_gl_color_convert_get_instance_private (convert);
603 gst_gl_color_convert_reset (convert);
607 * gst_gl_color_convert_new:
608 * @context: a #GstGLContext
610 * Returns: (transfer full): a new #GstGLColorConvert object
615 gst_gl_color_convert_new (GstGLContext * context)
617 GstGLColorConvert *convert;
619 convert = g_object_new (GST_TYPE_GL_COLOR_CONVERT, NULL);
620 gst_object_ref_sink (convert);
622 convert->context = gst_object_ref (context);
624 gst_video_info_set_format (&convert->in_info, GST_VIDEO_FORMAT_ENCODED, 0, 0);
625 gst_video_info_set_format (&convert->out_info, GST_VIDEO_FORMAT_ENCODED, 0,
628 GST_DEBUG_OBJECT (convert,
629 "Created new colorconvert for context %" GST_PTR_FORMAT, context);
635 gst_gl_color_convert_finalize (GObject * object)
637 GstGLColorConvert *convert;
639 convert = GST_GL_COLOR_CONVERT (object);
641 gst_gl_color_convert_reset (convert);
643 if (convert->context) {
644 gst_object_unref (convert->context);
645 convert->context = NULL;
648 G_OBJECT_CLASS (gst_gl_color_convert_parent_class)->finalize (object);
652 _reset_gl (GstGLContext * context, GstGLColorConvert * convert)
654 const GstGLFuncs *gl = context->gl_vtable;
656 if (convert->priv->vao) {
657 gl->DeleteVertexArrays (1, &convert->priv->vao);
658 convert->priv->vao = 0;
661 if (convert->priv->vertex_buffer) {
662 gl->DeleteBuffers (1, &convert->priv->vertex_buffer);
663 convert->priv->vertex_buffer = 0;
666 if (convert->priv->vbo_indices) {
667 gl->DeleteBuffers (1, &convert->priv->vbo_indices);
668 convert->priv->vbo_indices = 0;
673 gst_gl_color_convert_reset_shader (GstGLColorConvert * convert)
675 convert->priv->convert_info.chroma_sampling[0] = 1.0f;
676 convert->priv->convert_info.chroma_sampling[1] = 1.0f;
678 if (convert->priv->convert_info.frag_prog) {
679 g_free (convert->priv->convert_info.frag_prog);
680 convert->priv->convert_info.frag_prog = NULL;
682 if (convert->priv->convert_info.frag_body) {
683 g_free (convert->priv->convert_info.frag_body);
684 convert->priv->convert_info.frag_body = NULL;
686 if (convert->shader) {
687 gst_object_unref (convert->shader);
688 convert->shader = NULL;
691 convert->initted = FALSE;
695 gst_gl_color_convert_reset (GstGLColorConvert * convert)
700 gst_object_unref (convert->fbo);
704 for (i = 0; i < convert->priv->convert_info.out_n_textures; i++) {
705 if (convert->priv->out_tex[i])
706 gst_memory_unref ((GstMemory *) convert->priv->out_tex[i]);
707 convert->priv->out_tex[i] = NULL;
710 if (convert->priv->pool) {
711 convert->priv->pool_started = FALSE;
713 gst_object_unref (convert->priv->pool);
714 convert->priv->pool = NULL;
717 gst_caps_replace (&convert->priv->in_caps, NULL);
718 gst_caps_replace (&convert->priv->out_caps, NULL);
720 if (convert->context) {
721 gst_gl_context_thread_add (convert->context,
722 (GstGLContextThreadFunc) _reset_gl, convert);
725 gst_gl_color_convert_reset_shader (convert);
729 _gst_gl_color_convert_can_passthrough_info (const GstVideoInfo * in,
730 const GstVideoInfo * out)
734 if (GST_VIDEO_INFO_FORMAT (in) != GST_VIDEO_INFO_FORMAT (out))
736 if (GST_VIDEO_INFO_WIDTH (in) != GST_VIDEO_INFO_WIDTH (out))
738 if (GST_VIDEO_INFO_HEIGHT (in) != GST_VIDEO_INFO_HEIGHT (out))
740 if (GST_VIDEO_INFO_SIZE (in) != GST_VIDEO_INFO_SIZE (out))
743 for (i = 0; i < in->finfo->n_planes; i++) {
744 if (in->stride[i] != out->stride[i])
746 if (in->offset[i] != out->offset[i])
750 if (!gst_video_colorimetry_is_equal (&in->colorimetry, &out->colorimetry))
752 if (in->chroma_site != out->chroma_site)
759 _gst_gl_color_convert_set_caps_unlocked (GstGLColorConvert * convert,
760 GstCaps * in_caps, GstCaps * out_caps)
762 GstVideoInfo in_info, out_info;
763 GstCapsFeatures *in_features, *out_features;
764 GstGLTextureTarget from_target, to_target;
765 gboolean passthrough;
767 g_return_val_if_fail (convert != NULL, FALSE);
768 g_return_val_if_fail (in_caps, FALSE);
769 g_return_val_if_fail (out_caps, FALSE);
771 GST_LOG_OBJECT (convert, "Setting caps in %" GST_PTR_FORMAT
772 " out %" GST_PTR_FORMAT, in_caps, out_caps);
774 if (!gst_video_info_from_caps (&in_info, in_caps))
775 g_assert_not_reached ();
777 if (!gst_video_info_from_caps (&out_info, out_caps))
778 g_assert_not_reached ();
780 g_return_val_if_fail (GST_VIDEO_INFO_FORMAT (&in_info) !=
781 GST_VIDEO_FORMAT_UNKNOWN, FALSE);
782 g_return_val_if_fail (GST_VIDEO_INFO_FORMAT (&in_info) !=
783 GST_VIDEO_FORMAT_ENCODED, FALSE);
784 g_return_val_if_fail (GST_VIDEO_INFO_FORMAT (&out_info) !=
785 GST_VIDEO_FORMAT_UNKNOWN, FALSE);
786 g_return_val_if_fail (GST_VIDEO_INFO_FORMAT (&out_info) !=
787 GST_VIDEO_FORMAT_ENCODED, FALSE);
789 in_features = gst_caps_get_features (in_caps, 0);
790 out_features = gst_caps_get_features (out_caps, 0);
792 if (!gst_caps_features_contains (in_features,
793 GST_CAPS_FEATURE_MEMORY_GL_MEMORY)
794 || !gst_caps_features_contains (out_features,
795 GST_CAPS_FEATURE_MEMORY_GL_MEMORY)) {
800 GstStructure *in_s = gst_caps_get_structure (in_caps, 0);
801 GstStructure *out_s = gst_caps_get_structure (out_caps, 0);
803 if (gst_structure_has_field_typed (in_s, "texture-target", G_TYPE_STRING))
805 gst_gl_texture_target_from_string (gst_structure_get_string (in_s,
808 from_target = GST_GL_TEXTURE_TARGET_2D;
810 if (gst_structure_has_field_typed (out_s, "texture-target", G_TYPE_STRING))
812 gst_gl_texture_target_from_string (gst_structure_get_string (out_s,
815 to_target = GST_GL_TEXTURE_TARGET_2D;
817 if (to_target == GST_GL_TEXTURE_TARGET_NONE
818 || from_target == GST_GL_TEXTURE_TARGET_NONE)
823 if (gst_video_info_is_equal (&convert->in_info, &in_info) &&
824 gst_video_info_is_equal (&convert->out_info, &out_info) &&
825 convert->priv->from_texture_target == from_target &&
826 convert->priv->to_texture_target == to_target)
829 /* If input and output are identical, pass through directly */
831 _gst_gl_color_convert_can_passthrough_info (&in_info, &out_info) &&
832 from_target == to_target;
834 if (!passthrough && to_target != GST_GL_TEXTURE_TARGET_2D
835 && to_target != GST_GL_TEXTURE_TARGET_RECTANGLE)
839 guint yuv_gray_flags, in_flags, out_flags;
841 in_flags = GST_VIDEO_FORMAT_INFO_FLAGS (in_info.finfo);
842 out_flags = GST_VIDEO_FORMAT_INFO_FLAGS (out_info.finfo);
843 yuv_gray_flags = GST_VIDEO_FORMAT_FLAG_YUV | GST_VIDEO_FORMAT_FLAG_GRAY;
845 /* GRAY/YUV -> GRAY/YUV is not supported for non-passthrough */
846 if (!passthrough && (in_flags & yuv_gray_flags) != 0
847 && (out_flags & yuv_gray_flags) != 0)
851 gst_gl_color_convert_reset (convert);
852 convert->in_info = in_info;
853 convert->out_info = out_info;
854 gst_caps_replace (&convert->priv->in_caps, in_caps);
855 gst_caps_replace (&convert->priv->out_caps, out_caps);
856 convert->priv->from_texture_target = from_target;
857 convert->priv->to_texture_target = to_target;
858 convert->initted = FALSE;
860 convert->passthrough = passthrough;
861 #ifndef GST_DISABLE_GST_DEBUG
862 if (G_UNLIKELY (convert->passthrough))
863 GST_DEBUG_OBJECT (convert,
864 "Configuring passthrough mode for same in/out caps");
866 GST_DEBUG_OBJECT (convert, "Color converting %" GST_PTR_FORMAT
867 " to %" GST_PTR_FORMAT, in_caps, out_caps);
875 * gst_gl_color_convert_set_caps:
876 * @convert: a #GstGLColorConvert
877 * @in_caps: input #GstCaps
878 * @out_caps: output #GstCaps
880 * Initializes @convert with the information required for conversion.
885 gst_gl_color_convert_set_caps (GstGLColorConvert * convert,
886 GstCaps * in_caps, GstCaps * out_caps)
890 GST_OBJECT_LOCK (convert);
891 ret = _gst_gl_color_convert_set_caps_unlocked (convert, in_caps, out_caps);
892 GST_OBJECT_UNLOCK (convert);
898 * gst_gl_color_convert_decide_allocation:
899 * @convert: a #GstGLColorConvert
900 * @query: a completed ALLOCATION #GstQuery
902 * Provides an implementation of #GstBaseTransformClass.decide_allocation()
904 * Returns: whether the allocation parameters were successfully chosen
909 gst_gl_color_convert_decide_allocation (GstGLColorConvert * convert,
912 GstBufferPool *pool = NULL;
913 GstStructure *config;
915 guint min, max, size, n, i;
916 gboolean update_pool;
917 GstGLVideoAllocationParams *params;
920 gst_query_parse_allocation (query, &caps, NULL);
924 gst_video_info_from_caps (&vinfo, caps);
926 n = gst_query_get_n_allocation_pools (query);
929 for (i = 0; i < n; i++) {
930 gst_query_parse_nth_allocation_pool (query, i, &pool, &size, &min, &max);
932 if (!pool || !GST_IS_GL_BUFFER_POOL (pool)) {
934 gst_object_unref (pool);
943 gst_video_info_init (&vinfo);
950 pool = gst_gl_buffer_pool_new (convert->context);
952 config = gst_buffer_pool_get_config (pool);
954 gst_buffer_pool_config_set_params (config, caps, size, min, max);
955 gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
956 if (gst_query_find_allocation_meta (query, GST_GL_SYNC_META_API_TYPE, NULL))
957 gst_buffer_pool_config_add_option (config,
958 GST_BUFFER_POOL_OPTION_GL_SYNC_META);
960 params = gst_gl_video_allocation_params_new (convert->context, NULL, &vinfo,
961 0, NULL, convert->priv->to_texture_target, 0);
962 gst_buffer_pool_config_set_gl_allocation_params (config,
963 (GstGLAllocationParams *) params);
964 gst_gl_allocation_params_free ((GstGLAllocationParams *) params);
966 if (!gst_buffer_pool_set_config (pool, config))
967 GST_WARNING_OBJECT (convert, "Failed to set buffer pool config");
970 gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
972 gst_query_add_allocation_pool (query, pool, size, min, max);
974 if (convert->priv->pool) {
975 gst_object_unref (convert->priv->pool);
976 convert->priv->pool_started = FALSE;
978 convert->priv->pool = pool;
984 _init_value_string_list (GValue * list, ...)
986 GValue item = G_VALUE_INIT;
990 g_value_init (list, GST_TYPE_LIST);
992 va_start (args, list);
993 while ((str = va_arg (args, gchar *))) {
994 g_value_init (&item, G_TYPE_STRING);
995 g_value_set_string (&item, str);
997 gst_value_list_append_value (list, &item);
998 g_value_unset (&item);
1004 _append_value_string_list (GValue * list, ...)
1006 GValue item = G_VALUE_INIT;
1010 va_start (args, list);
1011 while ((str = va_arg (args, gchar *))) {
1012 g_value_init (&item, G_TYPE_STRING);
1013 g_value_set_string (&item, str);
1015 gst_value_list_append_value (list, &item);
1016 g_value_unset (&item);
1022 _init_supported_formats (GstGLContext * context, gboolean output,
1023 GValue * supported_formats)
1025 /* Assume if context == NULL that we don't have a GL context and can
1026 * do the conversion */
1028 /* Always supported input and output formats */
1029 _init_value_string_list (supported_formats, "RGBA", "RGB", "RGBx", "BGR",
1030 "BGRx", "BGRA", "xRGB", "xBGR", "ARGB", "ABGR", "GRAY8", "GRAY16_LE",
1031 "GRAY16_BE", "AYUV", "VUYA", "YUY2", "UYVY", NULL);
1033 /* Always supported input formats or output with multiple draw buffers */
1034 if (!output || (!context || context->gl_vtable->DrawBuffers))
1035 _append_value_string_list (supported_formats, "GBRA", "GBR", "RGBP", "BGRP",
1036 "Y444", "I420", "YV12", "Y42B", "Y41B", "NV12", "NV21", "NV16", "NV61",
1037 "A420", "AV12", NULL);
1039 /* Requires reading from a RG/LA framebuffer... */
1040 if (!context || (USING_GLES3 (context) || USING_OPENGL (context)))
1041 _append_value_string_list (supported_formats, "YUY2", "UYVY", NULL);
1043 if (!context || gst_gl_format_is_supported (context, GST_GL_RGBA16))
1044 _append_value_string_list (supported_formats, "ARGB64", NULL);
1046 if (!context || gst_gl_format_is_supported (context, GST_GL_RGB565))
1047 _append_value_string_list (supported_formats, "RGB16", "BGR16", NULL);
1049 if (!context || gst_gl_format_is_supported (context, GST_GL_RGB10_A2)) {
1050 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1051 _append_value_string_list (supported_formats, "BGR10A2_LE", "RGB10A2_LE",
1054 _append_value_string_list (supported_formats, "Y410", NULL);
1058 if (!context || (gst_gl_format_is_supported (context, GST_GL_R16) &&
1059 gst_gl_format_is_supported (context, GST_GL_RG16))) {
1060 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1061 _append_value_string_list (supported_formats, "P010_10LE", "P012_LE",
1064 _append_value_string_list (supported_formats, "P010_10BE", "P012_BE",
1069 if (!context || (gst_gl_format_is_supported (context, GST_GL_RG16))) {
1070 _append_value_string_list (supported_formats, "Y210", NULL);
1071 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1072 _append_value_string_list (supported_formats, "Y212_LE", NULL);
1074 _append_value_string_list (supported_formats, "Y212_BE", NULL);
1078 if (!context || gst_gl_format_is_supported (context, GST_GL_RGBA16)) {
1079 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1080 _append_value_string_list (supported_formats, "Y412_LE", NULL);
1082 _append_value_string_list (supported_formats, "Y412_BE", NULL);
1087 /* copies the given caps */
1089 gst_gl_color_convert_caps_transform_format_info (GstGLContext * context,
1090 gboolean output, GstCaps * caps)
1096 GValue supported_formats = G_VALUE_INIT;
1097 GValue rgb_formats = G_VALUE_INIT;
1098 GValue supported_rgb_formats = G_VALUE_INIT;
1100 /* There are effectively two modes here with the RGB/YUV transition:
1101 * 1. There is a RGB-like format as input and we can transform to YUV or,
1102 * 2. No RGB-like format as input so we can only transform to RGB-like formats
1104 * We also filter down the list of formats depending on what the OpenGL
1105 * context supports (when provided).
1108 _init_value_string_list (&rgb_formats, "RGBA", "ARGB", "BGRA", "ABGR", "RGBx",
1109 "xRGB", "BGRx", "xBGR", "RGB", "BGR", "ARGB64", "BGR10A2_LE",
1110 "RGB10A2_LE", NULL);
1111 _init_supported_formats (context, output, &supported_formats);
1112 gst_value_intersect (&supported_rgb_formats, &rgb_formats,
1113 &supported_formats);
1115 res = gst_caps_new_empty ();
1117 n = gst_caps_get_size (caps);
1118 for (i = 0; i < n; i++) {
1119 const GValue *format;
1121 st = gst_caps_get_structure (caps, i);
1122 f = gst_caps_get_features (caps, i);
1124 format = gst_structure_get_value (st, "format");
1125 st = gst_structure_copy (st);
1126 if (GST_VALUE_HOLDS_LIST (format)) {
1127 gboolean have_rgb_formats = FALSE;
1128 GValue passthrough_formats = G_VALUE_INIT;
1131 g_value_init (&passthrough_formats, GST_TYPE_LIST);
1132 len = gst_value_list_get_size (format);
1133 for (j = 0; j < len; j++) {
1136 val = gst_value_list_get_value (format, j);
1137 if (G_VALUE_HOLDS_STRING (val)) {
1138 const gchar *format_str = g_value_get_string (val);
1139 GstVideoFormat v_format = gst_video_format_from_string (format_str);
1140 const GstVideoFormatInfo *t_info =
1141 gst_video_format_get_info (v_format);
1142 if (GST_VIDEO_FORMAT_INFO_FLAGS (t_info) & (GST_VIDEO_FORMAT_FLAG_YUV
1143 | GST_VIDEO_FORMAT_FLAG_GRAY)) {
1144 gst_value_list_append_value (&passthrough_formats, val);
1145 } else if (GST_VIDEO_FORMAT_INFO_FLAGS (t_info) &
1146 GST_VIDEO_FORMAT_FLAG_RGB) {
1147 have_rgb_formats = TRUE;
1152 if (have_rgb_formats) {
1153 gst_structure_set_value (st, "format", &supported_formats);
1155 /* add passthrough structure, then the rgb conversion structure */
1156 gst_structure_set_value (st, "format", &passthrough_formats);
1157 gst_caps_append_structure_full (res, gst_structure_copy (st),
1158 gst_caps_features_copy (f));
1159 gst_structure_set_value (st, "format", &supported_rgb_formats);
1161 g_value_unset (&passthrough_formats);
1162 } else if (G_VALUE_HOLDS_STRING (format)) {
1163 const gchar *format_str = g_value_get_string (format);
1164 GstVideoFormat v_format = gst_video_format_from_string (format_str);
1165 const GstVideoFormatInfo *t_info = gst_video_format_get_info (v_format);
1166 if (GST_VIDEO_FORMAT_INFO_FLAGS (t_info) & (GST_VIDEO_FORMAT_FLAG_YUV |
1167 GST_VIDEO_FORMAT_FLAG_GRAY)) {
1168 /* add passthrough structure, then the rgb conversion structure */
1169 gst_structure_set_value (st, "format", format);
1170 gst_caps_append_structure_full (res, gst_structure_copy (st),
1171 gst_caps_features_copy (f));
1172 gst_structure_set_value (st, "format", &supported_rgb_formats);
1174 gst_structure_set_value (st, "format", &supported_formats);
1177 gst_structure_remove_fields (st, "colorimetry", "chroma-site",
1178 "texture-target", NULL);
1180 gst_caps_append_structure_full (res, st, gst_caps_features_copy (f));
1183 g_value_unset (&supported_formats);
1184 g_value_unset (&rgb_formats);
1185 g_value_unset (&supported_rgb_formats);
1191 * gst_gl_color_convert_transform_caps:
1192 * @context: a #GstGLContext to use for transforming @caps
1193 * @direction: a #GstPadDirection
1194 * @caps: (transfer none): the #GstCaps to transform
1195 * @filter: (transfer none): a set of filter #GstCaps
1197 * Provides an implementation of #GstBaseTransformClass.transform_caps()
1199 * Returns: (transfer full): the converted #GstCaps
1204 gst_gl_color_convert_transform_caps (GstGLContext * context,
1205 GstPadDirection direction, GstCaps * caps, GstCaps * filter)
1207 caps = gst_gl_color_convert_caps_transform_format_info (context,
1208 direction == GST_PAD_SRC, caps);
1213 tmp = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
1214 gst_caps_unref (caps);
1221 /* fixation from videoconvert */
1222 #define SCORE_FORMAT_CHANGE 1
1223 #define SCORE_DEPTH_CHANGE 1
1224 #define SCORE_ALPHA_CHANGE 1
1225 #define SCORE_CHROMA_W_CHANGE 1
1226 #define SCORE_CHROMA_H_CHANGE 1
1227 #define SCORE_PALETTE_CHANGE 1
1229 #define SCORE_COLORSPACE_LOSS 2 /* RGB <-> YUV */
1230 #define SCORE_DEPTH_LOSS 4 /* change bit depth */
1231 #define SCORE_ALPHA_LOSS 8 /* lose the alpha channel */
1232 #define SCORE_CHROMA_W_LOSS 16 /* vertical subsample */
1233 #define SCORE_CHROMA_H_LOSS 32 /* horizontal subsample */
1234 #define SCORE_PALETTE_LOSS 64 /* convert to palette format */
1235 #define SCORE_COLOR_LOSS 128 /* convert to GRAY */
1237 #define COLORSPACE_MASK (GST_VIDEO_FORMAT_FLAG_YUV | \
1238 GST_VIDEO_FORMAT_FLAG_RGB | GST_VIDEO_FORMAT_FLAG_GRAY)
1239 #define ALPHA_MASK (GST_VIDEO_FORMAT_FLAG_ALPHA)
1240 #define PALETTE_MASK (GST_VIDEO_FORMAT_FLAG_PALETTE)
1242 static GstGLTextureTarget
1243 _texture_target_demask (guint target_mask)
1245 if (target_mask & (1 << GST_GL_TEXTURE_TARGET_2D)) {
1246 return GST_GL_TEXTURE_TARGET_2D;
1248 if (target_mask & (1 << GST_GL_TEXTURE_TARGET_RECTANGLE)) {
1249 return GST_GL_TEXTURE_TARGET_RECTANGLE;
1251 if (target_mask & (1 << GST_GL_TEXTURE_TARGET_EXTERNAL_OES)) {
1252 return GST_GL_TEXTURE_TARGET_EXTERNAL_OES;
1258 /* calculate how much loss a conversion would be */
1260 score_format_target (const GstVideoFormatInfo * in_info, guint targets_mask,
1261 GstVideoFormat v_format, guint other_targets_mask, gint * min_loss,
1262 const GstVideoFormatInfo ** out_info, GstGLTextureTarget * result)
1264 const GstVideoFormatInfo *t_info;
1265 GstVideoFormatFlags in_flags, t_flags;
1268 t_info = gst_video_format_get_info (v_format);
1272 /* accept input format immediately without loss */
1273 if (in_info == t_info && (targets_mask & other_targets_mask) != 0) {
1276 *result = _texture_target_demask (targets_mask & other_targets_mask);
1280 /* can only passthrough external-oes textures */
1281 other_targets_mask &= ~(1 << GST_GL_TEXTURE_TARGET_EXTERNAL_OES);
1282 if (other_targets_mask == 0)
1284 /* try to keep the same target */
1285 if (targets_mask & other_targets_mask)
1286 other_targets_mask = targets_mask & other_targets_mask;
1288 loss = SCORE_FORMAT_CHANGE;
1290 in_flags = GST_VIDEO_FORMAT_INFO_FLAGS (in_info);
1291 in_flags &= ~GST_VIDEO_FORMAT_FLAG_LE;
1292 in_flags &= ~GST_VIDEO_FORMAT_FLAG_COMPLEX;
1293 in_flags &= ~GST_VIDEO_FORMAT_FLAG_UNPACK;
1295 t_flags = GST_VIDEO_FORMAT_INFO_FLAGS (t_info);
1296 t_flags &= ~GST_VIDEO_FORMAT_FLAG_LE;
1297 t_flags &= ~GST_VIDEO_FORMAT_FLAG_COMPLEX;
1298 t_flags &= ~GST_VIDEO_FORMAT_FLAG_UNPACK;
1300 /* GRAY/YUV -> GRAY/YUV is not supported */
1301 if ((in_flags & (GST_VIDEO_FORMAT_FLAG_YUV | GST_VIDEO_FORMAT_FLAG_GRAY)) != 0
1302 && (t_flags & (GST_VIDEO_FORMAT_FLAG_YUV | GST_VIDEO_FORMAT_FLAG_GRAY)) !=
1306 if ((t_flags & PALETTE_MASK) != (in_flags & PALETTE_MASK)) {
1307 loss += SCORE_PALETTE_CHANGE;
1308 if (t_flags & PALETTE_MASK)
1309 loss += SCORE_PALETTE_LOSS;
1312 if ((t_flags & COLORSPACE_MASK) != (in_flags & COLORSPACE_MASK)) {
1313 loss += SCORE_COLORSPACE_LOSS;
1314 if (t_flags & GST_VIDEO_FORMAT_FLAG_GRAY)
1315 loss += SCORE_COLOR_LOSS;
1318 if ((t_flags & ALPHA_MASK) != (in_flags & ALPHA_MASK)) {
1319 loss += SCORE_ALPHA_CHANGE;
1320 if (in_flags & ALPHA_MASK)
1321 loss += SCORE_ALPHA_LOSS;
1324 if ((in_info->h_sub[1]) != (t_info->h_sub[1])) {
1325 loss += SCORE_CHROMA_H_CHANGE;
1326 if ((in_info->h_sub[1]) < (t_info->h_sub[1]))
1327 loss += SCORE_CHROMA_H_LOSS;
1329 if ((in_info->w_sub[1]) != (t_info->w_sub[1])) {
1330 loss += SCORE_CHROMA_W_CHANGE;
1331 if ((in_info->w_sub[1]) < (t_info->w_sub[1]))
1332 loss += SCORE_CHROMA_W_LOSS;
1335 if ((in_info->bits) != (t_info->bits)) {
1336 loss += SCORE_DEPTH_CHANGE;
1337 if ((in_info->bits) > (t_info->bits))
1338 loss += SCORE_DEPTH_LOSS;
1341 if (loss < *min_loss) {
1342 GstGLTextureTarget target = _texture_target_demask (other_targets_mask);
1353 gst_gl_color_convert_fixate_format_target (GstCaps * caps, GstCaps * result)
1355 GstStructure *ins, *outs;
1356 const gchar *in_format;
1357 const GstVideoFormatInfo *in_info, *out_info = NULL;
1358 const GValue *targets;
1359 guint targets_mask = 0;
1360 GstGLTextureTarget target;
1361 gint min_loss = G_MAXINT;
1364 ins = gst_caps_get_structure (caps, 0);
1365 in_format = gst_structure_get_string (ins, "format");
1368 targets = gst_structure_get_value (ins, "texture-target");
1369 targets_mask = gst_gl_value_get_texture_target_mask (targets);
1374 gst_video_format_get_info (gst_video_format_from_string (in_format));
1378 outs = gst_caps_get_structure (result, 0);
1380 capslen = gst_caps_get_size (result);
1381 for (i = 0; i < capslen; i++) {
1382 GstStructure *tests;
1383 const GValue *format;
1384 const GValue *other_targets;
1385 guint other_targets_mask = 0;
1387 tests = gst_caps_get_structure (result, i);
1389 format = gst_structure_get_value (tests, "format");
1390 other_targets = gst_structure_get_value (tests, "texture-target");
1391 /* should not happen */
1392 if (format == NULL || other_targets == NULL)
1395 other_targets_mask = gst_gl_value_get_texture_target_mask (other_targets);
1397 if (GST_VALUE_HOLDS_LIST (format)) {
1400 len = gst_value_list_get_size (format);
1401 for (j = 0; j < len; j++) {
1404 val = gst_value_list_get_value (format, j);
1405 if (G_VALUE_HOLDS_STRING (val)) {
1406 const gchar *format_str = g_value_get_string (val);
1407 GstVideoFormat v_format = gst_video_format_from_string (format_str);
1408 score_format_target (in_info, targets_mask, v_format,
1409 other_targets_mask, &min_loss, &out_info, &target);
1414 } else if (G_VALUE_HOLDS_STRING (format)) {
1415 const gchar *format_str = g_value_get_string (format);
1416 GstVideoFormat v_format = gst_video_format_from_string (format_str);
1417 score_format_target (in_info, targets_mask, v_format, other_targets_mask,
1418 &min_loss, &out_info, &target);
1422 gst_structure_set (outs, "format", G_TYPE_STRING,
1423 GST_VIDEO_FORMAT_INFO_NAME (out_info), NULL);
1425 gst_structure_set (outs, "texture-target", G_TYPE_STRING,
1426 gst_gl_texture_target_to_string (target), NULL);
1430 * gst_gl_color_convert_fixate_caps:
1431 * @context: a #GstGLContext to use for transforming @caps
1432 * @direction: a #GstPadDirection
1433 * @caps: (transfer none): the #GstCaps of @direction
1434 * @other: (transfer full): the #GstCaps to fixate
1436 * Provides an implementation of #GstBaseTransformClass.fixate_caps()
1438 * Returns: (transfer full): the fixated #GstCaps
1443 gst_gl_color_convert_fixate_caps (GstGLContext * context,
1444 GstPadDirection direction, GstCaps * caps, GstCaps * other)
1448 result = gst_caps_intersect (other, caps);
1449 if (gst_caps_is_empty (result)) {
1450 gst_caps_unref (result);
1453 gst_caps_unref (other);
1456 result = gst_caps_make_writable (result);
1457 gst_gl_color_convert_fixate_format_target (caps, result);
1459 result = gst_caps_fixate (result);
1461 if (direction == GST_PAD_SINK) {
1462 if (gst_caps_is_subset (caps, result)) {
1463 gst_caps_replace (&result, caps);
1471 * gst_gl_color_convert_perform:
1472 * @convert: a #GstGLColorConvert
1473 * @inbuf: (transfer none): the #GstGLMemory filled #GstBuffer to convert
1475 * Converts the data contained by @inbuf using the formats specified by the
1476 * #GstCaps passed to gst_gl_color_convert_set_caps()
1478 * Returns: (transfer full): a converted #GstBuffer or %NULL
1483 gst_gl_color_convert_perform (GstGLColorConvert * convert, GstBuffer * inbuf)
1487 g_return_val_if_fail (convert != NULL, FALSE);
1489 GST_OBJECT_LOCK (convert);
1490 ret = _gst_gl_color_convert_perform_unlocked (convert, inbuf);
1491 GST_OBJECT_UNLOCK (convert);
1497 _gst_gl_color_convert_perform_unlocked (GstGLColorConvert * convert,
1500 g_return_val_if_fail (convert != NULL, FALSE);
1501 g_return_val_if_fail (inbuf, FALSE);
1503 if (G_UNLIKELY (convert->passthrough))
1504 return gst_buffer_ref (inbuf);
1506 convert->inbuf = inbuf;
1508 gst_gl_context_thread_add (convert->context,
1509 (GstGLContextThreadFunc) _do_convert, convert);
1511 if (!convert->priv->result) {
1512 if (convert->outbuf)
1513 gst_buffer_unref (convert->outbuf);
1514 convert->outbuf = NULL;
1518 return convert->outbuf;
1521 static inline gboolean
1522 _is_RGBx (GstVideoFormat v_format)
1525 case GST_VIDEO_FORMAT_RGBx:
1526 case GST_VIDEO_FORMAT_xRGB:
1527 case GST_VIDEO_FORMAT_BGRx:
1528 case GST_VIDEO_FORMAT_xBGR:
1535 static inline gboolean
1536 _is_planar_rgb (GstVideoFormat v_format)
1539 case GST_VIDEO_FORMAT_GBR:
1540 case GST_VIDEO_FORMAT_RGBP:
1541 case GST_VIDEO_FORMAT_BGRP:
1542 case GST_VIDEO_FORMAT_GBR_10BE:
1543 case GST_VIDEO_FORMAT_GBR_10LE:
1544 case GST_VIDEO_FORMAT_GBRA:
1545 case GST_VIDEO_FORMAT_GBRA_10BE:
1546 case GST_VIDEO_FORMAT_GBRA_10LE:
1547 case GST_VIDEO_FORMAT_GBR_12BE:
1548 case GST_VIDEO_FORMAT_GBR_12LE:
1549 case GST_VIDEO_FORMAT_GBRA_12BE:
1550 case GST_VIDEO_FORMAT_GBRA_12LE:
1558 _index_to_shader_swizzle (int idx)
1574 /* attempts to transform expected to want using swizzling */
1576 _RGB_pixel_order (const gchar * expected, const gchar * wanted)
1578 GString *ret = g_string_sized_new (4);
1579 gchar *expect, *want;
1582 gboolean discard_output = TRUE;
1584 if (g_ascii_strcasecmp (expected, wanted) == 0) {
1585 g_string_free (ret, TRUE);
1586 return g_ascii_strdown (expected, -1);
1589 expect = g_ascii_strdown (expected, -1);
1590 orig_want = want = g_ascii_strdown (wanted, -1);
1592 if (strcmp (expect, "rgb16") == 0 || strcmp (expect, "bgr16") == 0) {
1593 gchar *temp = expect;
1594 expect = g_strndup (temp, 3);
1596 } else if (strcmp (expect, "bgr10a2_le") == 0) {
1597 gchar *temp = expect;
1598 expect = g_strndup ("bgra", 4);
1600 } else if (strcmp (expect, "rgb10a2_le") == 0) {
1601 gchar *temp = expect;
1602 expect = g_strndup ("rgba", 4);
1604 } else if (strcmp (expect, "rgbp") == 0 || strcmp (expect, "bgrp") == 0) {
1605 gchar *temp = expect;
1606 expect = g_strndup (temp, 3);
1610 if (strcmp (want, "rgb16") == 0 || strcmp (want, "bgr16") == 0) {
1612 orig_want = want = g_strndup (temp, 3);
1614 } else if (strcmp (want, "bgr10a2_le") == 0) {
1616 orig_want = want = g_strndup ("bgra", 4);
1618 } else if (strcmp (want, "rgb10a2_le") == 0) {
1620 orig_want = want = g_strndup ("rgba", 4);
1624 /* pad want with 'a's */
1625 if ((len = strlen (want)) < 4) {
1626 gchar *new_want = g_strndup (want, 4);
1628 new_want[len] = 'a';
1632 orig_want = want = new_want;
1635 /* pad expect with 'a's */
1636 if ((len = strlen (expect)) < 4) {
1637 gchar *new_expect = g_strndup (expect, 4);
1639 new_expect[len] = 'a';
1643 expect = new_expect;
1646 /* build the swizzle format */
1647 while (want && want[0] != '\0') {
1650 gchar needle = want[0];
1655 if (!(val = strchr (expect, needle))
1656 && needle == 'a' && !(val = strchr (expect, 'x')))
1659 idx = (gint) (val - expect);
1661 ret = g_string_append_c (ret, _index_to_shader_swizzle (idx));
1665 discard_output = FALSE;
1670 return g_string_free (ret, discard_output);
1674 _get_n_textures (GstVideoFormat v_format)
1677 case GST_VIDEO_FORMAT_RGBA:
1678 case GST_VIDEO_FORMAT_RGBx:
1679 case GST_VIDEO_FORMAT_ARGB:
1680 case GST_VIDEO_FORMAT_xRGB:
1681 case GST_VIDEO_FORMAT_BGRA:
1682 case GST_VIDEO_FORMAT_BGRx:
1683 case GST_VIDEO_FORMAT_ABGR:
1684 case GST_VIDEO_FORMAT_xBGR:
1685 case GST_VIDEO_FORMAT_RGB:
1686 case GST_VIDEO_FORMAT_BGR:
1687 case GST_VIDEO_FORMAT_AYUV:
1688 case GST_VIDEO_FORMAT_VUYA:
1689 case GST_VIDEO_FORMAT_GRAY8:
1690 case GST_VIDEO_FORMAT_GRAY16_LE:
1691 case GST_VIDEO_FORMAT_GRAY16_BE:
1692 case GST_VIDEO_FORMAT_YUY2:
1693 case GST_VIDEO_FORMAT_UYVY:
1694 case GST_VIDEO_FORMAT_RGB16:
1695 case GST_VIDEO_FORMAT_BGR16:
1696 case GST_VIDEO_FORMAT_ARGB64:
1697 case GST_VIDEO_FORMAT_BGR10A2_LE:
1698 case GST_VIDEO_FORMAT_RGB10A2_LE:
1699 case GST_VIDEO_FORMAT_Y410:
1700 case GST_VIDEO_FORMAT_Y210:
1701 case GST_VIDEO_FORMAT_Y212_LE:
1702 case GST_VIDEO_FORMAT_Y212_BE:
1703 case GST_VIDEO_FORMAT_Y412_LE:
1704 case GST_VIDEO_FORMAT_Y412_BE:
1706 case GST_VIDEO_FORMAT_NV12:
1707 case GST_VIDEO_FORMAT_NV21:
1708 case GST_VIDEO_FORMAT_NV16:
1709 case GST_VIDEO_FORMAT_NV61:
1710 case GST_VIDEO_FORMAT_P010_10LE:
1711 case GST_VIDEO_FORMAT_P010_10BE:
1712 case GST_VIDEO_FORMAT_P012_LE:
1713 case GST_VIDEO_FORMAT_P012_BE:
1714 case GST_VIDEO_FORMAT_P016_LE:
1715 case GST_VIDEO_FORMAT_P016_BE:
1717 case GST_VIDEO_FORMAT_I420:
1718 case GST_VIDEO_FORMAT_Y444:
1719 case GST_VIDEO_FORMAT_Y42B:
1720 case GST_VIDEO_FORMAT_Y41B:
1721 case GST_VIDEO_FORMAT_YV12:
1722 case GST_VIDEO_FORMAT_GBR:
1723 case GST_VIDEO_FORMAT_RGBP:
1724 case GST_VIDEO_FORMAT_BGRP:
1725 case GST_VIDEO_FORMAT_AV12:
1727 case GST_VIDEO_FORMAT_GBRA:
1728 case GST_VIDEO_FORMAT_A420:
1731 g_assert_not_reached ();
1737 _PLANAR_RGB_to_PLANAR_RGB (GstGLColorConvert * convert)
1739 struct ConvertInfo *info = &convert->priv->convert_info;
1740 GstVideoFormat in_format = GST_VIDEO_INFO_FORMAT (&convert->in_info);
1741 const gchar *in_format_str = gst_video_format_to_string (in_format);
1742 GstVideoFormat out_format = GST_VIDEO_INFO_FORMAT (&convert->out_info);
1743 const gchar *out_format_str = gst_video_format_to_string (out_format);
1744 gchar *pixel_order = _RGB_pixel_order (in_format_str, out_format_str);
1745 const gchar *in_alpha = NULL;
1746 gchar *out_alpha = NULL;
1748 info->frag_prog = NULL;
1750 if (GST_VIDEO_INFO_HAS_ALPHA (&convert->in_info)) {
1751 in_alpha = "rgba.a = texture2D(Atex, texcoord * tex_scale3).r;";
1752 info->shader_tex_names[0] = "Rtex";
1753 info->shader_tex_names[1] = "Gtex";
1754 info->shader_tex_names[2] = "Btex";
1755 info->shader_tex_names[3] = "Atex";
1757 in_alpha = "rgba.a = 1.0;";
1758 info->shader_tex_names[0] = "Rtex";
1759 info->shader_tex_names[1] = "Gtex";
1760 info->shader_tex_names[2] = "Btex";
1763 if (GST_VIDEO_INFO_HAS_ALPHA (&convert->out_info)) {
1765 g_strdup_printf ("gl_FragData[3] = vec4(rgba.%c, 0, 0, 1.0);",
1767 info->out_n_textures = 4;
1769 out_alpha = g_strdup_printf ("\n");
1770 info->out_n_textures = 3;
1773 info->templ = &templ_PLANAR_RGB_to_PLANAR_RGB;
1775 g_strdup_printf (templ_PLANAR_RGB_to_PLANAR_RGB_BODY, in_alpha,
1776 pixel_order[0], pixel_order[1], pixel_order[2], out_alpha);
1779 g_free (pixel_order);
1783 _PLANAR_RGB_to_PACKED_RGB (GstGLColorConvert * convert)
1785 struct ConvertInfo *info = &convert->priv->convert_info;
1786 GstVideoFormat in_format = GST_VIDEO_INFO_FORMAT (&convert->in_info);
1787 const gchar *in_format_str = gst_video_format_to_string (in_format);
1788 GstVideoFormat out_format = GST_VIDEO_INFO_FORMAT (&convert->out_info);
1789 const gchar *out_format_str = gst_video_format_to_string (out_format);
1790 gchar *pixel_order = _RGB_pixel_order (in_format_str, out_format_str);
1791 const gchar *alpha = NULL;
1793 info->frag_prog = NULL;
1795 if (GST_VIDEO_INFO_HAS_ALPHA (&convert->in_info)) {
1796 alpha = "rgba.a = texture2D(Atex, texcoord * tex_scale3).r;";
1797 info->shader_tex_names[0] = "Rtex";
1798 info->shader_tex_names[1] = "Gtex";
1799 info->shader_tex_names[2] = "Btex";
1800 info->shader_tex_names[3] = "Atex";
1802 alpha = "rgba.a = 1.0;";
1803 info->shader_tex_names[0] = "Rtex";
1804 info->shader_tex_names[1] = "Gtex";
1805 info->shader_tex_names[2] = "Btex";
1808 info->out_n_textures = 1;
1810 info->templ = &templ_PLANAR_RGB_to_PACKED_RGB;
1811 info->frag_body = g_strdup_printf (templ_PLANAR_RGB_to_PACKED_RGB_BODY, alpha,
1812 pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3]);
1814 g_free (pixel_order);
1818 _PACKED_RGB_to_PLANAR_RGB (GstGLColorConvert * convert)
1820 struct ConvertInfo *info = &convert->priv->convert_info;
1821 GstVideoFormat in_format = GST_VIDEO_INFO_FORMAT (&convert->in_info);
1822 const gchar *in_format_str = gst_video_format_to_string (in_format);
1823 GstVideoFormat out_format = GST_VIDEO_INFO_FORMAT (&convert->out_info);
1824 const gchar *out_format_str = gst_video_format_to_string (out_format);
1825 gchar *pixel_order = _RGB_pixel_order (in_format_str, out_format_str);
1828 info->frag_prog = NULL;
1829 info->shader_tex_names[0] = "tex";
1831 if (GST_VIDEO_INFO_HAS_ALPHA (&convert->out_info)) {
1832 alpha = "gl_FragData[3] = vec4(rgba.a, 0, 0, 1.0);";
1833 info->out_n_textures = 4;
1836 info->out_n_textures = 3;
1839 info->templ = &templ_PACKED_RGB_to_PLANAR_RGB;
1840 info->frag_body = g_strdup_printf (templ_PACKED_RGB_to_PLANAR_RGB_BODY,
1841 pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3], alpha);
1842 info->shader_tex_names[0] = "tex";
1844 g_free (pixel_order);
1848 _PACKED_RGB_to_PACKED_RGB (GstGLColorConvert * convert)
1850 struct ConvertInfo *info = &convert->priv->convert_info;
1851 GstVideoFormat in_format = GST_VIDEO_INFO_FORMAT (&convert->in_info);
1852 const gchar *in_format_str = gst_video_format_to_string (in_format);
1853 GstVideoFormat out_format = GST_VIDEO_INFO_FORMAT (&convert->out_info);
1854 const gchar *out_format_str = gst_video_format_to_string (out_format);
1855 gchar *pixel_order = _RGB_pixel_order (in_format_str, out_format_str);
1856 gchar *alpha = NULL;
1858 if (_is_RGBx (in_format)) {
1860 char input_alpha_channel = 'a';
1861 for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) {
1862 if (in_format_str[i] == 'X' || in_format_str[i] == 'x') {
1863 input_alpha_channel = _index_to_shader_swizzle (i);
1867 alpha = g_strdup_printf ("t.%c = 1.0;", input_alpha_channel);
1869 info->templ = &templ_REORDER;
1870 info->frag_body = g_strdup_printf (templ_REORDER_BODY, alpha ? alpha : "",
1871 pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3]);
1872 info->shader_tex_names[0] = "tex";
1875 g_free (pixel_order);
1879 _RGB_to_RGB (GstGLColorConvert * convert)
1881 GstVideoFormat in_format = GST_VIDEO_INFO_FORMAT (&convert->in_info);
1882 GstVideoFormat out_format = GST_VIDEO_INFO_FORMAT (&convert->out_info);
1884 if (_is_planar_rgb (in_format)) {
1885 if (_is_planar_rgb (out_format))
1886 _PLANAR_RGB_to_PLANAR_RGB (convert);
1888 _PLANAR_RGB_to_PACKED_RGB (convert);
1890 if (_is_planar_rgb (out_format))
1891 _PACKED_RGB_to_PLANAR_RGB (convert);
1893 _PACKED_RGB_to_PACKED_RGB (convert);
1898 _YUV_to_RGB (GstGLColorConvert * convert)
1900 struct ConvertInfo *info = &convert->priv->convert_info;
1901 GstVideoFormat out_format = GST_VIDEO_INFO_FORMAT (&convert->out_info);
1902 const gchar *out_format_str = gst_video_format_to_string (out_format);
1903 gchar *pixel_order = _RGB_pixel_order ("rgba", out_format_str);
1904 gboolean apple_ycbcr = gst_gl_context_check_feature (convert->context,
1905 "GL_APPLE_ycbcr_422");
1906 gboolean in_tex_rectangular = FALSE;
1908 #if GST_GL_HAVE_OPENGL
1909 GstMemory *memory = gst_buffer_peek_memory (convert->inbuf, 0);
1910 if (gst_is_gl_memory (memory) && (USING_OPENGL (convert->context)
1911 || USING_OPENGL3 (convert->context))) {
1912 in_tex_rectangular =
1913 convert->priv->from_texture_target == GST_GL_TEXTURE_TARGET_RECTANGLE;
1917 info->out_n_textures = 1;
1919 if (in_tex_rectangular && apple_ycbcr
1920 && gst_buffer_n_memory (convert->inbuf) == 1) {
1921 /* FIXME: We should probably also check if tex_target actually is using
1922 * the Apple YCbCr422 extension. It could also be a normal UYVY texture
1923 * with RB or Lum/Alpha
1925 /* The mangling will change this to the correct texture2DRect, sampler2DRect
1927 info->templ = &templ_REORDER;
1929 g_strdup_printf (templ_REORDER_BODY, "", pixel_order[0], pixel_order[1],
1930 pixel_order[2], pixel_order[3]);
1931 info->shader_tex_names[0] = "tex";
1933 switch (GST_VIDEO_INFO_FORMAT (&convert->in_info)) {
1934 case GST_VIDEO_FORMAT_AYUV:
1935 info->templ = &templ_AYUV_to_RGB;
1936 info->frag_body = g_strdup_printf (templ_AYUV_to_RGB_BODY, "yzw", 'x',
1937 pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3]);
1938 info->shader_tex_names[0] = "tex";
1940 case GST_VIDEO_FORMAT_VUYA:
1941 info->templ = &templ_AYUV_to_RGB;
1942 info->frag_body = g_strdup_printf (templ_AYUV_to_RGB_BODY, "zyx", 'w',
1943 pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3]);
1944 info->shader_tex_names[0] = "tex";
1946 case GST_VIDEO_FORMAT_Y410:
1947 case GST_VIDEO_FORMAT_Y412_LE:
1948 case GST_VIDEO_FORMAT_Y412_BE:
1949 info->templ = &templ_AYUV_to_RGB;
1950 info->frag_body = g_strdup_printf (templ_AYUV_to_RGB_BODY, "yxz", 'w',
1951 pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3]);
1952 info->shader_tex_names[0] = "tex";
1954 case GST_VIDEO_FORMAT_I420:
1955 case GST_VIDEO_FORMAT_Y444:
1956 case GST_VIDEO_FORMAT_Y42B:
1957 case GST_VIDEO_FORMAT_Y41B:
1958 info->templ = &templ_PLANAR_YUV_to_RGB;
1960 g_strdup_printf (templ_PLANAR_YUV_to_RGB_BODY, pixel_order[0],
1961 pixel_order[1], pixel_order[2], pixel_order[3]);
1962 info->shader_tex_names[0] = "Ytex";
1963 info->shader_tex_names[1] = "Utex";
1964 info->shader_tex_names[2] = "Vtex";
1966 case GST_VIDEO_FORMAT_A420:
1967 info->templ = &templ_A420_to_RGB;
1969 g_strdup_printf (templ_A420_to_RGB_BODY, pixel_order[0],
1970 pixel_order[1], pixel_order[2], pixel_order[3]);
1971 info->shader_tex_names[0] = "Ytex";
1972 info->shader_tex_names[1] = "Utex";
1973 info->shader_tex_names[2] = "Vtex";
1974 info->shader_tex_names[3] = "Atex";
1976 case GST_VIDEO_FORMAT_YV12:
1977 info->templ = &templ_PLANAR_YUV_to_RGB;
1979 g_strdup_printf (templ_PLANAR_YUV_to_RGB_BODY, pixel_order[0],
1980 pixel_order[1], pixel_order[2], pixel_order[3]);
1981 info->shader_tex_names[0] = "Ytex";
1982 info->shader_tex_names[1] = "Vtex";
1983 info->shader_tex_names[2] = "Utex";
1985 case GST_VIDEO_FORMAT_YUY2:
1987 char uv_val = convert->priv->in_tex_formats[0] == GST_GL_RG ? 'g' : 'a';
1988 info->templ = &templ_YUY2_UYVY_to_RGB;
1990 g_strdup_printf (templ_YUY2_UYVY_to_RGB_BODY, 'r', uv_val, uv_val,
1991 'g', 'a', pixel_order[0], pixel_order[1], pixel_order[2],
1993 info->shader_tex_names[0] = "Ytex";
1996 case GST_VIDEO_FORMAT_UYVY:
1998 char y_val = convert->priv->in_tex_formats[0] == GST_GL_RG ? 'g' : 'a';
1999 info->templ = &templ_YUY2_UYVY_to_RGB;
2001 g_strdup_printf (templ_YUY2_UYVY_to_RGB_BODY, y_val, 'g', 'g', 'r',
2002 'b', pixel_order[0], pixel_order[1], pixel_order[2],
2004 info->shader_tex_names[0] = "Ytex";
2007 case GST_VIDEO_FORMAT_Y210:
2008 case GST_VIDEO_FORMAT_Y212_LE:
2009 case GST_VIDEO_FORMAT_Y212_BE:
2011 info->templ = &templ_YUY2_UYVY_to_RGB;
2013 g_strdup_printf (templ_YUY2_UYVY_to_RGB_BODY, 'r', 'g', 'g',
2014 'g', 'a', pixel_order[0], pixel_order[1], pixel_order[2],
2016 info->shader_tex_names[0] = "Ytex";
2019 case GST_VIDEO_FORMAT_NV12:
2020 case GST_VIDEO_FORMAT_NV16:
2022 char val2 = convert->priv->in_tex_formats[1] == GST_GL_RG ? 'g' : 'a';
2023 info->templ = &templ_SEMI_PLANAR_to_RGB;
2025 g_strdup_printf (templ_SEMI_PLANAR_to_RGB_BODY, 'r', val2,
2026 pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3]);
2027 info->shader_tex_names[0] = "Ytex";
2028 info->shader_tex_names[1] = "UVtex";
2031 case GST_VIDEO_FORMAT_AV12:
2033 info->templ = &templ_AV12_to_RGB;
2035 g_strdup_printf (templ_AV12_to_RGB_BODY,
2036 pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3]);
2037 info->shader_tex_names[0] = "Ytex";
2038 info->shader_tex_names[1] = "UVtex";
2039 info->shader_tex_names[2] = "Atex";
2042 case GST_VIDEO_FORMAT_NV21:
2043 case GST_VIDEO_FORMAT_NV61:
2045 char val2 = convert->priv->in_tex_formats[1] == GST_GL_RG ? 'g' : 'a';
2046 info->templ = &templ_SEMI_PLANAR_to_RGB;
2048 g_strdup_printf (templ_SEMI_PLANAR_to_RGB_BODY, val2, 'r',
2049 pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3]);
2050 info->shader_tex_names[0] = "Ytex";
2051 info->shader_tex_names[1] = "UVtex";
2054 case GST_VIDEO_FORMAT_P010_10LE:
2055 case GST_VIDEO_FORMAT_P010_10BE:
2056 case GST_VIDEO_FORMAT_P012_LE:
2057 case GST_VIDEO_FORMAT_P012_BE:
2058 case GST_VIDEO_FORMAT_P016_LE:
2059 case GST_VIDEO_FORMAT_P016_BE:
2061 info->templ = &templ_SEMI_PLANAR_to_RGB;
2063 g_strdup_printf (templ_SEMI_PLANAR_to_RGB_BODY, 'r', 'g',
2064 pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3]);
2065 info->shader_tex_names[0] = "Ytex";
2066 info->shader_tex_names[1] = "UVtex";
2074 if (gst_video_colorimetry_matches (&convert->in_info.colorimetry,
2075 GST_VIDEO_COLORIMETRY_BT709)) {
2076 info->cms_offset = (gfloat *) from_yuv_bt709_offset;
2077 info->cms_coeff1 = (gfloat *) from_yuv_bt709_rcoeff;
2078 info->cms_coeff2 = (gfloat *) from_yuv_bt709_gcoeff;
2079 info->cms_coeff3 = (gfloat *) from_yuv_bt709_bcoeff;
2081 /* defaults/bt601 */
2082 info->cms_offset = (gfloat *) from_yuv_bt601_offset;
2083 info->cms_coeff1 = (gfloat *) from_yuv_bt601_rcoeff;
2084 info->cms_coeff2 = (gfloat *) from_yuv_bt601_gcoeff;
2085 info->cms_coeff3 = (gfloat *) from_yuv_bt601_bcoeff;
2088 g_free (pixel_order);
2092 _RGB_to_YUV (GstGLColorConvert * convert)
2094 struct ConvertInfo *info = &convert->priv->convert_info;
2095 GstVideoFormat in_format = GST_VIDEO_INFO_FORMAT (&convert->in_info);
2096 const gchar *in_format_str = gst_video_format_to_string (in_format);
2097 GstVideoFormat out_format = GST_VIDEO_INFO_FORMAT (&convert->out_info);
2098 gchar *pixel_order = _RGB_pixel_order (in_format_str, "rgba");
2101 info->frag_prog = NULL;
2103 info->shader_tex_names[0] = "tex";
2105 switch (out_format) {
2106 case GST_VIDEO_FORMAT_AYUV:
2107 alpha = _is_RGBx (in_format) ? "1.0" : "texel.a";
2108 info->templ = &templ_RGB_to_AYUV;
2109 info->frag_body = g_strdup_printf (templ_RGB_to_AYUV_BODY, pixel_order[0],
2110 pixel_order[1], pixel_order[2], pixel_order[3], "yzw", 'x', alpha);
2111 info->out_n_textures = 1;
2113 case GST_VIDEO_FORMAT_VUYA:
2114 alpha = _is_RGBx (in_format) ? "1.0" : "texel.a";
2115 info->templ = &templ_RGB_to_AYUV;
2116 info->frag_body = g_strdup_printf (templ_RGB_to_AYUV_BODY, pixel_order[0],
2117 pixel_order[1], pixel_order[2], pixel_order[3], "zyx", 'w', alpha);
2118 info->out_n_textures = 1;
2120 case GST_VIDEO_FORMAT_Y410:
2121 case GST_VIDEO_FORMAT_Y412_LE:
2122 case GST_VIDEO_FORMAT_Y412_BE:
2123 alpha = _is_RGBx (in_format) ? "1.0" : "texel.a";
2124 info->templ = &templ_RGB_to_AYUV;
2125 info->frag_body = g_strdup_printf (templ_RGB_to_AYUV_BODY, pixel_order[0],
2126 pixel_order[1], pixel_order[2], pixel_order[3], "yxz", 'w', alpha);
2127 info->out_n_textures = 1;
2129 case GST_VIDEO_FORMAT_I420:
2130 case GST_VIDEO_FORMAT_YV12:
2131 case GST_VIDEO_FORMAT_Y444:
2132 case GST_VIDEO_FORMAT_Y42B:
2133 case GST_VIDEO_FORMAT_Y41B:
2134 case GST_VIDEO_FORMAT_A420:
2135 info->templ = &templ_RGB_to_PLANAR_YUV;
2136 if (out_format == GST_VIDEO_FORMAT_A420) {
2137 alpha = "gl_FragData[3] = vec4(texel.a, 0.0, 0.0, 1.0);\n";
2138 info->out_n_textures = 4;
2141 info->out_n_textures = 3;
2143 info->frag_body = g_strdup_printf (templ_RGB_to_PLANAR_YUV_BODY,
2144 pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3],
2145 pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3],
2147 if (out_format == GST_VIDEO_FORMAT_Y444) {
2148 info->chroma_sampling[0] = info->chroma_sampling[1] = 1.0f;
2149 } else if (out_format == GST_VIDEO_FORMAT_Y42B) {
2150 info->chroma_sampling[0] = 2.0f;
2151 info->chroma_sampling[1] = 1.0f;
2152 } else if (out_format == GST_VIDEO_FORMAT_Y41B) {
2153 info->chroma_sampling[0] = 4.0f;
2154 info->chroma_sampling[1] = 1.0f;
2156 info->chroma_sampling[0] = info->chroma_sampling[1] = 2.0f;
2159 case GST_VIDEO_FORMAT_YUY2:
2160 case GST_VIDEO_FORMAT_Y210:
2161 case GST_VIDEO_FORMAT_Y212_LE:
2162 case GST_VIDEO_FORMAT_Y212_BE:
2163 info->templ = &templ_RGB_to_YUY2_UYVY;
2164 info->frag_body = g_strdup_printf (templ_RGB_to_YUY2_UYVY_BODY,
2165 pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3],
2166 pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3],
2167 'x', 'y', 'x', 'z');
2168 info->out_n_textures = 1;
2170 case GST_VIDEO_FORMAT_UYVY:
2171 info->templ = &templ_RGB_to_YUY2_UYVY,
2172 info->frag_body = g_strdup_printf (templ_RGB_to_YUY2_UYVY_BODY,
2173 pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3],
2174 pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3],
2175 'y', 'x', 'z', 'x');
2176 info->out_n_textures = 1;
2178 case GST_VIDEO_FORMAT_NV12:
2179 case GST_VIDEO_FORMAT_NV16:
2180 info->templ = &templ_RGB_to_SEMI_PLANAR_YUV,
2181 info->frag_body = g_strdup_printf (templ_RGB_to_SEMI_PLANAR_YUV_BODY,
2182 pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3],
2183 pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3],
2185 info->out_n_textures = 2;
2186 if (out_format == GST_VIDEO_FORMAT_NV16) {
2187 info->chroma_sampling[0] = 2.0f;
2188 info->chroma_sampling[1] = 1.0f;
2190 info->chroma_sampling[0] = info->chroma_sampling[1] = 2.0f;
2193 case GST_VIDEO_FORMAT_AV12:
2194 info->templ = &templ_RGB_to_AV12,
2195 info->frag_body = g_strdup_printf (templ_RGB_to_AV12_BODY,
2196 pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3],
2197 pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3]);
2198 info->out_n_textures = 3;
2199 info->chroma_sampling[0] = info->chroma_sampling[1] = 2.0f;
2201 case GST_VIDEO_FORMAT_NV21:
2202 case GST_VIDEO_FORMAT_NV61:
2203 info->templ = &templ_RGB_to_SEMI_PLANAR_YUV,
2204 info->frag_body = g_strdup_printf (templ_RGB_to_SEMI_PLANAR_YUV_BODY,
2205 pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3],
2206 pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3],
2208 info->out_n_textures = 2;
2209 if (out_format == GST_VIDEO_FORMAT_NV61) {
2210 info->chroma_sampling[0] = 2.0f;
2211 info->chroma_sampling[1] = 1.0f;
2213 info->chroma_sampling[0] = info->chroma_sampling[1] = 2.0f;
2220 if (gst_video_colorimetry_matches (&convert->in_info.colorimetry,
2221 GST_VIDEO_COLORIMETRY_BT709)) {
2222 info->cms_offset = (gfloat *) from_rgb_bt709_offset;
2223 info->cms_coeff1 = (gfloat *) from_rgb_bt709_ycoeff;
2224 info->cms_coeff2 = (gfloat *) from_rgb_bt709_ucoeff;
2225 info->cms_coeff3 = (gfloat *) from_rgb_bt709_vcoeff;
2227 /* defaults/bt601 */
2228 info->cms_offset = (gfloat *) from_rgb_bt601_offset;
2229 info->cms_coeff1 = (gfloat *) from_rgb_bt601_ycoeff;
2230 info->cms_coeff2 = (gfloat *) from_rgb_bt601_ucoeff;
2231 info->cms_coeff3 = (gfloat *) from_rgb_bt601_vcoeff;
2234 g_free (pixel_order);
2238 _RGB_to_GRAY (GstGLColorConvert * convert)
2240 struct ConvertInfo *info = &convert->priv->convert_info;
2241 GstVideoFormat in_format = GST_VIDEO_INFO_FORMAT (&convert->in_info);
2242 const gchar *in_format_str = gst_video_format_to_string (in_format);
2243 gchar *pixel_order = _RGB_pixel_order (in_format_str, "rgba");
2244 gchar *alpha = NULL;
2246 info->out_n_textures = 1;
2247 info->shader_tex_names[0] = "tex";
2249 if (_is_RGBx (in_format))
2250 alpha = g_strdup_printf ("t.%c = 1.0;", pixel_order[3]);
2252 switch (GST_VIDEO_INFO_FORMAT (&convert->out_info)) {
2253 case GST_VIDEO_FORMAT_GRAY8:
2254 info->templ = &templ_REORDER;
2255 info->frag_body = g_strdup_printf (templ_REORDER_BODY, alpha ? alpha : "",
2256 pixel_order[0], pixel_order[0], pixel_order[0], pixel_order[3]);
2263 g_free (pixel_order);
2267 _GRAY_to_RGB (GstGLColorConvert * convert)
2269 struct ConvertInfo *info = &convert->priv->convert_info;
2270 GstVideoFormat out_format = GST_VIDEO_INFO_FORMAT (&convert->out_info);
2271 const gchar *out_format_str = gst_video_format_to_string (out_format);
2272 gchar *pixel_order = _RGB_pixel_order ("rgba", out_format_str);
2274 info->shader_tex_names[0] = "tex";
2276 switch (GST_VIDEO_INFO_FORMAT (&convert->in_info)) {
2277 case GST_VIDEO_FORMAT_GRAY8:
2278 info->templ = &templ_REORDER;
2279 info->frag_body = g_strdup_printf (templ_REORDER_BODY, "", pixel_order[0],
2280 pixel_order[0], pixel_order[0], pixel_order[3]);
2282 case GST_VIDEO_FORMAT_GRAY16_LE:
2284 char val2 = convert->priv->in_tex_formats[0] == GST_GL_RG ? 'g' : 'a';
2285 info->templ = &templ_COMPOSE;
2286 info->frag_body = g_strdup_printf (templ_COMPOSE_BODY, val2, 'r',
2287 pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3]);
2290 case GST_VIDEO_FORMAT_GRAY16_BE:
2292 char val2 = convert->priv->in_tex_formats[0] == GST_GL_RG ? 'g' : 'a';
2293 info->templ = &templ_COMPOSE;
2294 info->frag_body = g_strdup_printf (templ_COMPOSE_BODY, 'r', val2,
2295 pixel_order[0], pixel_order[1], pixel_order[2], pixel_order[3]);
2302 g_free (pixel_order);
2306 _bind_buffer (GstGLColorConvert * convert)
2308 const GstGLFuncs *gl = convert->context->gl_vtable;
2310 gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, convert->priv->vbo_indices);
2311 gl->BindBuffer (GL_ARRAY_BUFFER, convert->priv->vertex_buffer);
2313 /* Load the vertex position */
2314 gl->VertexAttribPointer (convert->priv->attr_position, 3, GL_FLOAT, GL_FALSE,
2315 5 * sizeof (GLfloat), (void *) 0);
2317 /* Load the texture coordinate */
2318 gl->VertexAttribPointer (convert->priv->attr_texture, 2, GL_FLOAT, GL_FALSE,
2319 5 * sizeof (GLfloat), (void *) (3 * sizeof (GLfloat)));
2321 gl->EnableVertexAttribArray (convert->priv->attr_position);
2322 gl->EnableVertexAttribArray (convert->priv->attr_texture);
2326 _unbind_buffer (GstGLColorConvert * convert)
2328 const GstGLFuncs *gl = convert->context->gl_vtable;
2330 gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);
2331 gl->BindBuffer (GL_ARRAY_BUFFER, 0);
2333 gl->DisableVertexAttribArray (convert->priv->attr_position);
2334 gl->DisableVertexAttribArray (convert->priv->attr_texture);
2337 static GstGLShader *
2338 _create_shader (GstGLColorConvert * convert)
2340 struct ConvertInfo *info = &convert->priv->convert_info;
2341 GString *str = g_string_new (NULL);
2342 GstGLShader *ret = NULL;
2343 GstGLSLStage *stage;
2344 GstGLSLVersion version;
2345 GstGLSLProfile profile;
2346 gchar *version_str, *tmp, *tmp1;
2347 const gchar *strings[3];
2348 GError *error = NULL;
2351 ret = gst_gl_shader_new (convert->context);
2354 _gst_glsl_mangle_shader (text_vertex_shader, GL_VERTEX_SHADER,
2355 info->templ->target, convert->priv->from_texture_target, convert->context,
2356 &version, &profile);
2358 tmp1 = gst_glsl_version_profile_to_string (version, profile);
2359 version_str = g_strdup_printf ("#version %s\n", tmp1);
2362 strings[0] = version_str;
2364 if (!(stage = gst_glsl_stage_new_with_strings (convert->context,
2365 GL_VERTEX_SHADER, version, profile, 2, strings))) {
2366 GST_ERROR_OBJECT (convert, "Failed to create vertex stage");
2367 g_free (version_str);
2369 gst_object_unref (ret);
2374 if (!gst_gl_shader_compile_attach_stage (ret, stage, &error)) {
2375 GST_ERROR_OBJECT (convert, "Failed to compile vertex shader %s",
2377 g_clear_error (&error);
2378 g_free (version_str);
2379 gst_object_unref (stage);
2380 gst_object_unref (ret);
2384 if (info->templ->extensions)
2385 g_string_append (str, info->templ->extensions);
2387 if (convert->priv->from_texture_target == GST_GL_TEXTURE_TARGET_EXTERNAL_OES
2388 && info->templ->target != GST_GL_TEXTURE_TARGET_EXTERNAL_OES)
2389 g_string_append (str, glsl_OES_extension_string);
2391 g_string_append (str,
2392 gst_gl_shader_string_get_highest_precision (convert->context, version,
2395 if (info->templ->uniforms)
2396 g_string_append (str, info->templ->uniforms);
2398 g_string_append_c (str, '\n');
2400 /* GL 3.3+ and GL ES 3.x */
2401 if ((profile == GST_GLSL_PROFILE_CORE && version >= GST_GLSL_VERSION_330)
2402 || (profile == GST_GLSL_PROFILE_ES && version >= GST_GLSL_VERSION_300)) {
2403 if (info->out_n_textures > 1) {
2406 for (i = 0; i < info->out_n_textures; i++) {
2407 g_string_append_printf (str,
2408 "layout(location = %d) out vec4 fragColor_%d;\n", i, i);
2411 g_string_append (str, "layout (location = 0) out vec4 fragColor;\n");
2413 } else if (profile == GST_GLSL_PROFILE_CORE
2414 && version >= GST_GLSL_VERSION_150) {
2415 /* no layout specifiers, use glBindFragDataLocation instead */
2416 if (info->out_n_textures > 1) {
2419 for (i = 0; i < info->out_n_textures; i++) {
2420 gchar *var_name = g_strdup_printf ("fragColor_%d", i);
2421 g_string_append_printf (str, "out vec4 %s;\n", var_name);
2422 gst_gl_shader_bind_frag_data_location (ret, i, var_name);
2426 g_string_append (str, "out vec4 fragColor;\n");
2427 gst_gl_shader_bind_frag_data_location (ret, 0, "fragColor");
2431 for (i = 0; i < MAX_FUNCTIONS; i++) {
2432 if (info->templ->functions[i] == NULL)
2435 g_string_append_c (str, '\n');
2436 g_string_append (str, info->templ->functions[i]);
2437 g_string_append_c (str, '\n');
2441 const gchar *varying = NULL;
2443 if ((profile == GST_GLSL_PROFILE_ES && version >= GST_GLSL_VERSION_300)
2444 || (profile == GST_GLSL_PROFILE_CORE
2445 && version >= GST_GLSL_VERSION_150)) {
2448 varying = "varying";
2450 g_string_append_printf (str, "\n%s vec2 v_texcoord;\nvoid main (void) {\n",
2453 if (info->frag_body) {
2454 g_string_append (str, "vec2 texcoord;\n");
2455 if (convert->priv->from_texture_target == GST_GL_TEXTURE_TARGET_RECTANGLE
2456 && info->templ->target != GST_GL_TEXTURE_TARGET_RECTANGLE) {
2457 g_string_append (str, "texcoord = v_texcoord * vec2 (width, height);\n");
2459 g_string_append (str, "texcoord = v_texcoord;\n");
2462 g_string_append (str, info->frag_body);
2464 g_string_append (str, "\n}");
2465 tmp = g_string_free (str, FALSE);
2466 info->frag_prog = _gst_glsl_mangle_shader (tmp, GL_FRAGMENT_SHADER,
2467 info->templ->target, convert->priv->from_texture_target, convert->context,
2468 &version, &profile);
2471 strings[1] = info->frag_prog;
2472 if (!(stage = gst_glsl_stage_new_with_strings (convert->context,
2473 GL_FRAGMENT_SHADER, version, profile, 2, strings))) {
2474 GST_ERROR_OBJECT (convert, "Failed to create fragment stage");
2475 g_free (info->frag_prog);
2476 info->frag_prog = NULL;
2477 g_free (version_str);
2478 gst_object_unref (ret);
2481 g_free (version_str);
2482 if (!gst_gl_shader_compile_attach_stage (ret, stage, &error)) {
2483 GST_ERROR_OBJECT (convert, "Failed to compile fragment shader %s",
2485 g_clear_error (&error);
2486 g_free (info->frag_prog);
2487 info->frag_prog = NULL;
2488 gst_object_unref (stage);
2489 gst_object_unref (ret);
2493 if (!gst_gl_shader_link (ret, &error)) {
2494 GST_ERROR_OBJECT (convert, "Failed to link shader %s", error->message);
2495 g_clear_error (&error);
2496 g_free (info->frag_prog);
2497 info->frag_prog = NULL;
2498 gst_object_unref (ret);
2505 /* Called in the gl thread */
2507 _init_convert (GstGLColorConvert * convert)
2510 struct ConvertInfo *info = &convert->priv->convert_info;
2513 gl = convert->context->gl_vtable;
2515 if (convert->initted)
2518 GST_INFO ("Initializing color conversion from %s to %s",
2519 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&convert->in_info)),
2520 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&convert->out_info)));
2522 if (!gl->CreateProgramObject && !gl->CreateProgram) {
2523 GST_ERROR_OBJECT (convert, "Cannot perform color conversion without "
2528 if (GST_VIDEO_INFO_IS_RGB (&convert->in_info)) {
2529 if (GST_VIDEO_INFO_IS_RGB (&convert->out_info)) {
2530 _RGB_to_RGB (convert);
2534 if (GST_VIDEO_INFO_IS_YUV (&convert->in_info)) {
2535 if (GST_VIDEO_INFO_IS_RGB (&convert->out_info)) {
2536 _YUV_to_RGB (convert);
2540 if (GST_VIDEO_INFO_IS_RGB (&convert->in_info)) {
2541 if (GST_VIDEO_INFO_IS_YUV (&convert->out_info)) {
2542 _RGB_to_YUV (convert);
2546 if (GST_VIDEO_INFO_IS_RGB (&convert->in_info)) {
2547 if (GST_VIDEO_INFO_IS_GRAY (&convert->out_info)) {
2548 _RGB_to_GRAY (convert);
2552 if (GST_VIDEO_INFO_IS_GRAY (&convert->in_info)) {
2553 if (GST_VIDEO_INFO_IS_RGB (&convert->out_info)) {
2554 _GRAY_to_RGB (convert);
2558 if (!info->frag_body || info->in_n_textures == 0 || info->out_n_textures == 0)
2559 goto unhandled_format;
2561 /* multiple draw targets not supported on GLES2... */
2562 if (info->out_n_textures > 1 && !gl->DrawBuffers) {
2563 GST_ERROR ("Conversion requires output to multiple draw buffers");
2564 goto incompatible_api;
2567 /* Requires reading from a RG/LA framebuffer... */
2568 if (USING_GLES2 (convert->context) && !USING_GLES3 (convert->context) &&
2569 (GST_VIDEO_INFO_FORMAT (&convert->out_info) == GST_VIDEO_FORMAT_YUY2 ||
2570 GST_VIDEO_INFO_FORMAT (&convert->out_info) ==
2571 GST_VIDEO_FORMAT_UYVY)) {
2572 GST_ERROR ("Conversion requires reading with an unsupported format");
2573 goto incompatible_api;
2576 if (!(convert->shader = _create_shader (convert)))
2579 convert->priv->attr_position =
2580 gst_gl_shader_get_attribute_location (convert->shader, "a_position");
2581 convert->priv->attr_texture =
2582 gst_gl_shader_get_attribute_location (convert->shader, "a_texcoord");
2584 gst_gl_shader_use (convert->shader);
2586 if (info->cms_offset && info->cms_coeff1
2587 && info->cms_coeff2 && info->cms_coeff3) {
2588 gst_gl_shader_set_uniform_3fv (convert->shader, "offset", 1,
2590 gst_gl_shader_set_uniform_3fv (convert->shader, "coeff1", 1,
2592 gst_gl_shader_set_uniform_3fv (convert->shader, "coeff2", 1,
2594 gst_gl_shader_set_uniform_3fv (convert->shader, "coeff3", 1,
2598 for (i = info->in_n_textures; i >= 0; i--) {
2599 if (info->shader_tex_names[i])
2600 gst_gl_shader_set_uniform_1i (convert->shader, info->shader_tex_names[i],
2604 gst_gl_shader_set_uniform_1f (convert->shader, "width",
2605 GST_VIDEO_INFO_WIDTH (&convert->in_info));
2606 gst_gl_shader_set_uniform_1f (convert->shader, "height",
2607 GST_VIDEO_INFO_HEIGHT (&convert->in_info));
2609 if (convert->priv->from_texture_target == GST_GL_TEXTURE_TARGET_RECTANGLE) {
2610 gst_gl_shader_set_uniform_1f (convert->shader, "poffset_x", 1.);
2611 gst_gl_shader_set_uniform_1f (convert->shader, "poffset_y", 1.);
2613 gst_gl_shader_set_uniform_1f (convert->shader, "poffset_x",
2614 1. / (gfloat) GST_VIDEO_INFO_WIDTH (&convert->in_info));
2615 gst_gl_shader_set_uniform_1f (convert->shader, "poffset_y",
2616 1. / (gfloat) GST_VIDEO_INFO_HEIGHT (&convert->in_info));
2619 if (info->chroma_sampling[0] > 0.0f && info->chroma_sampling[1] > 0.0f) {
2620 gst_gl_shader_set_uniform_2fv (convert->shader, "chroma_sampling", 1,
2621 info->chroma_sampling);
2624 gst_gl_context_clear_shader (convert->context);
2626 if (convert->fbo == NULL && !_init_convert_fbo (convert)) {
2630 if (!convert->priv->vertex_buffer) {
2631 if (gl->GenVertexArrays) {
2632 gl->GenVertexArrays (1, &convert->priv->vao);
2633 gl->BindVertexArray (convert->priv->vao);
2636 gl->GenBuffers (1, &convert->priv->vertex_buffer);
2637 gl->BindBuffer (GL_ARRAY_BUFFER, convert->priv->vertex_buffer);
2638 gl->BufferData (GL_ARRAY_BUFFER, 4 * 5 * sizeof (GLfloat), vertices,
2641 gl->GenBuffers (1, &convert->priv->vbo_indices);
2642 gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, convert->priv->vbo_indices);
2643 gl->BufferData (GL_ELEMENT_ARRAY_BUFFER, sizeof (indices), indices,
2646 if (gl->GenVertexArrays) {
2647 _bind_buffer (convert);
2648 gl->BindVertexArray (0);
2651 gl->BindBuffer (GL_ARRAY_BUFFER, 0);
2652 gl->BindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0);
2655 gl->BindTexture (GL_TEXTURE_2D, 0);
2657 convert->initted = TRUE;
2662 GST_ERROR_OBJECT (convert, "Don't know how to convert from %s to %s",
2663 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&convert->in_info)),
2664 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&convert->out_info)));
2671 GST_ERROR_OBJECT (convert, "Converting from %s to %s requires "
2672 "functionality that the current OpenGL setup does not support",
2673 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&convert->in_info)),
2674 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT
2675 (&convert->out_info)));
2680 /* called by _init_convert (in the gl thread) */
2682 _init_convert_fbo (GstGLColorConvert * convert)
2684 guint out_width, out_height;
2686 out_width = GST_VIDEO_INFO_WIDTH (&convert->out_info);
2687 out_height = GST_VIDEO_INFO_HEIGHT (&convert->out_info);
2690 gst_gl_framebuffer_new_with_default_depth (convert->context, out_width,
2693 return convert->fbo != NULL;
2697 _do_convert_one_view (GstGLContext * context, GstGLColorConvert * convert,
2700 guint in_width, in_height, out_width, out_height;
2701 struct ConvertInfo *c_info = &convert->priv->convert_info;
2702 GstMapInfo out_info[GST_VIDEO_MAX_PLANES], in_info[GST_VIDEO_MAX_PLANES];
2703 gboolean res = TRUE;
2705 const gint in_plane_offset = view_num * c_info->in_n_textures;
2706 const gint out_plane_offset = view_num * c_info->out_n_textures;
2708 out_width = GST_VIDEO_INFO_WIDTH (&convert->out_info);
2709 out_height = GST_VIDEO_INFO_HEIGHT (&convert->out_info);
2710 in_width = GST_VIDEO_INFO_WIDTH (&convert->in_info);
2711 in_height = GST_VIDEO_INFO_HEIGHT (&convert->in_info);
2713 for (i = 0; i < c_info->in_n_textures; i++) {
2714 convert->priv->in_tex[i] =
2715 (GstGLMemory *) gst_buffer_peek_memory (convert->inbuf,
2716 i + in_plane_offset);
2717 if (!gst_is_gl_memory ((GstMemory *) convert->priv->in_tex[i])) {
2718 GST_ERROR_OBJECT (convert, "input must be GstGLMemory");
2722 if (convert->context != convert->priv->in_tex[i]->mem.context) {
2723 GST_ERROR_OBJECT (convert, "input memory OpenGL context is different. "
2724 "we have %" GST_PTR_FORMAT " memory has %" GST_PTR_FORMAT,
2725 convert->context, convert->priv->in_tex[i]->mem.context);
2730 if (!gst_memory_map ((GstMemory *) convert->priv->in_tex[i], &in_info[i],
2731 GST_MAP_READ | GST_MAP_GL)) {
2732 GST_ERROR_OBJECT (convert, "failed to map input memory %p",
2733 convert->priv->in_tex[i]);
2739 for (j = 0; j < c_info->out_n_textures; j++) {
2740 GstGLMemory *out_tex =
2741 (GstGLMemory *) gst_buffer_peek_memory (convert->outbuf,
2742 j + out_plane_offset);
2743 gint mem_width, mem_height;
2745 if (!gst_is_gl_memory ((GstMemory *) out_tex)) {
2746 GST_ERROR_OBJECT (convert, "output must be GstGLMemory");
2750 if (convert->context != out_tex->mem.context) {
2751 GST_ERROR_OBJECT (convert, "output memory OpenGL context is different. "
2752 "we have %" GST_PTR_FORMAT " memory has %" GST_PTR_FORMAT,
2753 convert->context, out_tex->mem.context);
2758 mem_width = gst_gl_memory_get_texture_width (out_tex);
2759 mem_height = gst_gl_memory_get_texture_height (out_tex);
2761 if (out_tex->tex_format == GST_GL_LUMINANCE
2762 || out_tex->tex_format == GST_GL_LUMINANCE_ALPHA
2763 || out_width != mem_width || out_height != mem_height) {
2764 /* Luminance formats are not color renderable */
2765 /* rendering to a framebuffer only renders the intersection of all
2766 * the attachments i.e. the smallest attachment size */
2767 if (!convert->priv->out_tex[j]) {
2768 GstGLVideoAllocationParams *params;
2769 GstGLBaseMemoryAllocator *base_mem_allocator;
2770 GstAllocator *allocator;
2771 GstVideoInfo temp_info;
2773 gst_video_info_set_format (&temp_info, GST_VIDEO_FORMAT_RGBA, out_width,
2776 allocator = gst_allocator_find (GST_GL_MEMORY_ALLOCATOR_NAME);
2777 base_mem_allocator = GST_GL_BASE_MEMORY_ALLOCATOR (allocator);
2778 params = gst_gl_video_allocation_params_new (context, NULL, &temp_info,
2779 0, NULL, convert->priv->to_texture_target, GST_GL_RGBA);
2781 convert->priv->out_tex[j] =
2782 (GstGLMemory *) gst_gl_base_memory_alloc (base_mem_allocator,
2783 (GstGLAllocationParams *) params);
2785 gst_gl_allocation_params_free ((GstGLAllocationParams *) params);
2786 gst_object_unref (allocator);
2789 convert->priv->out_tex[j] = out_tex;
2792 if (!gst_memory_map ((GstMemory *) convert->priv->out_tex[j], &out_info[j],
2793 GST_MAP_WRITE | GST_MAP_GL)) {
2794 GST_ERROR_OBJECT (convert, "failed to map output memory %p",
2795 convert->priv->out_tex[i]);
2801 GST_LOG_OBJECT (convert, "converting to textures:%p,%p,%p,%p "
2802 "dimensions:%ux%u, from textures:%p,%p,%p,%p dimensions:%ux%u",
2803 convert->priv->out_tex[0], convert->priv->out_tex[1],
2804 convert->priv->out_tex[2], convert->priv->out_tex[3], out_width,
2805 out_height, convert->priv->in_tex[0], convert->priv->in_tex[1],
2806 convert->priv->in_tex[2], convert->priv->in_tex[3], in_width, in_height);
2808 if (!_do_convert_draw (context, convert))
2812 for (j--; j >= 0; j--) {
2813 GstGLMemory *out_tex =
2814 (GstGLMemory *) gst_buffer_peek_memory (convert->outbuf,
2815 j + out_plane_offset);
2816 gint mem_width, mem_height;
2818 gst_memory_unmap ((GstMemory *) convert->priv->out_tex[j], &out_info[j]);
2820 mem_width = gst_gl_memory_get_texture_width (out_tex);
2821 mem_height = gst_gl_memory_get_texture_height (out_tex);
2823 if (out_tex->tex_format == GST_GL_LUMINANCE
2824 || out_tex->tex_format == GST_GL_LUMINANCE_ALPHA
2825 || out_width != mem_width || out_height != mem_height) {
2826 GstMapInfo to_info, from_info;
2828 if (!gst_memory_map ((GstMemory *) convert->priv->out_tex[j], &from_info,
2829 GST_MAP_READ | GST_MAP_GL)) {
2830 GST_ERROR_OBJECT (convert, "Failed to map intermediate memory");
2834 if (!gst_memory_map ((GstMemory *) out_tex, &to_info,
2835 GST_MAP_WRITE | GST_MAP_GL)) {
2836 GST_ERROR_OBJECT (convert, "Failed to map intermediate memory");
2840 gst_gl_memory_copy_into (convert->priv->out_tex[j],
2841 out_tex->tex_id, convert->priv->to_texture_target,
2842 out_tex->tex_format, mem_width, mem_height);
2843 gst_memory_unmap ((GstMemory *) convert->priv->out_tex[j], &from_info);
2844 gst_memory_unmap ((GstMemory *) out_tex, &to_info);
2846 convert->priv->out_tex[j] = NULL;
2850 /* YV12 the same as I420 except planes 1+2 swapped */
2851 if (GST_VIDEO_INFO_FORMAT (&convert->out_info) == GST_VIDEO_FORMAT_YV12) {
2853 gst_buffer_get_memory (convert->outbuf, 1 + out_plane_offset);
2855 gst_buffer_get_memory (convert->outbuf, 2 + out_plane_offset);
2857 gst_buffer_replace_memory (convert->outbuf, 1 + out_plane_offset, mem2);
2858 gst_buffer_replace_memory (convert->outbuf, 2 + out_plane_offset, mem1);
2861 for (i--; i >= 0; i--) {
2862 gst_memory_unmap ((GstMemory *) convert->priv->in_tex[i], &in_info[i]);
2869 foreach_metadata (GstBuffer * inbuf, GstMeta ** meta, gpointer user_data)
2871 CopyMetaData *data = user_data;
2872 GstGLColorConvert *convert = data->convert;
2873 const GstMetaInfo *info = (*meta)->info;
2874 GstBuffer *outbuf = data->outbuf;
2876 if (!gst_meta_api_type_has_tag (info->api, _gst_meta_tag_memory) &&
2877 info->api != gst_video_overlay_composition_meta_api_get_type () &&
2878 info->api != gst_gl_sync_meta_api_get_type ()) {
2879 GstMetaTransformCopy copy_data = { FALSE, 0, -1 };
2880 if (info->transform_func) {
2881 GST_TRACE_OBJECT (convert, "copy metadata %s", g_type_name (info->api));
2882 info->transform_func (outbuf, *meta, inbuf,
2883 _gst_meta_transform_copy, ©_data);
2885 GST_DEBUG_OBJECT (convert, "couldn't copy metadata %s",
2886 g_type_name (info->api));
2893 /* Called by the idle function in the gl thread */
2895 _do_convert (GstGLContext * context, GstGLColorConvert * convert)
2897 GstVideoInfo *in_info = &convert->in_info;
2898 struct ConvertInfo *c_info = &convert->priv->convert_info;
2899 gboolean res = TRUE;
2901 GstGLSyncMeta *sync_meta;
2904 convert->outbuf = NULL;
2906 if (GST_VIDEO_INFO_MULTIVIEW_MODE (in_info) ==
2907 GST_VIDEO_MULTIVIEW_MODE_SEPARATED)
2908 views = GST_VIDEO_INFO_VIEWS (in_info);
2912 c_info->in_n_textures =
2913 _get_n_textures (GST_VIDEO_INFO_FORMAT (&convert->in_info));
2914 c_info->out_n_textures =
2915 _get_n_textures (GST_VIDEO_INFO_FORMAT (&convert->out_info));
2918 gboolean tex_format_change = FALSE;
2921 for (v = 0; v < views; v++) {
2922 for (i = 0; i < c_info->in_n_textures; i++) {
2923 guint j = v * c_info->in_n_textures + i;
2924 GstGLMemory *in_tex =
2925 (GstGLMemory *) gst_buffer_peek_memory (convert->inbuf, j);
2926 if (!gst_is_gl_memory ((GstMemory *) in_tex)) {
2927 GST_ERROR_OBJECT (convert, "input must be GstGLMemory");
2928 convert->priv->result = FALSE;
2932 if (j >= GST_VIDEO_MAX_PLANES)
2933 /* our arrays aren't that big */
2934 g_assert_not_reached ();
2936 if (v > 0 && in_tex->tex_format != convert->priv->in_tex_formats[i]) {
2937 GST_ERROR_OBJECT (convert, "Cannot convert textures with "
2939 convert->priv->result = FALSE;
2943 if (convert->priv->in_tex_formats[j] != in_tex->tex_format)
2944 tex_format_change = TRUE;
2946 convert->priv->in_tex_formats[j] = in_tex->tex_format;
2950 if (tex_format_change)
2951 gst_gl_color_convert_reset_shader (convert);
2954 if (!_init_convert (convert)) {
2955 convert->priv->result = FALSE;
2959 sync_meta = gst_buffer_get_gl_sync_meta (convert->inbuf);
2961 gst_gl_sync_meta_wait (sync_meta, convert->context);
2963 if (!convert->priv->pool) {
2966 GstQuery *query = gst_query_new_allocation (convert->priv->out_caps, TRUE);
2967 ret = gst_gl_color_convert_decide_allocation (convert, query);
2968 gst_query_unref (query);
2971 GST_ERROR_OBJECT (convert, "Failed to choose allocation parameters");
2972 convert->priv->result = FALSE;
2976 if (!convert->priv->pool) {
2977 GST_ERROR_OBJECT (convert, "Failed to create a buffer pool");
2978 convert->priv->result = FALSE;
2983 if (!convert->priv->pool_started) {
2984 if (!gst_buffer_pool_set_active (convert->priv->pool, TRUE)) {
2985 GST_ERROR_OBJECT (convert, "Failed to start buffer pool");
2986 convert->priv->result = FALSE;
2989 convert->priv->pool_started = TRUE;
2993 gst_buffer_pool_acquire_buffer (convert->priv->pool, &convert->outbuf,
2995 if (ret != GST_FLOW_OK) {
2996 GST_ERROR_OBJECT (convert, "Failed to acquire buffer from pool: %s",
2997 gst_flow_get_name (ret));
2998 convert->priv->result = FALSE;
3002 gst_gl_insert_debug_marker (context, "%s converting from %s to %s",
3003 GST_OBJECT_NAME (convert),
3004 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (in_info)),
3005 gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&convert->out_info)));
3006 /* Handle all views on input and output one at a time */
3007 for (v = 0; res && v < views; v++)
3008 res = _do_convert_one_view (context, convert, v);
3011 gst_buffer_unref (convert->outbuf);
3012 convert->outbuf = NULL;
3015 if (convert->outbuf) {
3017 GstVideoOverlayCompositionMeta *composition_meta;
3018 GstGLSyncMeta *sync_meta;
3020 if (G_UNLIKELY (!gst_buffer_is_writable (convert->outbuf))) {
3021 GST_WARNING_OBJECT (convert,
3022 "buffer is not writable at this point, bailing out");
3023 convert->priv->result = FALSE;
3027 sync_meta = gst_buffer_add_gl_sync_meta (convert->context, convert->outbuf);
3030 gst_gl_sync_meta_set_sync_point (sync_meta, convert->context);
3033 gst_buffer_get_video_overlay_composition_meta (convert->inbuf);
3034 if (composition_meta) {
3035 GST_DEBUG ("found video overlay composition meta, applying on output.");
3036 gst_buffer_add_video_overlay_composition_meta
3037 (convert->outbuf, composition_meta->overlay);
3040 data.convert = convert;
3041 data.outbuf = convert->outbuf;
3042 gst_buffer_foreach_meta (convert->inbuf, foreach_metadata, &data);
3045 convert->priv->result = res;
3050 _do_convert_draw (GstGLContext * context, GstGLColorConvert * convert)
3053 struct ConvertInfo *c_info = &convert->priv->convert_info;
3054 guint out_width, out_height;
3056 gboolean ret = TRUE;
3058 GLenum multipleRT[] = {
3059 GL_COLOR_ATTACHMENT0,
3060 GL_COLOR_ATTACHMENT1,
3061 GL_COLOR_ATTACHMENT2,
3062 GL_COLOR_ATTACHMENT3
3065 gl = context->gl_vtable;
3067 gst_gl_framebuffer_bind (convert->fbo);
3069 /* attach the texture to the FBO to renderer to */
3070 for (i = 0; i < c_info->out_n_textures; i++) {
3071 GstGLBaseMemory *tex = (GstGLBaseMemory *) convert->priv->out_tex[i];
3073 gst_gl_framebuffer_attach (convert->fbo, GL_COLOR_ATTACHMENT0 + i, tex);
3076 if (gl->DrawBuffers)
3077 gl->DrawBuffers (c_info->out_n_textures, multipleRT);
3078 else if (gl->DrawBuffer)
3079 gl->DrawBuffer (GL_COLOR_ATTACHMENT0);
3081 gst_gl_framebuffer_get_effective_dimensions (convert->fbo, &out_width,
3083 gl->Viewport (0, 0, out_width, out_height);
3085 gst_gl_shader_use (convert->shader);
3087 if (gl->BindVertexArray)
3088 gl->BindVertexArray (convert->priv->vao);
3089 _bind_buffer (convert);
3091 for (i = c_info->in_n_textures - 1; i >= 0; i--) {
3092 gchar *scale_name = g_strdup_printf ("tex_scale%u", i);
3094 gst_gl_texture_target_to_gl (convert->priv->from_texture_target);
3096 gl->ActiveTexture (GL_TEXTURE0 + i);
3097 gl->BindTexture (gl_target, convert->priv->in_tex[i]->tex_id);
3098 gl->TexParameteri (gl_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
3099 gl->TexParameteri (gl_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
3100 gl->TexParameteri (gl_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
3101 gl->TexParameteri (gl_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
3103 gst_gl_shader_set_uniform_2fv (convert->shader, scale_name, 1,
3104 convert->priv->in_tex[i]->tex_scaling);
3106 g_free (scale_name);
3109 gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
3111 if (gl->BindVertexArray)
3112 gl->BindVertexArray (0);
3114 _unbind_buffer (convert);
3117 gl->DrawBuffer (GL_COLOR_ATTACHMENT0);
3119 /* we are done with the shader */
3120 gst_gl_context_clear_shader (context);
3122 if (!gst_gl_context_check_framebuffer_status (context, GL_FRAMEBUFFER))
3125 gst_gl_context_clear_framebuffer (context);